PageSourceSearch

https://zepetto.com/js/v2/three.module.js

js zepetto.com collected 2026-10-04 08:18:42 UTC 1,326,040 bytes, 53,057 lines download raw bytes

1/**
2 * @license
3 * Copyright 2010-2023 Three.js Authors
4 * SPDX-License-Identifier: MIT
5 */
6const REVISION = '160';
7
8const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
9const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
10const CullFaceNone = 0;
11const CullFaceBack = 1;
12const CullFaceFront = 2;
13const CullFaceFrontBack = 3;
14const BasicShadowMap = 0;
15const PCFShadowMap = 1;
16const PCFSoftShadowMap = 2;
17const VSMShadowMap = 3;
18const FrontSide = 0;
19const BackSide = 1;
20const DoubleSide = 2;
21const TwoPassDoubleSide = 2; // r149
22const NoBlending = 0;
23const NormalBlending = 1;
24const AdditiveBlending = 2;
25const SubtractiveBlending = 3;
26const MultiplyBlending = 4;
27const CustomBlending = 5;
28const AddEquation = 100;
29const SubtractEquation = 101;
30const ReverseSubtractEquation = 102;
31const MinEquation = 103;
32const MaxEquation = 104;
33const ZeroFactor = 200;
34const OneFactor = 201;
35const SrcColorFactor = 202;
36const OneMinusSrcColorFactor = 203;
37const SrcAlphaFactor = 204;
38const OneMinusSrcAlphaFactor = 205;
39const DstAlphaFactor = 206;
40const OneMinusDstAlphaFactor = 207;
41const DstColorFactor = 208;
42const OneMinusDstColorFactor = 209;
43const SrcAlphaSaturateFactor = 210;
44const ConstantColorFactor = 211;
45const OneMinusConstantColorFactor = 212;
46const ConstantAlphaFactor = 213;
47const OneMinusConstantAlphaFactor = 214;
48const NeverDepth = 0;
49const AlwaysDepth = 1;
50const LessDepth = 2;
51const LessEqualDepth = 3;
52const EqualDepth = 4;
53const GreaterEqualDepth = 5;
54const GreaterDepth = 6;
55const NotEqualDepth = 7;
56const MultiplyOperation = 0;
57const MixOperation = 1;
58const AddOperation = 2;
59const NoToneMapping = 0;
60const LinearToneMapping = 1;
61const ReinhardToneMapping = 2;
62const CineonToneMapping = 3;
63const ACESFilmicToneMapping = 4;
64const CustomToneMapping = 5;
65const AgXToneMapping = 6;
66const AttachedBindMode = 'attached';
67const DetachedBindMode = 'detached';
68
69const UVMapping = 300;
70const CubeReflectionMapping = 301;
71const CubeRefractionMapping = 302;
72const EquirectangularReflectionMapping = 303;
73const EquirectangularRefractionMapping = 304;
74const CubeUVReflectionMapping = 306;
75const RepeatWrapping = 1000;
76const ClampToEdgeWrapping = 1001;
77const MirroredRepeatWrapping = 1002;
78const NearestFilter = 1003;
79const NearestMipmapNearestFilter = 1004;
80const NearestMipMapNearestFilter = 1004;
81const NearestMipmapLinearFilter = 1005;
82const NearestMipMapLinearFilter = 1005;
83const LinearFilter = 1006;
84const LinearMipmapNearestFilter = 1007;
85const LinearMipMapNearestFilter = 1007;
86const LinearMipmapLinearFilter = 1008;
87const LinearMipMapLinearFilter = 1008;
88const UnsignedByteType = 1009;
89const ByteType = 1010;
90const ShortType = 1011;
91const UnsignedShortType = 1012;
92const IntType = 1013;
93const UnsignedIntType = 1014;
94const FloatType = 1015;
95const HalfFloatType = 1016;
96const UnsignedShort4444Type = 1017;
97const UnsignedShort5551Type = 1018;
98const UnsignedInt248Type = 1020;
99const AlphaFormat = 1021;
100const RGBAFormat = 1023;
101const LuminanceFormat = 1024;
102const LuminanceAlphaFormat = 1025;
103const DepthFormat = 1026;
104const DepthStencilFormat = 1027;
105const RedFormat = 1028;
106const RedIntegerFormat = 1029;
107const RGFormat = 1030;
108const RGIntegerFormat = 1031;
109const RGBAIntegerFormat = 1033;
110
111const RGB_S3TC_DXT1_Format = 33776;
112const RGBA_S3TC_DXT1_Format = 33777;
113const RGBA_S3TC_DXT3_Format = 33778;
114const RGBA_S3TC_DXT5_Format = 33779;
115const RGB_PVRTC_4BPPV1_Format = 35840;
116const RGB_PVRTC_2BPPV1_Format = 35841;
117const RGBA_PVRTC_4BPPV1_Format = 35842;
118const RGBA_PVRTC_2BPPV1_Format = 35843;
119const RGB_ETC1_Format = 36196;
120const RGB_ETC2_Format = 37492;
121const RGBA_ETC2_EAC_Format = 37496;
122const RGBA_ASTC_4x4_Format = 37808;
123const RGBA_ASTC_5x4_Format = 37809;
124const RGBA_ASTC_5x5_Format = 37810;
125const RGBA_ASTC_6x5_Format = 37811;
126const RGBA_ASTC_6x6_Format = 37812;
127const RGBA_ASTC_8x5_Format = 37813;
128const RGBA_ASTC_8x6_Format = 37814;
129const RGBA_ASTC_8x8_Format = 37815;
130const RGBA_ASTC_10x5_Format = 37816;
131const RGBA_ASTC_10x6_Format = 37817;
132const RGBA_ASTC_10x8_Format = 37818;
133const RGBA_ASTC_10x10_Format = 37819;
134const RGBA_ASTC_12x10_Format = 37820;
135const RGBA_ASTC_12x12_Format = 37821;
136const RGBA_BPTC_Format = 36492;
137const RGB_BPTC_SIGNED_Format = 36494;
138const RGB_BPTC_UNSIGNED_Format = 36495;
139const RED_RGTC1_Format = 36283;
140const SIGNED_RED_RGTC1_Format = 36284;
141const RED_GREEN_RGTC2_Format = 36285;
142const SIGNED_RED_GREEN_RGTC2_Format = 36286;
143const LoopOnce = 2200;
144const LoopRepeat = 2201;
145const LoopPingPong = 2202;
146const InterpolateDiscrete = 2300;
147const InterpolateLinear = 2301;
148const InterpolateSmooth = 2302;
149const ZeroCurvatureEnding = 2400;
150const ZeroSlopeEnding = 2401;
151const WrapAroundEnding = 2402;
152const NormalAnimationBlendMode = 2500;
153const AdditiveAnimationBlendMode = 2501;
154const TrianglesDrawMode = 0;
155const TriangleStripDrawMode = 1;
156const TriangleFanDrawMode = 2;
157/** @deprecated Use LinearSRGBColorSpace or NoColorSpace in three.js r152+. */
158const LinearEncoding = 3000;
159/** @deprecated Use SRGBColorSpace in three.js r152+. */
160const sRGBEncoding = 3001;
161const BasicDepthPacking = 3200;
162const RGBADepthPacking = 3201;
163const TangentSpaceNormalMap = 0;
164const ObjectSpaceNormalMap = 1;
165
166// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU n
vendor: 7,693 bytes, lines 166-434
166ames where available.
167const NoColorSpace = '';
168const SRGBColorSpace = 'srgb';
169const LinearSRGBColorSpace = 'srgb-linear';
170const DisplayP3ColorSpace = 'display-p3';
171const LinearDisplayP3ColorSpace = 'display-p3-linear';
172
173const LinearTransfer = 'linear';
174const SRGBTransfer = 'srgb';
175
176const Rec709Primaries = 'rec709';
177const P3Primaries = 'p3';
178
179const ZeroStencilOp = 0;
180const KeepStencilOp = 7680;
181const ReplaceStencilOp = 7681;
182const IncrementStencilOp = 7682;
183const DecrementStencilOp = 7683;
184const IncrementWrapStencilOp = 34055;
185const DecrementWrapStencilOp = 34056;
186const InvertStencilOp = 5386;
187
188const NeverStencilFunc = 512;
189const LessStencilFunc = 513;
190const EqualStencilFunc = 514;
191const LessEqualStencilFunc = 515;
192const GreaterStencilFunc = 516;
193const NotEqualStencilFunc = 517;
194const GreaterEqualStencilFunc = 518;
195const AlwaysStencilFunc = 519;
196
197const NeverCompare = 512;
198const LessCompare = 513;
199const EqualCompare = 514;
200const LessEqualCompare = 515;
201const GreaterCompare = 516;
202const NotEqualCompare = 517;
203const GreaterEqualCompare = 518;
204const AlwaysCompare = 519;
205
206const StaticDrawUsage = 35044;
207const DynamicDrawUsage = 35048;
208const StreamDrawUsage = 35040;
209const StaticReadUsage = 35045;
210const DynamicReadUsage = 35049;
211const StreamReadUsage = 35041;
212const StaticCopyUsage = 35046;
213const DynamicCopyUsage = 35050;
214const StreamCopyUsage = 35042;
215
216const GLSL1 = '100';
217const GLSL3 = '300 es';
218
219const _SRGBAFormat = 1035; // fallback for WebGL 1
220
221const WebGLCoordinateSystem = 2000;
222const WebGPUCoordinateSystem = 2001;
223
224/**
225 * https://github.com/mrdoob/eventdispatcher.js/
226 */
227
228class EventDispatcher {
229
230	addEventListener( type, listener ) {
231
232		if ( this._listeners === undefined ) this._listeners = {};
233
234		const listeners = this._listeners;
235
236		if ( listeners[ type ] === undefined ) {
237
238			listeners[ type ] = [];
239
240		}
241
242		if ( listeners[ type ].indexOf( listener ) === - 1 ) {
243
244			listeners[ type ].push( listener );
245
246		}
247
248	}
249
250	hasEventListener( type, listener ) {
251
252		if ( this._listeners === undefined ) return false;
253
254		const listeners = this._listeners;
255
256		return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
257
258	}
259
260	removeEventListener( type, listener ) {
261
262		if ( this._listeners === undefined ) return;
263
264		const listeners = this._listeners;
265		const listenerArray = listeners[ type ];
266
267		if ( listenerArray !== undefined ) {
268
269			const index = listenerArray.indexOf( listener );
270
271			if ( index !== - 1 ) {
272
273				listenerArray.splice( index, 1 );
274
275			}
276
277		}
278
279	}
280
281	dispatchEvent( event ) {
282
283		if ( this._listeners === undefined ) return;
284
285		const listeners = this._listeners;
286		const listenerArray = listeners[ event.type ];
287
288		if ( listenerArray !== undefined ) {
289
290			event.target = this;
291
292			// Make a copy, in case listeners are removed while iterating.
293			const array = listenerArray.slice( 0 );
294
295			for ( let i = 0, l = array.length; i < l; i ++ ) {
296
297				array[ i ].call( this, event );
298
299			}
300
301			event.target = null;
302
303		}
304
305	}
306
307}
308
309const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ];
310
311let _seed = 1234567;
312
313
314const DEG2RAD = Math.PI / 180;
315const RAD2DEG = 180 / Math.PI;
316
317// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
318function generateUUID() {
319
320	const d0 = Math.random() * 0xffffffff | 0;
321	const d1 = Math.random() * 0xffffffff | 0;
322	const d2 = Math.random() * 0xffffffff | 0;
323	const d3 = Math.random() * 0xffffffff | 0;
324	const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
325			_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
326			_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
327			_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
328
329	// .toLowerCase() here flattens concatenated strings to save heap memory space.
330	return uuid.toLowerCase();
331
332}
333
334function clamp( value, min, max ) {
335
336	return Math.max( min, Math.min( max, value ) );
337
338}
339
340// compute euclidean modulo of m % n
341// https://en.wikipedia.org/wiki/Modulo_operation
342function euclideanModulo( n, m ) {
343
344	return ( ( n % m ) + m ) % m;
345
346}
347
348// Linear mapping from range <a1, a2> to range <b1, b2>
349function mapLinear( x, a1, a2, b1, b2 ) {
350
351	return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
352
353}
354
355// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
356function inverseLerp( x, y, value ) {
357
358	if ( x !== y ) {
359
360		return ( value - x ) / ( y - x );
361
362	} else {
363
364		return 0;
365
366	}
367
368}
369
370// https://en.wikipedia.org/wiki/Linear_interpolation
371function lerp( x, y, t ) {
372
373	return ( 1 - t ) * x + t * y;
374
375}
376
377// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
378function damp( x, y, lambda, dt ) {
379
380	return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
381
382}
383
384// https://www.desmos.com/calculator/vcsjnyz7x4
385function pingpong( x, length = 1 ) {
386
387	return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
388
389}
390
391// http://en.wikipedia.org/wiki/Smoothstep
392function smoothstep( x, min, max ) {
393
394	if ( x <= min ) return 0;
395	if ( x >= max ) return 1;
396
397	x = ( x - min ) / ( max - min );
398
399	return x * x * ( 3 - 2 * x );
400
401}
402
403function smootherstep( x, min, max ) {
404
405	if ( x <= min ) return 0;
406	if ( x >= max ) return 1;
407
408	x = ( x - min ) / ( max - min );
409
410	return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
411
412}
413
414// Random integer from <low, high> interval
415function randInt( low, high ) {
416
417	return low + Math.floor( Math.random() * ( high - low + 1 ) );
418
419}
420
421// Random float from <low, high> interval
422function randFloat( low, high ) {
423
424	return low + Math.random() * ( high - low );
425
426}
427
428// Random float from <-range/2, range/2> interval
429function randFloatSpread( range ) {
430
431	return range * ( 0.5 - Math.random() );
432
433}
434
vendor: 5,932 bytes, lines 435-835
435// Deterministic pseudo-random float in the interval [ 0, 1 ]
436function seededRandom( s ) {
437
438	if ( s !== undefined ) _seed = s;
439
440	// Mulberry32 generator
441
442	let t = _seed += 0x6D2B79F5;
443
444	t = Math.imul( t ^ t >>> 15, t | 1 );
445
446	t ^= t + Math.imul( t ^ t >>> 7, t | 61 );
447
448	return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;
449
450}
451
452function degToRad( degrees ) {
453
454	return degrees * DEG2RAD;
455
456}
457
458function radToDeg( radians ) {
459
460	return radians * RAD2DEG;
461
462}
463
464function isPowerOfTwo( value ) {
465
466	return ( value & ( value - 1 ) ) === 0 && value !== 0;
467
468}
469
470function ceilPowerOfTwo( value ) {
471
472	return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
473
474}
475
476function floorPowerOfTwo( value ) {
477
478	return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
479
480}
481
482function setQuaternionFromProperEuler( q, a, b, c, order ) {
483
484	// Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
485
486	// rotations are applied to the axes in the order specified by 'order'
487	// rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
488	// angles are in radians
489
490	const cos = Math.cos;
491	const sin = Math.sin;
492
493	const c2 = cos( b / 2 );
494	const s2 = sin( b / 2 );
495
496	const c13 = cos( ( a + c ) / 2 );
497	const s13 = sin( ( a + c ) / 2 );
498
499	const c1_3 = cos( ( a - c ) / 2 );
500	const s1_3 = sin( ( a - c ) / 2 );
501
502	const c3_1 = cos( ( c - a ) / 2 );
503	const s3_1 = sin( ( c - a ) / 2 );
504
505	switch ( order ) {
506
507		case 'XYX':
508			q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
509			break;
510
511		case 'YZY':
512			q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
513			break;
514
515		case 'ZXZ':
516			q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
517			break;
518
519		case 'XZX':
520			q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
521			break;
522
523		case 'YXY':
524			q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
525			break;
526
527		case 'ZYZ':
528			q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
529			break;
530
531		default:
532			console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
533
534	}
535
536}
537
538function denormalize( value, array ) {
539
540	switch ( array.constructor ) {
541
542		case Float32Array:
543
544			return value;
545
546		case Uint32Array:
547
548			return value / 4294967295.0;
549
550		case Uint16Array:
551
552			return value / 65535.0;
553
554		case Uint8Array:
555
556			return value / 255.0;
557
558		case Int32Array:
559
560			return Math.max( value / 2147483647.0, - 1.0 );
561
562		case Int16Array:
563
564			return Math.max( value / 32767.0, - 1.0 );
565
566		case Int8Array:
567
568			return Math.max( value / 127.0, - 1.0 );
569
570		default:
571
572			throw new Error( 'Invalid component type.' );
573
574	}
575
576}
577
578function normalize( value, array ) {
579
580	switch ( array.constructor ) {
581
582		case Float32Array:
583
584			return value;
585
586		case Uint32Array:
587
588			return Math.round( value * 4294967295.0 );
589
590		case Uint16Array:
591
592			return Math.round( value * 65535.0 );
593
594		case Uint8Array:
595
596			return Math.round( value * 255.0 );
597
598		case Int32Array:
599
600			return Math.round( value * 2147483647.0 );
601
602		case Int16Array:
603
604			return Math.round( value * 32767.0 );
605
606		case Int8Array:
607
608			return Math.round( value * 127.0 );
609
610		default:
611
612			throw new Error( 'Invalid component type.' );
613
614	}
615
616}
617
618const MathUtils = {
619	DEG2RAD: DEG2RAD,
620	RAD2DEG: RAD2DEG,
621	generateUUID: generateUUID,
622	clamp: clamp,
623	euclideanModulo: euclideanModulo,
624	mapLinear: mapLinear,
625	inverseLerp: inverseLerp,
626	lerp: lerp,
627	damp: damp,
628	pingpong: pingpong,
629	smoothstep: smoothstep,
630	smootherstep: smootherstep,
631	randInt: randInt,
632	randFloat: randFloat,
633	randFloatSpread: randFloatSpread,
634	seededRandom: seededRandom,
635	degToRad: degToRad,
636	radToDeg: radToDeg,
637	isPowerOfTwo: isPowerOfTwo,
638	ceilPowerOfTwo: ceilPowerOfTwo,
639	floorPowerOfTwo: floorPowerOfTwo,
640	setQuaternionFromProperEuler: setQuaternionFromProperEuler,
641	normalize: normalize,
642	denormalize: denormalize
643};
644
645class Vector2 {
646
647	constructor( x = 0, y = 0 ) {
648
649		Vector2.prototype.isVector2 = true;
650
651		this.x = x;
652		this.y = y;
653
654	}
655
656	get width() {
657
658		return this.x;
659
660	}
661
662	set width( value ) {
663
664		this.x = value;
665
666	}
667
668	get height() {
669
670		return this.y;
671
672	}
673
674	set height( value ) {
675
676		this.y = value;
677
678	}
679
680	set( x, y ) {
681
682		this.x = x;
683		this.y = y;
684
685		return this;
686
687	}
688
689	setScalar( scalar ) {
690
691		this.x = scalar;
692		this.y = scalar;
693
694		return this;
695
696	}
697
698	setX( x ) {
699
700		this.x = x;
701
702		return this;
703
704	}
705
706	setY( y ) {
707
708		this.y = y;
709
710		return this;
711
712	}
713
714	setComponent( index, value ) {
715
716		switch ( index ) {
717
718			case 0: this.x = value; break;
719			case 1: this.y = value; break;
720			default: throw new Error( 'index is out of range: ' + index );
721
722		}
723
724		return this;
725
726	}
727
728	getComponent( index ) {
729
730		switch ( index ) {
731
732			case 0: return this.x;
733			case 1: return this.y;
734			default: throw new Error( 'index is out of range: ' + index );
735
736		}
737
738	}
739
740	clone() {
741
742		return new this.constructor( this.x, this.y );
743
744	}
745
746	copy( v ) {
747
748		this.x = v.x;
749		this.y = v.y;
750
751		return this;
752
753	}
754
755	add( v ) {
756
757		this.x += v.x;
758		this.y += v.y;
759
760		return this;
761
762	}
763
764	addScalar( s ) {
765
766		this.x += s;
767		this.y += s;
768
769		return this;
770
771	}
772
773	addVectors( a, b ) {
774
775		this.x = a.x + b.x;
776		this.y = a.y + b.y;
777
778		return this;
779
780	}
781
782	addScaledVector( v, s ) {
783
784		this.x += v.x * s;
785		this.y += v.y * s;
786
787		return this;
788
789	}
790
791	sub( v ) {
792
793		this.x -= v.x;
794		this.y -= v.y;
795
796		return this;
797
798	}
799
800	subScalar( s ) {
801
802		this.x -= s;
803		this.y -= s;
804
805		return this;
806
807	}
808
809	subVectors( a, b ) {
810
811		this.x = a.x - b.x;
812		this.y = a.y - b.y;
813
814		return this;
815
816	}
817
818	multiply( v ) {
819
820		this.x *= v.x;
821		this.y *= v.y;
822
823		return this;
824
825	}
826
827	multiplyScalar( scalar ) {
828
829		this.x *= scalar;
830		this.y *= scalar;
831
832		return this;
833
834	}
835
vendor: 6,898 bytes, lines 836-1268
836	divide( v ) {
837
838		this.x /= v.x;
839		this.y /= v.y;
840
841		return this;
842
843	}
844
845	divideScalar( scalar ) {
846
847		return this.multiplyScalar( 1 / scalar );
848
849	}
850
851	applyMatrix3( m ) {
852
853		const x = this.x, y = this.y;
854		const e = m.elements;
855
856		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
857		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
858
859		return this;
860
861	}
862
863	min( v ) {
864
865		this.x = Math.min( this.x, v.x );
866		this.y = Math.min( this.y, v.y );
867
868		return this;
869
870	}
871
872	max( v ) {
873
874		this.x = Math.max( this.x, v.x );
875		this.y = Math.max( this.y, v.y );
876
877		return this;
878
879	}
880
881	clamp( min, max ) {
882
883		// assumes min < max, componentwise
884
885		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
886		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
887
888		return this;
889
890	}
891
892	clampScalar( minVal, maxVal ) {
893
894		this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
895		this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
896
897		return this;
898
899	}
900
901	clampLength( min, max ) {
902
903		const length = this.length();
904
905		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
906
907	}
908
909	floor() {
910
911		this.x = Math.floor( this.x );
912		this.y = Math.floor( this.y );
913
914		return this;
915
916	}
917
918	ceil() {
919
920		this.x = Math.ceil( this.x );
921		this.y = Math.ceil( this.y );
922
923		return this;
924
925	}
926
927	round() {
928
929		this.x = Math.round( this.x );
930		this.y = Math.round( this.y );
931
932		return this;
933
934	}
935
936	roundToZero() {
937
938		this.x = Math.trunc( this.x );
939		this.y = Math.trunc( this.y );
940
941		return this;
942
943	}
944
945	negate() {
946
947		this.x = - this.x;
948		this.y = - this.y;
949
950		return this;
951
952	}
953
954	dot( v ) {
955
956		return this.x * v.x + this.y * v.y;
957
958	}
959
960	cross( v ) {
961
962		return this.x * v.y - this.y * v.x;
963
964	}
965
966	lengthSq() {
967
968		return this.x * this.x + this.y * this.y;
969
970	}
971
972	length() {
973
974		return Math.sqrt( this.x * this.x + this.y * this.y );
975
976	}
977
978	manhattanLength() {
979
980		return Math.abs( this.x ) + Math.abs( this.y );
981
982	}
983
984	normalize() {
985
986		return this.divideScalar( this.length() || 1 );
987
988	}
989
990	angle() {
991
992		// computes the angle in radians with respect to the positive x-axis
993
994		const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
995
996		return angle;
997
998	}
999
1000	angleTo( v ) {
1001
1002		const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
1003
1004		if ( denominator === 0 ) return Math.PI / 2;
1005
1006		const theta = this.dot( v ) / denominator;
1007
1008		// clamp, to handle numerical problems
1009
1010		return Math.acos( clamp( theta, - 1, 1 ) );
1011
1012	}
1013
1014	distanceTo( v ) {
1015
1016		return Math.sqrt( this.distanceToSquared( v ) );
1017
1018	}
1019
1020	distanceToSquared( v ) {
1021
1022		const dx = this.x - v.x, dy = this.y - v.y;
1023		return dx * dx + dy * dy;
1024
1025	}
1026
1027	manhattanDistanceTo( v ) {
1028
1029		return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
1030
1031	}
1032
1033	setLength( length ) {
1034
1035		return this.normalize().multiplyScalar( length );
1036
1037	}
1038
1039	lerp( v, alpha ) {
1040
1041		this.x += ( v.x - this.x ) * alpha;
1042		this.y += ( v.y - this.y ) * alpha;
1043
1044		return this;
1045
1046	}
1047
1048	lerpVectors( v1, v2, alpha ) {
1049
1050		this.x = v1.x + ( v2.x - v1.x ) * alpha;
1051		this.y = v1.y + ( v2.y - v1.y ) * alpha;
1052
1053		return this;
1054
1055	}
1056
1057	equals( v ) {
1058
1059		return ( ( v.x === this.x ) && ( v.y === this.y ) );
1060
1061	}
1062
1063	fromArray( array, offset = 0 ) {
1064
1065		this.x = array[ offset ];
1066		this.y = array[ offset + 1 ];
1067
1068		return this;
1069
1070	}
1071
1072	toArray( array = [], offset = 0 ) {
1073
1074		array[ offset ] = this.x;
1075		array[ offset + 1 ] = this.y;
1076
1077		return array;
1078
1079	}
1080
1081	fromBufferAttribute( attribute, index ) {
1082
1083		this.x = attribute.getX( index );
1084		this.y = attribute.getY( index );
1085
1086		return this;
1087
1088	}
1089
1090	rotateAround( center, angle ) {
1091
1092		const c = Math.cos( angle ), s = Math.sin( angle );
1093
1094		const x = this.x - center.x;
1095		const y = this.y - center.y;
1096
1097		this.x = x * c - y * s + center.x;
1098		this.y = x * s + y * c + center.y;
1099
1100		return this;
1101
1102	}
1103
1104	random() {
1105
1106		this.x = Math.random();
1107		this.y = Math.random();
1108
1109		return this;
1110
1111	}
1112
1113	*[ Symbol.iterator ]() {
1114
1115		yield this.x;
1116		yield this.y;
1117
1118	}
1119
1120}
1121
1122class Matrix3 {
1123
1124	constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1125
1126		Matrix3.prototype.isMatrix3 = true;
1127
1128		this.elements = [
1129
1130			1, 0, 0,
1131			0, 1, 0,
1132			0, 0, 1
1133
1134		];
1135
1136		if ( n11 !== undefined ) {
1137
1138			this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
1139
1140		}
1141
1142	}
1143
1144	set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1145
1146		const te = this.elements;
1147
1148		te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
1149		te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
1150		te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
1151
1152		return this;
1153
1154	}
1155
1156	identity() {
1157
1158		this.set(
1159
1160			1, 0, 0,
1161			0, 1, 0,
1162			0, 0, 1
1163
1164		);
1165
1166		return this;
1167
1168	}
1169
1170	copy( m ) {
1171
1172		const te = this.elements;
1173		const me = m.elements;
1174
1175		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
1176		te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
1177		te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
1178
1179		return this;
1180
1181	}
1182
1183	extractBasis( xAxis, yAxis, zAxis ) {
1184
1185		xAxis.setFromMatrix3Column( this, 0 );
1186		yAxis.setFromMatrix3Column( this, 1 );
1187		zAxis.setFromMatrix3Column( this, 2 );
1188
1189		return this;
1190
1191	}
1192
1193	setFromMatrix4( m ) {
1194
1195		const me = m.elements;
1196
1197		this.set(
1198
1199			me[ 0 ], me[ 4 ], me[ 8 ],
1200			me[ 1 ], me[ 5 ], me[ 9 ],
1201			me[ 2 ], me[ 6 ], me[ 10 ]
1202
1203		);
1204
1205		return this;
1206
1207	}
1208
1209	multiply( m ) {
1210
1211		return this.multiplyMatrices( this, m );
1212
1213	}
1214
1215	premultiply( m ) {
1216
1217		return this.multiplyMatrices( m, this );
1218
1219	}
1220
1221	multiplyMatrices( a, b ) {
1222
1223		const ae = a.elements;
1224		const be = b.elements;
1225		const te = this.elements;
1226
1227		const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
1228		const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
1229		const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
1230
1231		const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
1232		const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
1233		const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
1234
1235		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
1236		te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
1237		te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
1238
1239		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
1240		te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
1241		te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
1242
1243		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
1244		te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
1245		te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
1246
1247		return this;
1248
1249	}
1250
1251	multiplyScalar( s ) {
1252
1253		const te = this.elements;
1254
1255		te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
1256		te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
1257		te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
1258
1259		return this;
1260
1261	}
1262
1263	determinant() {
1264
1265		const te = this.elements;
1266
1267		const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
1268			d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
vendor: 4,678 bytes, lines 1269-1560
1269			g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
1270
1271		return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
1272
1273	}
1274
1275	invert() {
1276
1277		const te = this.elements,
1278
1279			n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
1280			n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
1281			n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
1282
1283			t11 = n33 * n22 - n32 * n23,
1284			t12 = n32 * n13 - n33 * n12,
1285			t13 = n23 * n12 - n22 * n13,
1286
1287			det = n11 * t11 + n21 * t12 + n31 * t13;
1288
1289		if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1290
1291		const detInv = 1 / det;
1292
1293		te[ 0 ] = t11 * detInv;
1294		te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
1295		te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
1296
1297		te[ 3 ] = t12 * detInv;
1298		te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
1299		te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
1300
1301		te[ 6 ] = t13 * detInv;
1302		te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
1303		te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
1304
1305		return this;
1306
1307	}
1308
1309	transpose() {
1310
1311		let tmp;
1312		const m = this.elements;
1313
1314		tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
1315		tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
1316		tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
1317
1318		return this;
1319
1320	}
1321
1322	getNormalMatrix( matrix4 ) {
1323
1324		return this.setFromMatrix4( matrix4 ).invert().transpose();
1325
1326	}
1327
1328	transposeIntoArray( r ) {
1329
1330		const m = this.elements;
1331
1332		r[ 0 ] = m[ 0 ];
1333		r[ 1 ] = m[ 3 ];
1334		r[ 2 ] = m[ 6 ];
1335		r[ 3 ] = m[ 1 ];
1336		r[ 4 ] = m[ 4 ];
1337		r[ 5 ] = m[ 7 ];
1338		r[ 6 ] = m[ 2 ];
1339		r[ 7 ] = m[ 5 ];
1340		r[ 8 ] = m[ 8 ];
1341
1342		return this;
1343
1344	}
1345
1346	setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
1347
1348		const c = Math.cos( rotation );
1349		const s = Math.sin( rotation );
1350
1351		this.set(
1352			sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
1353			- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
1354			0, 0, 1
1355		);
1356
1357		return this;
1358
1359	}
1360
1361	//
1362
1363	scale( sx, sy ) {
1364
1365		this.premultiply( _m3.makeScale( sx, sy ) );
1366
1367		return this;
1368
1369	}
1370
1371	rotate( theta ) {
1372
1373		this.premultiply( _m3.makeRotation( - theta ) );
1374
1375		return this;
1376
1377	}
1378
1379	translate( tx, ty ) {
1380
1381		this.premultiply( _m3.makeTranslation( tx, ty ) );
1382
1383		return this;
1384
1385	}
1386
1387	// for 2D Transforms
1388
1389	makeTranslation( x, y ) {
1390
1391		if ( x.isVector2 ) {
1392
1393			this.set(
1394
1395				1, 0, x.x,
1396				0, 1, x.y,
1397				0, 0, 1
1398
1399			);
1400
1401		} else {
1402
1403			this.set(
1404
1405				1, 0, x,
1406				0, 1, y,
1407				0, 0, 1
1408
1409			);
1410
1411		}
1412
1413		return this;
1414
1415	}
1416
1417	makeRotation( theta ) {
1418
1419		// counterclockwise
1420
1421		const c = Math.cos( theta );
1422		const s = Math.sin( theta );
1423
1424		this.set(
1425
1426			c, - s, 0,
1427			s, c, 0,
1428			0, 0, 1
1429
1430		);
1431
1432		return this;
1433
1434	}
1435
1436	makeScale( x, y ) {
1437
1438		this.set(
1439
1440			x, 0, 0,
1441			0, y, 0,
1442			0, 0, 1
1443
1444		);
1445
1446		return this;
1447
1448	}
1449
1450	//
1451
1452	equals( matrix ) {
1453
1454		const te = this.elements;
1455		const me = matrix.elements;
1456
1457		for ( let i = 0; i < 9; i ++ ) {
1458
1459			if ( te[ i ] !== me[ i ] ) return false;
1460
1461		}
1462
1463		return true;
1464
1465	}
1466
1467	fromArray( array, offset = 0 ) {
1468
1469		for ( let i = 0; i < 9; i ++ ) {
1470
1471			this.elements[ i ] = array[ i + offset ];
1472
1473		}
1474
1475		return this;
1476
1477	}
1478
1479	toArray( array = [], offset = 0 ) {
1480
1481		const te = this.elements;
1482
1483		array[ offset ] = te[ 0 ];
1484		array[ offset + 1 ] = te[ 1 ];
1485		array[ offset + 2 ] = te[ 2 ];
1486
1487		array[ offset + 3 ] = te[ 3 ];
1488		array[ offset + 4 ] = te[ 4 ];
1489		array[ offset + 5 ] = te[ 5 ];
1490
1491		array[ offset + 6 ] = te[ 6 ];
1492		array[ offset + 7 ] = te[ 7 ];
1493		array[ offset + 8 ] = te[ 8 ];
1494
1495		return array;
1496
1497	}
1498
1499	clone() {
1500
1501		return new this.constructor().fromArray( this.elements );
1502
1503	}
1504
1505}
1506
1507const _m3 = /*@__PURE__*/ new Matrix3();
1508
1509function arrayNeedsUint32( array ) {
1510
1511	// assumes larger values usually on last
1512
1513	for ( let i = array.length - 1; i >= 0; -- i ) {
1514
1515		if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
1516
1517	}
1518
1519	return false;
1520
1521}
1522
1523const TYPED_ARRAYS = {
1524	Int8Array: Int8Array,
1525	Uint8Array: Uint8Array,
1526	Uint8ClampedArray: Uint8ClampedArray,
1527	Int16Array: Int16Array,
1528	Uint16Array: Uint16Array,
1529	Int32Array: Int32Array,
1530	Uint32Array: Uint32Array,
1531	Float32Array: Float32Array,
1532	Float64Array: Float64Array
1533};
1534
1535function getTypedArray( type, buffer ) {
1536
1537	return new TYPED_ARRAYS[ type ]( buffer );
1538
1539}
1540
1541function createElementNS( name ) {
1542
1543	return document.createElementNS( 'http://www.w3.org/1999/xhtml', name );
1544
1545}
1546
1547function createCanvasElement() {
1548
1549	const canvas = createElementNS( 'canvas' );
1550	canvas.style.display = 'block';
1551	return canvas;
1552
1553}
1554
1555const _cache = {};
1556
1557function warnOnce( message ) {
1558
1559	if ( message in _cache ) return;
1560
vendor: 8,200 bytes, lines 1561-1953
1561	_cache[ message ] = true;
1562
1563	console.warn( message );
1564
1565}
1566
1567/**
1568 * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping
1569 * or clipping. Based on W3C specifications for sRGB and Display P3,
1570 * and ICC specifications for the D50 connection space. Values in/out
1571 * are _linear_ sRGB and _linear_ Display P3.
1572 *
1573 * Note that both sRGB and Display P3 use the sRGB transfer functions.
1574 *
1575 * Reference:
1576 * - http://www.russellcottrell.com/photo/matrixCalculator.htm
1577 */
1578
1579const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set(
1580	0.8224621, 0.177538, 0.0,
1581	0.0331941, 0.9668058, 0.0,
1582	0.0170827, 0.0723974, 0.9105199,
1583);
1584
1585const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set(
1586	1.2249401, - 0.2249404, 0.0,
1587	- 0.0420569, 1.0420571, 0.0,
1588	- 0.0196376, - 0.0786361, 1.0982735
1589);
1590
1591/**
1592 * Defines supported color spaces by transfer function and primaries,
1593 * and provides conversions to/from the Linear-sRGB reference space.
1594 */
1595const COLOR_SPACES = {
1596	[ LinearSRGBColorSpace ]: {
1597		transfer: LinearTransfer,
1598		primaries: Rec709Primaries,
1599		toReference: ( color ) => color,
1600		fromReference: ( color ) => color,
1601	},
1602	[ SRGBColorSpace ]: {
1603		transfer: SRGBTransfer,
1604		primaries: Rec709Primaries,
1605		toReference: ( color ) => color.convertSRGBToLinear(),
1606		fromReference: ( color ) => color.convertLinearToSRGB(),
1607	},
1608	[ LinearDisplayP3ColorSpace ]: {
1609		transfer: LinearTransfer,
1610		primaries: P3Primaries,
1611		toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),
1612		fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ),
1613	},
1614	[ DisplayP3ColorSpace ]: {
1615		transfer: SRGBTransfer,
1616		primaries: P3Primaries,
1617		toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),
1618		fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(),
1619	},
1620};
1621
1622const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] );
1623
1624const ColorManagement = {
1625
1626	enabled: true,
1627
1628	_workingColorSpace: LinearSRGBColorSpace,
1629
1630	get workingColorSpace() {
1631
1632		return this._workingColorSpace;
1633
1634	},
1635
1636	set workingColorSpace( colorSpace ) {
1637
1638		if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) {
1639
1640			throw new Error( `Unsupported working color space, "${ colorSpace }".` );
1641
1642		}
1643
1644		this._workingColorSpace = colorSpace;
1645
1646	},
1647
1648	convert: function ( color, sourceColorSpace, targetColorSpace ) {
1649
1650		if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {
1651
1652			return color;
1653
1654		}
1655
1656		const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference;
1657		const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference;
1658
1659		return targetFromReference( sourceToReference( color ) );
1660
1661	},
1662
1663	fromWorkingColorSpace: function ( color, targetColorSpace ) {
1664
1665		return this.convert( color, this._workingColorSpace, targetColorSpace );
1666
1667	},
1668
1669	toWorkingColorSpace: function ( color, sourceColorSpace ) {
1670
1671		return this.convert( color, sourceColorSpace, this._workingColorSpace );
1672
1673	},
1674
1675	getPrimaries: function ( colorSpace ) {
1676
1677		return COLOR_SPACES[ colorSpace ].primaries;
1678
1679	},
1680
1681	getTransfer: function ( colorSpace ) {
1682
1683		if ( colorSpace === NoColorSpace ) return LinearTransfer;
1684
1685		return COLOR_SPACES[ colorSpace ].transfer;
1686
1687	},
1688
1689};
1690
1691
1692function SRGBToLinear( c ) {
1693
1694	return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
1695
1696}
1697
1698function LinearToSRGB( c ) {
1699
1700	return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
1701
1702}
1703
1704let _canvas;
1705
1706class ImageUtils {
1707
1708	static getDataURL( image ) {
1709
1710		if ( /^data:/i.test( image.src ) ) {
1711
1712			return image.src;
1713
1714		}
1715
1716		if ( typeof HTMLCanvasElement === 'undefined' ) {
1717
1718			return image.src;
1719
1720		}
1721
1722		let canvas;
1723
1724		if ( image instanceof HTMLCanvasElement ) {
1725
1726			canvas = image;
1727
1728		} else {
1729
1730			if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );
1731
1732			_canvas.width = image.width;
1733			_canvas.height = image.height;
1734
1735			const context = _canvas.getContext( '2d' );
1736
1737			if ( image instanceof ImageData ) {
1738
1739				context.putImageData( image, 0, 0 );
1740
1741			} else {
1742
1743				context.drawImage( image, 0, 0, image.width, image.height );
1744
1745			}
1746
1747			canvas = _canvas;
1748
1749		}
1750
1751		if ( canvas.width > 2048 || canvas.height > 2048 ) {
1752
1753			console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );
1754
1755			return canvas.toDataURL( 'image/jpeg', 0.6 );
1756
1757		} else {
1758
1759			return canvas.toDataURL( 'image/png' );
1760
1761		}
1762
1763	}
1764
1765	static sRGBToLinear( image ) {
1766
1767		if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1768			( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
1769			( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1770
1771			const canvas = createElementNS( 'canvas' );
1772
1773			canvas.width = image.width;
1774			canvas.height = image.height;
1775
1776			const context = canvas.getContext( '2d' );
1777			context.drawImage( image, 0, 0, image.width, image.height );
1778
1779			const imageData = context.getImageData( 0, 0, image.width, image.height );
1780			const data = imageData.data;
1781
1782			for ( let i = 0; i < data.length; i ++ ) {
1783
1784				data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
1785
1786			}
1787
1788			context.putImageData( imageData, 0, 0 );
1789
1790			return canvas;
1791
1792		} else if ( image.data ) {
1793
1794			const data = image.data.slice( 0 );
1795
1796			for ( let i = 0; i < data.length; i ++ ) {
1797
1798				if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {
1799
1800					data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
1801
1802				} else {
1803
1804					// assuming float
1805
1806					data[ i ] = SRGBToLinear( data[ i ] );
1807
1808				}
1809
1810			}
1811
1812			return {
1813				data: data,
1814				width: image.width,
1815				height: image.height
1816			};
1817
1818		} else {
1819
1820			console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
1821			return image;
1822
1823		}
1824
1825	}
1826
1827}
1828
1829let _sourceId = 0;
1830
1831class Source {
1832
1833	constructor( data = null ) {
1834
1835		this.isSource = true;
1836
1837		Object.defineProperty( this, 'id', { value: _sourceId ++ } );
1838
1839		this.uuid = generateUUID();
1840
1841		this.data = data;
1842
1843		this.version = 0;
1844
1845	}
1846
1847	set needsUpdate( value ) {
1848
1849		if ( value === true ) this.version ++;
1850
1851	}
1852
1853	toJSON( meta ) {
1854
1855		const isRootObject = ( meta === undefined || typeof meta === 'string' );
1856
1857		if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) {
1858
1859			return meta.images[ this.uuid ];
1860
1861		}
1862
1863		const output = {
1864			uuid: this.uuid,
1865			url: ''
1866		};
1867
1868		const data = this.data;
1869
1870		if ( data !== null ) {
1871
1872			let url;
1873
1874			if ( Array.isArray( data ) ) {
1875
1876				// cube texture
1877
1878				url = [];
1879
1880				for ( let i = 0, l = data.length; i < l; i ++ ) {
1881
1882					if ( data[ i ].isDataTexture ) {
1883
1884						url.push( serializeImage( data[ i ].image ) );
1885
1886					} else {
1887
1888						url.push( serializeImage( data[ i ] ) );
1889
1890					}
1891
1892				}
1893
1894			} else {
1895
1896				// texture
1897
1898				url = serializeImage( data );
1899
1900			}
1901
1902			output.url = url;
1903
1904		}
1905
1906		if ( ! isRootObject ) {
1907
1908			meta.images[ this.uuid ] = output;
1909
1910		}
1911
1912		return output;
1913
1914	}
1915
1916}
1917
1918function serializeImage( image ) {
1919
1920	if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1921		( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
1922		( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1923
1924		// default images
1925
1926		return ImageUtils.getDataURL( image );
1927
1928	} else {
1929
1930		if ( image.data ) {
1931
1932			// images of DataTexture
1933
1934			return {
1935				data: Array.from( image.data ),
1936				width: image.width,
1937				height: image.height,
1938				type: image.data.constructor.name
1939			};
1940
1941		} else {
1942
1943			console.warn( 'THREE.Texture: Unable to serialize Texture.' );
1944			return {};
1945
1946		}
1947
1948	}
1949
1950}
1951
1952let _textureId = 0;
1953
vendor: 9,254 bytes, lines 1954-2504
1954class Texture extends EventDispatcher {
1955
1956	constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) {
1957
1958		super();
1959
1960		this.isTexture = true;
1961
1962		Object.defineProperty( this, 'id', { value: _textureId ++ } );
1963
1964		this.uuid = generateUUID();
1965
1966		this.name = '';
1967
1968		this.source = new Source( image );
1969		this.mipmaps = [];
1970
1971		this.mapping = mapping;
1972		this.channel = 0;
1973
1974		this.wrapS = wrapS;
1975		this.wrapT = wrapT;
1976
1977		this.magFilter = magFilter;
1978		this.minFilter = minFilter;
1979
1980		this.anisotropy = anisotropy;
1981
1982		this.format = format;
1983		this.internalFormat = null;
1984		this.type = type;
1985
1986		this.offset = new Vector2( 0, 0 );
1987		this.repeat = new Vector2( 1, 1 );
1988		this.center = new Vector2( 0, 0 );
1989		this.rotation = 0;
1990
1991		this.matrixAutoUpdate = true;
1992		this.matrix = new Matrix3();
1993
1994		this.generateMipmaps = true;
1995		this.premultiplyAlpha = false;
1996		this.flipY = true;
1997		this.unpackAlignment = 4;	// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
1998
1999		if ( typeof colorSpace === 'string' ) {
2000
2001			this.colorSpace = colorSpace;
2002
2003		} else { // @deprecated, r152
2004
2005			warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2006			this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
2007
2008		}
2009
2010
2011		this.userData = {};
2012
2013		this.version = 0;
2014		this.onUpdate = null;
2015
2016		this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not
2017		this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures)
2018
2019	}
2020
2021	get image() {
2022
2023		return this.source.data;
2024
2025	}
2026
2027	set image( value = null ) {
2028
2029		this.source.data = value;
2030
2031	}
2032
2033	updateMatrix() {
2034
2035		this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
2036
2037	}
2038
2039	clone() {
2040
2041		return new this.constructor().copy( this );
2042
2043	}
2044
2045	copy( source ) {
2046
2047		this.name = source.name;
2048
2049		this.source = source.source;
2050		this.mipmaps = source.mipmaps.slice( 0 );
2051
2052		this.mapping = source.mapping;
2053		this.channel = source.channel;
2054
2055		this.wrapS = source.wrapS;
2056		this.wrapT = source.wrapT;
2057
2058		this.magFilter = source.magFilter;
2059		this.minFilter = source.minFilter;
2060
2061		this.anisotropy = source.anisotropy;
2062
2063		this.format = source.format;
2064		this.internalFormat = source.internalFormat;
2065		this.type = source.type;
2066
2067		this.offset.copy( source.offset );
2068		this.repeat.copy( source.repeat );
2069		this.center.copy( source.center );
2070		this.rotation = source.rotation;
2071
2072		this.matrixAutoUpdate = source.matrixAutoUpdate;
2073		this.matrix.copy( source.matrix );
2074
2075		this.generateMipmaps = source.generateMipmaps;
2076		this.premultiplyAlpha = source.premultiplyAlpha;
2077		this.flipY = source.flipY;
2078		this.unpackAlignment = source.unpackAlignment;
2079		this.colorSpace = source.colorSpace;
2080
2081		this.userData = JSON.parse( JSON.stringify( source.userData ) );
2082
2083		this.needsUpdate = true;
2084
2085		return this;
2086
2087	}
2088
2089	toJSON( meta ) {
2090
2091		const isRootObject = ( meta === undefined || typeof meta === 'string' );
2092
2093		if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
2094
2095			return meta.textures[ this.uuid ];
2096
2097		}
2098
2099		const output = {
2100
2101			metadata: {
2102				version: 4.6,
2103				type: 'Texture',
2104				generator: 'Texture.toJSON'
2105			},
2106
2107			uuid: this.uuid,
2108			name: this.name,
2109
2110			image: this.source.toJSON( meta ).uuid,
2111
2112			mapping: this.mapping,
2113			channel: this.channel,
2114
2115			repeat: [ this.repeat.x, this.repeat.y ],
2116			offset: [ this.offset.x, this.offset.y ],
2117			center: [ this.center.x, this.center.y ],
2118			rotation: this.rotation,
2119
2120			wrap: [ this.wrapS, this.wrapT ],
2121
2122			format: this.format,
2123			internalFormat: this.internalFormat,
2124			type: this.type,
2125			colorSpace: this.colorSpace,
2126
2127			minFilter: this.minFilter,
2128			magFilter: this.magFilter,
2129			anisotropy: this.anisotropy,
2130
2131			flipY: this.flipY,
2132
2133			generateMipmaps: this.generateMipmaps,
2134			premultiplyAlpha: this.premultiplyAlpha,
2135			unpackAlignment: this.unpackAlignment
2136
2137		};
2138
2139		if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;
2140
2141		if ( ! isRootObject ) {
2142
2143			meta.textures[ this.uuid ] = output;
2144
2145		}
2146
2147		return output;
2148
2149	}
2150
2151	dispose() {
2152
2153		this.dispatchEvent( { type: 'dispose' } );
2154
2155	}
2156
2157	transformUv( uv ) {
2158
2159		if ( this.mapping !== UVMapping ) return uv;
2160
2161		uv.applyMatrix3( this.matrix );
2162
2163		if ( uv.x < 0 || uv.x > 1 ) {
2164
2165			switch ( this.wrapS ) {
2166
2167				case RepeatWrapping:
2168
2169					uv.x = uv.x - Math.floor( uv.x );
2170					break;
2171
2172				case ClampToEdgeWrapping:
2173
2174					uv.x = uv.x < 0 ? 0 : 1;
2175					break;
2176
2177				case MirroredRepeatWrapping:
2178
2179					if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
2180
2181						uv.x = Math.ceil( uv.x ) - uv.x;
2182
2183					} else {
2184
2185						uv.x = uv.x - Math.floor( uv.x );
2186
2187					}
2188
2189					break;
2190
2191			}
2192
2193		}
2194
2195		if ( uv.y < 0 || uv.y > 1 ) {
2196
2197			switch ( this.wrapT ) {
2198
2199				case RepeatWrapping:
2200
2201					uv.y = uv.y - Math.floor( uv.y );
2202					break;
2203
2204				case ClampToEdgeWrapping:
2205
2206					uv.y = uv.y < 0 ? 0 : 1;
2207					break;
2208
2209				case MirroredRepeatWrapping:
2210
2211					if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
2212
2213						uv.y = Math.ceil( uv.y ) - uv.y;
2214
2215					} else {
2216
2217						uv.y = uv.y - Math.floor( uv.y );
2218
2219					}
2220
2221					break;
2222
2223			}
2224
2225		}
2226
2227		if ( this.flipY ) {
2228
2229			uv.y = 1 - uv.y;
2230
2231		}
2232
2233		return uv;
2234
2235	}
2236
2237	set needsUpdate( value ) {
2238
2239		if ( value === true ) {
2240
2241			this.version ++;
2242			this.source.needsUpdate = true;
2243
2244		}
2245
2246	}
2247
2248	get encoding() { // @deprecated, r152
2249
2250		warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2251		return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding;
2252
2253	}
2254
2255	set encoding( encoding ) { // @deprecated, r152
2256
2257		warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2258		this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
2259
2260	}
2261
2262}
2263
2264Texture.DEFAULT_IMAGE = null;
2265Texture.DEFAULT_MAPPING = UVMapping;
2266Texture.DEFAULT_ANISOTROPY = 1;
2267
2268class Vector4 {
2269
2270	constructor( x = 0, y = 0, z = 0, w = 1 ) {
2271
2272		Vector4.prototype.isVector4 = true;
2273
2274		this.x = x;
2275		this.y = y;
2276		this.z = z;
2277		this.w = w;
2278
2279	}
2280
2281	get width() {
2282
2283		return this.z;
2284
2285	}
2286
2287	set width( value ) {
2288
2289		this.z = value;
2290
2291	}
2292
2293	get height() {
2294
2295		return this.w;
2296
2297	}
2298
2299	set height( value ) {
2300
2301		this.w = value;
2302
2303	}
2304
2305	set( x, y, z, w ) {
2306
2307		this.x = x;
2308		this.y = y;
2309		this.z = z;
2310		this.w = w;
2311
2312		return this;
2313
2314	}
2315
2316	setScalar( scalar ) {
2317
2318		this.x = scalar;
2319		this.y = scalar;
2320		this.z = scalar;
2321		this.w = scalar;
2322
2323		return this;
2324
2325	}
2326
2327	setX( x ) {
2328
2329		this.x = x;
2330
2331		return this;
2332
2333	}
2334
2335	setY( y ) {
2336
2337		this.y = y;
2338
2339		return this;
2340
2341	}
2342
2343	setZ( z ) {
2344
2345		this.z = z;
2346
2347		return this;
2348
2349	}
2350
2351	setW( w ) {
2352
2353		this.w = w;
2354
2355		return this;
2356
2357	}
2358
2359	setComponent( index, value ) {
2360
2361		switch ( index ) {
2362
2363			case 0: this.x = value; break;
2364			case 1: this.y = value; break;
2365			case 2: this.z = value; break;
2366			case 3: this.w = value; break;
2367			default: throw new Error( 'index is out of range: ' + index );
2368
2369		}
2370
2371		return this;
2372
2373	}
2374
2375	getComponent( index ) {
2376
2377		switch ( index ) {
2378
2379			case 0: return this.x;
2380			case 1: return this.y;
2381			case 2: return this.z;
2382			case 3: return this.w;
2383			default: throw new Error( 'index is out of range: ' + index );
2384
2385		}
2386
2387	}
2388
2389	clone() {
2390
2391		return new this.constructor( this.x, this.y, this.z, this.w );
2392
2393	}
2394
2395	copy( v ) {
2396
2397		this.x = v.x;
2398		this.y = v.y;
2399		this.z = v.z;
2400		this.w = ( v.w !== undefined ) ? v.w : 1;
2401
2402		return this;
2403
2404	}
2405
2406	add( v ) {
2407
2408		this.x += v.x;
2409		this.y += v.y;
2410		this.z += v.z;
2411		this.w += v.w;
2412
2413		return this;
2414
2415	}
2416
2417	addScalar( s ) {
2418
2419		this.x += s;
2420		this.y += s;
2421		this.z += s;
2422		this.w += s;
2423
2424		return this;
2425
2426	}
2427
2428	addVectors( a, b ) {
2429
2430		this.x = a.x + b.x;
2431		this.y = a.y + b.y;
2432		this.z = a.z + b.z;
2433		this.w = a.w + b.w;
2434
2435		return this;
2436
2437	}
2438
2439	addScaledVector( v, s ) {
2440
2441		this.x += v.x * s;
2442		this.y += v.y * s;
2443		this.z += v.z * s;
2444		this.w += v.w * s;
2445
2446		return this;
2447
2448	}
2449
2450	sub( v ) {
2451
2452		this.x -= v.x;
2453		this.y -= v.y;
2454		this.z -= v.z;
2455		this.w -= v.w;
2456
2457		return this;
2458
2459	}
2460
2461	subScalar( s ) {
2462
2463		this.x -= s;
2464		this.y -= s;
2465		this.z -= s;
2466		this.w -= s;
2467
2468		return this;
2469
2470	}
2471
2472	subVectors( a, b ) {
2473
2474		this.x = a.x - b.x;
2475		this.y = a.y - b.y;
2476		this.z = a.z - b.z;
2477		this.w = a.w - b.w;
2478
2479		return this;
2480
2481	}
2482
2483	multiply( v ) {
2484
2485		this.x *= v.x;
2486		this.y *= v.y;
2487		this.z *= v.z;
2488		this.w *= v.w;
2489
2490		return this;
2491
2492	}
2493
2494	multiplyScalar( scalar ) {
2495
2496		this.x *= scalar;
2497		this.y *= scalar;
2498		this.z *= scalar;
2499		this.w *= scalar;
2500
2501		return this;
2502
2503	}
2504
vendor: 37,104 bytes, lines 2505-4475
2505	applyMatrix4( m ) {
2506
2507		const x = this.x, y = this.y, z = this.z, w = this.w;
2508		const e = m.elements;
2509
2510		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
2511		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
2512		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
2513		this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
2514
2515		return this;
2516
2517	}
2518
2519	divideScalar( scalar ) {
2520
2521		return this.multiplyScalar( 1 / scalar );
2522
2523	}
2524
2525	setAxisAngleFromQuaternion( q ) {
2526
2527		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
2528
2529		// q is assumed to be normalized
2530
2531		this.w = 2 * Math.acos( q.w );
2532
2533		const s = Math.sqrt( 1 - q.w * q.w );
2534
2535		if ( s < 0.0001 ) {
2536
2537			this.x = 1;
2538			this.y = 0;
2539			this.z = 0;
2540
2541		} else {
2542
2543			this.x = q.x / s;
2544			this.y = q.y / s;
2545			this.z = q.z / s;
2546
2547		}
2548
2549		return this;
2550
2551	}
2552
2553	setAxisAngleFromRotationMatrix( m ) {
2554
2555		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
2556
2557		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2558
2559		let angle, x, y, z; // variables for result
2560		const epsilon = 0.01,		// margin to allow for rounding errors
2561			epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees
2562
2563			te = m.elements,
2564
2565			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2566			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2567			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
2568
2569		if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
2570		     ( Math.abs( m13 - m31 ) < epsilon ) &&
2571		     ( Math.abs( m23 - m32 ) < epsilon ) ) {
2572
2573			// singularity found
2574			// first check for identity matrix which must have +1 for all terms
2575			// in leading diagonal and zero in other terms
2576
2577			if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
2578			     ( Math.abs( m13 + m31 ) < epsilon2 ) &&
2579			     ( Math.abs( m23 + m32 ) < epsilon2 ) &&
2580			     ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
2581
2582				// this singularity is identity matrix so angle = 0
2583
2584				this.set( 1, 0, 0, 0 );
2585
2586				return this; // zero angle, arbitrary axis
2587
2588			}
2589
2590			// otherwise this singularity is angle = 180
2591
2592			angle = Math.PI;
2593
2594			const xx = ( m11 + 1 ) / 2;
2595			const yy = ( m22 + 1 ) / 2;
2596			const zz = ( m33 + 1 ) / 2;
2597			const xy = ( m12 + m21 ) / 4;
2598			const xz = ( m13 + m31 ) / 4;
2599			const yz = ( m23 + m32 ) / 4;
2600
2601			if ( ( xx > yy ) && ( xx > zz ) ) {
2602
2603				// m11 is the largest diagonal term
2604
2605				if ( xx < epsilon ) {
2606
2607					x = 0;
2608					y = 0.707106781;
2609					z = 0.707106781;
2610
2611				} else {
2612
2613					x = Math.sqrt( xx );
2614					y = xy / x;
2615					z = xz / x;
2616
2617				}
2618
2619			} else if ( yy > zz ) {
2620
2621				// m22 is the largest diagonal term
2622
2623				if ( yy < epsilon ) {
2624
2625					x = 0.707106781;
2626					y = 0;
2627					z = 0.707106781;
2628
2629				} else {
2630
2631					y = Math.sqrt( yy );
2632					x = xy / y;
2633					z = yz / y;
2634
2635				}
2636
2637			} else {
2638
2639				// m33 is the largest diagonal term so base result on this
2640
2641				if ( zz < epsilon ) {
2642
2643					x = 0.707106781;
2644					y = 0.707106781;
2645					z = 0;
2646
2647				} else {
2648
2649					z = Math.sqrt( zz );
2650					x = xz / z;
2651					y = yz / z;
2652
2653				}
2654
2655			}
2656
2657			this.set( x, y, z, angle );
2658
2659			return this; // return 180 deg rotation
2660
2661		}
2662
2663		// as we have reached here there are no singularities so we can handle normally
2664
2665		let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
2666			( m13 - m31 ) * ( m13 - m31 ) +
2667			( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
2668
2669		if ( Math.abs( s ) < 0.001 ) s = 1;
2670
2671		// prevent divide by zero, should not happen if matrix is orthogonal and should be
2672		// caught by singularity test above, but I've left it in just in case
2673
2674		this.x = ( m32 - m23 ) / s;
2675		this.y = ( m13 - m31 ) / s;
2676		this.z = ( m21 - m12 ) / s;
2677		this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
2678
2679		return this;
2680
2681	}
2682
2683	min( v ) {
2684
2685		this.x = Math.min( this.x, v.x );
2686		this.y = Math.min( this.y, v.y );
2687		this.z = Math.min( this.z, v.z );
2688		this.w = Math.min( this.w, v.w );
2689
2690		return this;
2691
2692	}
2693
2694	max( v ) {
2695
2696		this.x = Math.max( this.x, v.x );
2697		this.y = Math.max( this.y, v.y );
2698		this.z = Math.max( this.z, v.z );
2699		this.w = Math.max( this.w, v.w );
2700
2701		return this;
2702
2703	}
2704
2705	clamp( min, max ) {
2706
2707		// assumes min < max, componentwise
2708
2709		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2710		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2711		this.z = Math.max( min.z, Math.min( max.z, this.z ) );
2712		this.w = Math.max( min.w, Math.min( max.w, this.w ) );
2713
2714		return this;
2715
2716	}
2717
2718	clampScalar( minVal, maxVal ) {
2719
2720		this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
2721		this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
2722		this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
2723		this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
2724
2725		return this;
2726
2727	}
2728
2729	clampLength( min, max ) {
2730
2731		const length = this.length();
2732
2733		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
2734
2735	}
2736
2737	floor() {
2738
2739		this.x = Math.floor( this.x );
2740		this.y = Math.floor( this.y );
2741		this.z = Math.floor( this.z );
2742		this.w = Math.floor( this.w );
2743
2744		return this;
2745
2746	}
2747
2748	ceil() {
2749
2750		this.x = Math.ceil( this.x );
2751		this.y = Math.ceil( this.y );
2752		this.z = Math.ceil( this.z );
2753		this.w = Math.ceil( this.w );
2754
2755		return this;
2756
2757	}
2758
2759	round() {
2760
2761		this.x = Math.round( this.x );
2762		this.y = Math.round( this.y );
2763		this.z = Math.round( this.z );
2764		this.w = Math.round( this.w );
2765
2766		return this;
2767
2768	}
2769
2770	roundToZero() {
2771
2772		this.x = Math.trunc( this.x );
2773		this.y = Math.trunc( this.y );
2774		this.z = Math.trunc( this.z );
2775		this.w = Math.trunc( this.w );
2776
2777		return this;
2778
2779	}
2780
2781	negate() {
2782
2783		this.x = - this.x;
2784		this.y = - this.y;
2785		this.z = - this.z;
2786		this.w = - this.w;
2787
2788		return this;
2789
2790	}
2791
2792	dot( v ) {
2793
2794		return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
2795
2796	}
2797
2798	lengthSq() {
2799
2800		return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
2801
2802	}
2803
2804	length() {
2805
2806		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
2807
2808	}
2809
2810	manhattanLength() {
2811
2812		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
2813
2814	}
2815
2816	normalize() {
2817
2818		return this.divideScalar( this.length() || 1 );
2819
2820	}
2821
2822	setLength( length ) {
2823
2824		return this.normalize().multiplyScalar( length );
2825
2826	}
2827
2828	lerp( v, alpha ) {
2829
2830		this.x += ( v.x - this.x ) * alpha;
2831		this.y += ( v.y - this.y ) * alpha;
2832		this.z += ( v.z - this.z ) * alpha;
2833		this.w += ( v.w - this.w ) * alpha;
2834
2835		return this;
2836
2837	}
2838
2839	lerpVectors( v1, v2, alpha ) {
2840
2841		this.x = v1.x + ( v2.x - v1.x ) * alpha;
2842		this.y = v1.y + ( v2.y - v1.y ) * alpha;
2843		this.z = v1.z + ( v2.z - v1.z ) * alpha;
2844		this.w = v1.w + ( v2.w - v1.w ) * alpha;
2845
2846		return this;
2847
2848	}
2849
2850	equals( v ) {
2851
2852		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
2853
2854	}
2855
2856	fromArray( array, offset = 0 ) {
2857
2858		this.x = array[ offset ];
2859		this.y = array[ offset + 1 ];
2860		this.z = array[ offset + 2 ];
2861		this.w = array[ offset + 3 ];
2862
2863		return this;
2864
2865	}
2866
2867	toArray( array = [], offset = 0 ) {
2868
2869		array[ offset ] = this.x;
2870		array[ offset + 1 ] = this.y;
2871		array[ offset + 2 ] = this.z;
2872		array[ offset + 3 ] = this.w;
2873
2874		return array;
2875
2876	}
2877
2878	fromBufferAttribute( attribute, index ) {
2879
2880		this.x = attribute.getX( index );
2881		this.y = attribute.getY( index );
2882		this.z = attribute.getZ( index );
2883		this.w = attribute.getW( index );
2884
2885		return this;
2886
2887	}
2888
2889	random() {
2890
2891		this.x = Math.random();
2892		this.y = Math.random();
2893		this.z = Math.random();
2894		this.w = Math.random();
2895
2896		return this;
2897
2898	}
2899
2900	*[ Symbol.iterator ]() {
2901
2902		yield this.x;
2903		yield this.y;
2904		yield this.z;
2905		yield this.w;
2906
2907	}
2908
2909}
2910
2911/*
2912 In options, we can specify:
2913 * Texture parameters for an auto-generated target texture
2914 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
2915*/
2916class RenderTarget extends EventDispatcher {
2917
2918	constructor( width = 1, height = 1, options = {} ) {
2919
2920		super();
2921
2922		this.isRenderTarget = true;
2923
2924		this.width = width;
2925		this.height = height;
2926		this.depth = 1;
2927
2928		this.scissor = new Vector4( 0, 0, width, height );
2929		this.scissorTest = false;
2930
2931		this.viewport = new Vector4( 0, 0, width, height );
2932
2933		const image = { width: width, height: height, depth: 1 };
2934
2935		if ( options.encoding !== undefined ) {
2936
2937			// @deprecated, r152
2938			warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' );
2939			options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
2940
2941		}
2942
2943		options = Object.assign( {
2944			generateMipmaps: false,
2945			internalFormat: null,
2946			minFilter: LinearFilter,
2947			depthBuffer: true,
2948			stencilBuffer: false,
2949			depthTexture: null,
2950			samples: 0
2951		}, options );
2952
2953		this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
2954		this.texture.isRenderTargetTexture = true;
2955
2956		this.texture.flipY = false;
2957		this.texture.generateMipmaps = options.generateMipmaps;
2958		this.texture.internalFormat = options.internalFormat;
2959
2960		this.depthBuffer = options.depthBuffer;
2961		this.stencilBuffer = options.stencilBuffer;
2962
2963		this.depthTexture = options.depthTexture;
2964
2965		this.samples = options.samples;
2966
2967	}
2968
2969	setSize( width, height, depth = 1 ) {
2970
2971		if ( this.width !== width || this.height !== height || this.depth !== depth ) {
2972
2973			this.width = width;
2974			this.height = height;
2975			this.depth = depth;
2976
2977			this.texture.image.width = width;
2978			this.texture.image.height = height;
2979			this.texture.image.depth = depth;
2980
2981			this.dispose();
2982
2983		}
2984
2985		this.viewport.set( 0, 0, width, height );
2986		this.scissor.set( 0, 0, width, height );
2987
2988	}
2989
2990	clone() {
2991
2992		return new this.constructor().copy( this );
2993
2994	}
2995
2996	copy( source ) {
2997
2998		this.width = source.width;
2999		this.height = source.height;
3000		this.depth = source.depth;
3001
3002		this.scissor.copy( source.scissor );
3003		this.scissorTest = source.scissorTest;
3004
3005		this.viewport.copy( source.viewport );
3006
3007		this.texture = source.texture.clone();
3008		this.texture.isRenderTargetTexture = true;
3009
3010		// ensure image object is not shared, see #20328
3011
3012		const image = Object.assign( {}, source.texture.image );
3013		this.texture.source = new Source( image );
3014
3015		this.depthBuffer = source.depthBuffer;
3016		this.stencilBuffer = source.stencilBuffer;
3017
3018		if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
3019
3020		this.samples = source.samples;
3021
3022		return this;
3023
3024	}
3025
3026	dispose() {
3027
3028		this.dispatchEvent( { type: 'dispose' } );
3029
3030	}
3031
3032}
3033
3034class WebGLRenderTarget extends RenderTarget {
3035
3036	constructor( width = 1, height = 1, options = {} ) {
3037
3038		super( width, height, options );
3039
3040		this.isWebGLRenderTarget = true;
3041
3042	}
3043
3044}
3045
3046class DataArrayTexture extends Texture {
3047
3048	constructor( data = null, width = 1, height = 1, depth = 1 ) {
3049
3050		super( null );
3051
3052		this.isDataArrayTexture = true;
3053
3054		this.image = { data, width, height, depth };
3055
3056		this.magFilter = NearestFilter;
3057		this.minFilter = NearestFilter;
3058
3059		this.wrapR = ClampToEdgeWrapping;
3060
3061		this.generateMipmaps = false;
3062		this.flipY = false;
3063		this.unpackAlignment = 1;
3064
3065	}
3066
3067}
3068
3069class WebGLArrayRenderTarget extends WebGLRenderTarget {
3070
3071	constructor( width = 1, height = 1, depth = 1, options = {} ) {
3072
3073		super( width, height, options );
3074
3075		this.isWebGLArrayRenderTarget = true;
3076
3077		this.depth = depth;
3078
3079		this.texture = new DataArrayTexture( null, width, height, depth );
3080
3081		this.texture.isRenderTargetTexture = true;
3082
3083	}
3084
3085}
3086
3087class Data3DTexture extends Texture {
3088
3089	constructor( data = null, width = 1, height = 1, depth = 1 ) {
3090
3091		// We're going to add .setXXX() methods for setting properties later.
3092		// Users can still set in DataTexture3D directly.
3093		//
3094		//	const texture = new THREE.DataTexture3D( data, width, height, depth );
3095		// 	texture.anisotropy = 16;
3096		//
3097		// See #14839
3098
3099		super( null );
3100
3101		this.isData3DTexture = true;
3102
3103		this.image = { data, width, height, depth };
3104
3105		this.magFilter = NearestFilter;
3106		this.minFilter = NearestFilter;
3107
3108		this.wrapR = ClampToEdgeWrapping;
3109
3110		this.generateMipmaps = false;
3111		this.flipY = false;
3112		this.unpackAlignment = 1;
3113
3114	}
3115
3116}
3117
3118class WebGL3DRenderTarget extends WebGLRenderTarget {
3119
3120	constructor( width = 1, height = 1, depth = 1, options = {} ) {
3121
3122		super( width, height, options );
3123
3124		this.isWebGL3DRenderTarget = true;
3125
3126		this.depth = depth;
3127
3128		this.texture = new Data3DTexture( null, width, height, depth );
3129
3130		this.texture.isRenderTargetTexture = true;
3131
3132	}
3133
3134}
3135
3136class WebGLMultipleRenderTargets extends WebGLRenderTarget {
3137
3138	constructor( width = 1, height = 1, count = 1, options = {} ) {
3139
3140		super( width, height, options );
3141
3142		this.isWebGLMultipleRenderTargets = true;
3143
3144		const texture = this.texture;
3145
3146		this.texture = [];
3147
3148		for ( let i = 0; i < count; i ++ ) {
3149
3150			this.texture[ i ] = texture.clone();
3151			this.texture[ i ].isRenderTargetTexture = true;
3152
3153		}
3154
3155	}
3156
3157	setSize( width, height, depth = 1 ) {
3158
3159		if ( this.width !== width || this.height !== height || this.depth !== depth ) {
3160
3161			this.width = width;
3162			this.height = height;
3163			this.depth = depth;
3164
3165			for ( let i = 0, il = this.texture.length; i < il; i ++ ) {
3166
3167				this.texture[ i ].image.width = width;
3168				this.texture[ i ].image.height = height;
3169				this.texture[ i ].image.depth = depth;
3170
3171			}
3172
3173			this.dispose();
3174
3175		}
3176
3177		this.viewport.set( 0, 0, width, height );
3178		this.scissor.set( 0, 0, width, height );
3179
3180	}
3181
3182	copy( source ) {
3183
3184		this.dispose();
3185
3186		this.width = source.width;
3187		this.height = source.height;
3188		this.depth = source.depth;
3189
3190		this.scissor.copy( source.scissor );
3191		this.scissorTest = source.scissorTest;
3192
3193		this.viewport.copy( source.viewport );
3194
3195		this.depthBuffer = source.depthBuffer;
3196		this.stencilBuffer = source.stencilBuffer;
3197
3198		if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
3199
3200		this.texture.length = 0;
3201
3202		for ( let i = 0, il = source.texture.length; i < il; i ++ ) {
3203
3204			this.texture[ i ] = source.texture[ i ].clone();
3205			this.texture[ i ].isRenderTargetTexture = true;
3206
3207		}
3208
3209		return this;
3210
3211	}
3212
3213}
3214
3215class Quaternion {
3216
3217	constructor( x = 0, y = 0, z = 0, w = 1 ) {
3218
3219		this.isQuaternion = true;
3220
3221		this._x = x;
3222		this._y = y;
3223		this._z = z;
3224		this._w = w;
3225
3226	}
3227
3228	static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
3229
3230		// fuzz-free, array-based Quaternion SLERP operation
3231
3232		let x0 = src0[ srcOffset0 + 0 ],
3233			y0 = src0[ srcOffset0 + 1 ],
3234			z0 = src0[ srcOffset0 + 2 ],
3235			w0 = src0[ srcOffset0 + 3 ];
3236
3237		const x1 = src1[ srcOffset1 + 0 ],
3238			y1 = src1[ srcOffset1 + 1 ],
3239			z1 = src1[ srcOffset1 + 2 ],
3240			w1 = src1[ srcOffset1 + 3 ];
3241
3242		if ( t === 0 ) {
3243
3244			dst[ dstOffset + 0 ] = x0;
3245			dst[ dstOffset + 1 ] = y0;
3246			dst[ dstOffset + 2 ] = z0;
3247			dst[ dstOffset + 3 ] = w0;
3248			return;
3249
3250		}
3251
3252		if ( t === 1 ) {
3253
3254			dst[ dstOffset + 0 ] = x1;
3255			dst[ dstOffset + 1 ] = y1;
3256			dst[ dstOffset + 2 ] = z1;
3257			dst[ dstOffset + 3 ] = w1;
3258			return;
3259
3260		}
3261
3262		if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
3263
3264			let s = 1 - t;
3265			const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
3266				dir = ( cos >= 0 ? 1 : - 1 ),
3267				sqrSin = 1 - cos * cos;
3268
3269			// Skip the Slerp for tiny steps to avoid numeric problems:
3270			if ( sqrSin > Number.EPSILON ) {
3271
3272				const sin = Math.sqrt( sqrSin ),
3273					len = Math.atan2( sin, cos * dir );
3274
3275				s = Math.sin( s * len ) / sin;
3276				t = Math.sin( t * len ) / sin;
3277
3278			}
3279
3280			const tDir = t * dir;
3281
3282			x0 = x0 * s + x1 * tDir;
3283			y0 = y0 * s + y1 * tDir;
3284			z0 = z0 * s + z1 * tDir;
3285			w0 = w0 * s + w1 * tDir;
3286
3287			// Normalize in case we just did a lerp:
3288			if ( s === 1 - t ) {
3289
3290				const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
3291
3292				x0 *= f;
3293				y0 *= f;
3294				z0 *= f;
3295				w0 *= f;
3296
3297			}
3298
3299		}
3300
3301		dst[ dstOffset ] = x0;
3302		dst[ dstOffset + 1 ] = y0;
3303		dst[ dstOffset + 2 ] = z0;
3304		dst[ dstOffset + 3 ] = w0;
3305
3306	}
3307
3308	static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
3309
3310		const x0 = src0[ srcOffset0 ];
3311		const y0 = src0[ srcOffset0 + 1 ];
3312		const z0 = src0[ srcOffset0 + 2 ];
3313		const w0 = src0[ srcOffset0 + 3 ];
3314
3315		const x1 = src1[ srcOffset1 ];
3316		const y1 = src1[ srcOffset1 + 1 ];
3317		const z1 = src1[ srcOffset1 + 2 ];
3318		const w1 = src1[ srcOffset1 + 3 ];
3319
3320		dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
3321		dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
3322		dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
3323		dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
3324
3325		return dst;
3326
3327	}
3328
3329	get x() {
3330
3331		return this._x;
3332
3333	}
3334
3335	set x( value ) {
3336
3337		this._x = value;
3338		this._onChangeCallback();
3339
3340	}
3341
3342	get y() {
3343
3344		return this._y;
3345
3346	}
3347
3348	set y( value ) {
3349
3350		this._y = value;
3351		this._onChangeCallback();
3352
3353	}
3354
3355	get z() {
3356
3357		return this._z;
3358
3359	}
3360
3361	set z( value ) {
3362
3363		this._z = value;
3364		this._onChangeCallback();
3365
3366	}
3367
3368	get w() {
3369
3370		return this._w;
3371
3372	}
3373
3374	set w( value ) {
3375
3376		this._w = value;
3377		this._onChangeCallback();
3378
3379	}
3380
3381	set( x, y, z, w ) {
3382
3383		this._x = x;
3384		this._y = y;
3385		this._z = z;
3386		this._w = w;
3387
3388		this._onChangeCallback();
3389
3390		return this;
3391
3392	}
3393
3394	clone() {
3395
3396		return new this.constructor( this._x, this._y, this._z, this._w );
3397
3398	}
3399
3400	copy( quaternion ) {
3401
3402		this._x = quaternion.x;
3403		this._y = quaternion.y;
3404		this._z = quaternion.z;
3405		this._w = quaternion.w;
3406
3407		this._onChangeCallback();
3408
3409		return this;
3410
3411	}
3412
3413	setFromEuler( euler, update = true ) {
3414
3415		const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
3416
3417		// http://www.mathworks.com/matlabcentral/fileexchange/
3418		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
3419		//	content/SpinCalc.m
3420
3421		const cos = Math.cos;
3422		const sin = Math.sin;
3423
3424		const c1 = cos( x / 2 );
3425		const c2 = cos( y / 2 );
3426		const c3 = cos( z / 2 );
3427
3428		const s1 = sin( x / 2 );
3429		const s2 = sin( y / 2 );
3430		const s3 = sin( z / 2 );
3431
3432		switch ( order ) {
3433
3434			case 'XYZ':
3435				this._x = s1 * c2 * c3 + c1 * s2 * s3;
3436				this._y = c1 * s2 * c3 - s1 * c2 * s3;
3437				this._z = c1 * c2 * s3 + s1 * s2 * c3;
3438				this._w = c1 * c2 * c3 - s1 * s2 * s3;
3439				break;
3440
3441			case 'YXZ':
3442				this._x = s1 * c2 * c3 + c1 * s2 * s3;
3443				this._y = c1 * s2 * c3 - s1 * c2 * s3;
3444				this._z = c1 * c2 * s3 - s1 * s2 * c3;
3445				this._w = c1 * c2 * c3 + s1 * s2 * s3;
3446				break;
3447
3448			case 'ZXY':
3449				this._x = s1 * c2 * c3 - c1 * s2 * s3;
3450				this._y = c1 * s2 * c3 + s1 * c2 * s3;
3451				this._z = c1 * c2 * s3 + s1 * s2 * c3;
3452				this._w = c1 * c2 * c3 - s1 * s2 * s3;
3453				break;
3454
3455			case 'ZYX':
3456				this._x = s1 * c2 * c3 - c1 * s2 * s3;
3457				this._y = c1 * s2 * c3 + s1 * c2 * s3;
3458				this._z = c1 * c2 * s3 - s1 * s2 * c3;
3459				this._w = c1 * c2 * c3 + s1 * s2 * s3;
3460				break;
3461
3462			case 'YZX':
3463				this._x = s1 * c2 * c3 + c1 * s2 * s3;
3464				this._y = c1 * s2 * c3 + s1 * c2 * s3;
3465				this._z = c1 * c2 * s3 - s1 * s2 * c3;
3466				this._w = c1 * c2 * c3 - s1 * s2 * s3;
3467				break;
3468
3469			case 'XZY':
3470				this._x = s1 * c2 * c3 - c1 * s2 * s3;
3471				this._y = c1 * s2 * c3 - s1 * c2 * s3;
3472				this._z = c1 * c2 * s3 + s1 * s2 * c3;
3473				this._w = c1 * c2 * c3 + s1 * s2 * s3;
3474				break;
3475
3476			default:
3477				console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
3478
3479		}
3480
3481		if ( update === true ) this._onChangeCallback();
3482
3483		return this;
3484
3485	}
3486
3487	setFromAxisAngle( axis, angle ) {
3488
3489		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
3490
3491		// assumes axis is normalized
3492
3493		const halfAngle = angle / 2, s = Math.sin( halfAngle );
3494
3495		this._x = axis.x * s;
3496		this._y = axis.y * s;
3497		this._z = axis.z * s;
3498		this._w = Math.cos( halfAngle );
3499
3500		this._onChangeCallback();
3501
3502		return this;
3503
3504	}
3505
3506	setFromRotationMatrix( m ) {
3507
3508		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
3509
3510		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
3511
3512		const te = m.elements,
3513
3514			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
3515			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
3516			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
3517
3518			trace = m11 + m22 + m33;
3519
3520		if ( trace > 0 ) {
3521
3522			const s = 0.5 / Math.sqrt( trace + 1.0 );
3523
3524			this._w = 0.25 / s;
3525			this._x = ( m32 - m23 ) * s;
3526			this._y = ( m13 - m31 ) * s;
3527			this._z = ( m21 - m12 ) * s;
3528
3529		} else if ( m11 > m22 && m11 > m33 ) {
3530
3531			const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
3532
3533			this._w = ( m32 - m23 ) / s;
3534			this._x = 0.25 * s;
3535			this._y = ( m12 + m21 ) / s;
3536			this._z = ( m13 + m31 ) / s;
3537
3538		} else if ( m22 > m33 ) {
3539
3540			const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
3541
3542			this._w = ( m13 - m31 ) / s;
3543			this._x = ( m12 + m21 ) / s;
3544			this._y = 0.25 * s;
3545			this._z = ( m23 + m32 ) / s;
3546
3547		} else {
3548
3549			const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
3550
3551			this._w = ( m21 - m12 ) / s;
3552			this._x = ( m13 + m31 ) / s;
3553			this._y = ( m23 + m32 ) / s;
3554			this._z = 0.25 * s;
3555
3556		}
3557
3558		this._onChangeCallback();
3559
3560		return this;
3561
3562	}
3563
3564	setFromUnitVectors( vFrom, vTo ) {
3565
3566		// assumes direction vectors vFrom and vTo are normalized
3567
3568		let r = vFrom.dot( vTo ) + 1;
3569
3570		if ( r < Number.EPSILON ) {
3571
3572			// vFrom and vTo point in opposite directions
3573
3574			r = 0;
3575
3576			if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
3577
3578				this._x = - vFrom.y;
3579				this._y = vFrom.x;
3580				this._z = 0;
3581				this._w = r;
3582
3583			} else {
3584
3585				this._x = 0;
3586				this._y = - vFrom.z;
3587				this._z = vFrom.y;
3588				this._w = r;
3589
3590			}
3591
3592		} else {
3593
3594			// crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
3595
3596			this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
3597			this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
3598			this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
3599			this._w = r;
3600
3601		}
3602
3603		return this.normalize();
3604
3605	}
3606
3607	angleTo( q ) {
3608
3609		return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) );
3610
3611	}
3612
3613	rotateTowards( q, step ) {
3614
3615		const angle = this.angleTo( q );
3616
3617		if ( angle === 0 ) return this;
3618
3619		const t = Math.min( 1, step / angle );
3620
3621		this.slerp( q, t );
3622
3623		return this;
3624
3625	}
3626
3627	identity() {
3628
3629		return this.set( 0, 0, 0, 1 );
3630
3631	}
3632
3633	invert() {
3634
3635		// quaternion is assumed to have unit length
3636
3637		return this.conjugate();
3638
3639	}
3640
3641	conjugate() {
3642
3643		this._x *= - 1;
3644		this._y *= - 1;
3645		this._z *= - 1;
3646
3647		this._onChangeCallback();
3648
3649		return this;
3650
3651	}
3652
3653	dot( v ) {
3654
3655		return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
3656
3657	}
3658
3659	lengthSq() {
3660
3661		return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
3662
3663	}
3664
3665	length() {
3666
3667		return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
3668
3669	}
3670
3671	normalize() {
3672
3673		let l = this.length();
3674
3675		if ( l === 0 ) {
3676
3677			this._x = 0;
3678			this._y = 0;
3679			this._z = 0;
3680			this._w = 1;
3681
3682		} else {
3683
3684			l = 1 / l;
3685
3686			this._x = this._x * l;
3687			this._y = this._y * l;
3688			this._z = this._z * l;
3689			this._w = this._w * l;
3690
3691		}
3692
3693		this._onChangeCallback();
3694
3695		return this;
3696
3697	}
3698
3699	multiply( q ) {
3700
3701		return this.multiplyQuaternions( this, q );
3702
3703	}
3704
3705	premultiply( q ) {
3706
3707		return this.multiplyQuaternions( q, this );
3708
3709	}
3710
3711	multiplyQuaternions( a, b ) {
3712
3713		// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
3714
3715		const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
3716		const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
3717
3718		this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
3719		this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
3720		this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
3721		this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
3722
3723		this._onChangeCallback();
3724
3725		return this;
3726
3727	}
3728
3729	slerp( qb, t ) {
3730
3731		if ( t === 0 ) return this;
3732		if ( t === 1 ) return this.copy( qb );
3733
3734		const x = this._x, y = this._y, z = this._z, w = this._w;
3735
3736		// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
3737
3738		let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
3739
3740		if ( cosHalfTheta < 0 ) {
3741
3742			this._w = - qb._w;
3743			this._x = - qb._x;
3744			this._y = - qb._y;
3745			this._z = - qb._z;
3746
3747			cosHalfTheta = - cosHalfTheta;
3748
3749		} else {
3750
3751			this.copy( qb );
3752
3753		}
3754
3755		if ( cosHalfTheta >= 1.0 ) {
3756
3757			this._w = w;
3758			this._x = x;
3759			this._y = y;
3760			this._z = z;
3761
3762			return this;
3763
3764		}
3765
3766		const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
3767
3768		if ( sqrSinHalfTheta <= Number.EPSILON ) {
3769
3770			const s = 1 - t;
3771			this._w = s * w + t * this._w;
3772			this._x = s * x + t * this._x;
3773			this._y = s * y + t * this._y;
3774			this._z = s * z + t * this._z;
3775
3776			this.normalize(); // normalize calls _onChangeCallback()
3777
3778			return this;
3779
3780		}
3781
3782		const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
3783		const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
3784		const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
3785			ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
3786
3787		this._w = ( w * ratioA + this._w * ratioB );
3788		this._x = ( x * ratioA + this._x * ratioB );
3789		this._y = ( y * ratioA + this._y * ratioB );
3790		this._z = ( z * ratioA + this._z * ratioB );
3791
3792		this._onChangeCallback();
3793
3794		return this;
3795
3796	}
3797
3798	slerpQuaternions( qa, qb, t ) {
3799
3800		return this.copy( qa ).slerp( qb, t );
3801
3802	}
3803
3804	random() {
3805
3806		// Derived from http://planning.cs.uiuc.edu/node198.html
3807		// Note, this source uses w, x, y, z ordering,
3808		// so we swap the order below.
3809
3810		const u1 = Math.random();
3811		const sqrt1u1 = Math.sqrt( 1 - u1 );
3812		const sqrtu1 = Math.sqrt( u1 );
3813
3814		const u2 = 2 * Math.PI * Math.random();
3815
3816		const u3 = 2 * Math.PI * Math.random();
3817
3818		return this.set(
3819			sqrt1u1 * Math.cos( u2 ),
3820			sqrtu1 * Math.sin( u3 ),
3821			sqrtu1 * Math.cos( u3 ),
3822			sqrt1u1 * Math.sin( u2 ),
3823		);
3824
3825	}
3826
3827	equals( quaternion ) {
3828
3829		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
3830
3831	}
3832
3833	fromArray( array, offset = 0 ) {
3834
3835		this._x = array[ offset ];
3836		this._y = array[ offset + 1 ];
3837		this._z = array[ offset + 2 ];
3838		this._w = array[ offset + 3 ];
3839
3840		this._onChangeCallback();
3841
3842		return this;
3843
3844	}
3845
3846	toArray( array = [], offset = 0 ) {
3847
3848		array[ offset ] = this._x;
3849		array[ offset + 1 ] = this._y;
3850		array[ offset + 2 ] = this._z;
3851		array[ offset + 3 ] = this._w;
3852
3853		return array;
3854
3855	}
3856
3857	fromBufferAttribute( attribute, index ) {
3858
3859		this._x = attribute.getX( index );
3860		this._y = attribute.getY( index );
3861		this._z = attribute.getZ( index );
3862		this._w = attribute.getW( index );
3863
3864		this._onChangeCallback();
3865
3866		return this;
3867
3868	}
3869
3870	toJSON() {
3871
3872		return this.toArray();
3873
3874	}
3875
3876	_onChange( callback ) {
3877
3878		this._onChangeCallback = callback;
3879
3880		return this;
3881
3882	}
3883
3884	_onChangeCallback() {}
3885
3886	*[ Symbol.iterator ]() {
3887
3888		yield this._x;
3889		yield this._y;
3890		yield this._z;
3891		yield this._w;
3892
3893	}
3894
3895}
3896
3897class Vector3 {
3898
3899	constructor( x = 0, y = 0, z = 0 ) {
3900
3901		Vector3.prototype.isVector3 = true;
3902
3903		this.x = x;
3904		this.y = y;
3905		this.z = z;
3906
3907	}
3908
3909	set( x, y, z ) {
3910
3911		if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
3912
3913		this.x = x;
3914		this.y = y;
3915		this.z = z;
3916
3917		return this;
3918
3919	}
3920
3921	setScalar( scalar ) {
3922
3923		this.x = scalar;
3924		this.y = scalar;
3925		this.z = scalar;
3926
3927		return this;
3928
3929	}
3930
3931	setX( x ) {
3932
3933		this.x = x;
3934
3935		return this;
3936
3937	}
3938
3939	setY( y ) {
3940
3941		this.y = y;
3942
3943		return this;
3944
3945	}
3946
3947	setZ( z ) {
3948
3949		this.z = z;
3950
3951		return this;
3952
3953	}
3954
3955	setComponent( index, value ) {
3956
3957		switch ( index ) {
3958
3959			case 0: this.x = value; break;
3960			case 1: this.y = value; break;
3961			case 2: this.z = value; break;
3962			default: throw new Error( 'index is out of range: ' + index );
3963
3964		}
3965
3966		return this;
3967
3968	}
3969
3970	getComponent( index ) {
3971
3972		switch ( index ) {
3973
3974			case 0: return this.x;
3975			case 1: return this.y;
3976			case 2: return this.z;
3977			default: throw new Error( 'index is out of range: ' + index );
3978
3979		}
3980
3981	}
3982
3983	clone() {
3984
3985		return new this.constructor( this.x, this.y, this.z );
3986
3987	}
3988
3989	copy( v ) {
3990
3991		this.x = v.x;
3992		this.y = v.y;
3993		this.z = v.z;
3994
3995		return this;
3996
3997	}
3998
3999	add( v ) {
4000
4001		this.x += v.x;
4002		this.y += v.y;
4003		this.z += v.z;
4004
4005		return this;
4006
4007	}
4008
4009	addScalar( s ) {
4010
4011		this.x += s;
4012		this.y += s;
4013		this.z += s;
4014
4015		return this;
4016
4017	}
4018
4019	addVectors( a, b ) {
4020
4021		this.x = a.x + b.x;
4022		this.y = a.y + b.y;
4023		this.z = a.z + b.z;
4024
4025		return this;
4026
4027	}
4028
4029	addScaledVector( v, s ) {
4030
4031		this.x += v.x * s;
4032		this.y += v.y * s;
4033		this.z += v.z * s;
4034
4035		return this;
4036
4037	}
4038
4039	sub( v ) {
4040
4041		this.x -= v.x;
4042		this.y -= v.y;
4043		this.z -= v.z;
4044
4045		return this;
4046
4047	}
4048
4049	subScalar( s ) {
4050
4051		this.x -= s;
4052		this.y -= s;
4053		this.z -= s;
4054
4055		return this;
4056
4057	}
4058
4059	subVectors( a, b ) {
4060
4061		this.x = a.x - b.x;
4062		this.y = a.y - b.y;
4063		this.z = a.z - b.z;
4064
4065		return this;
4066
4067	}
4068
4069	multiply( v ) {
4070
4071		this.x *= v.x;
4072		this.y *= v.y;
4073		this.z *= v.z;
4074
4075		return this;
4076
4077	}
4078
4079	multiplyScalar( scalar ) {
4080
4081		this.x *= scalar;
4082		this.y *= scalar;
4083		this.z *= scalar;
4084
4085		return this;
4086
4087	}
4088
4089	multiplyVectors( a, b ) {
4090
4091		this.x = a.x * b.x;
4092		this.y = a.y * b.y;
4093		this.z = a.z * b.z;
4094
4095		return this;
4096
4097	}
4098
4099	applyEuler( euler ) {
4100
4101		return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );
4102
4103	}
4104
4105	applyAxisAngle( axis, angle ) {
4106
4107		return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );
4108
4109	}
4110
4111	applyMatrix3( m ) {
4112
4113		const x = this.x, y = this.y, z = this.z;
4114		const e = m.elements;
4115
4116		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
4117		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
4118		this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
4119
4120		return this;
4121
4122	}
4123
4124	applyNormalMatrix( m ) {
4125
4126		return this.applyMatrix3( m ).normalize();
4127
4128	}
4129
4130	applyMatrix4( m ) {
4131
4132		const x = this.x, y = this.y, z = this.z;
4133		const e = m.elements;
4134
4135		const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
4136
4137		this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
4138		this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
4139		this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
4140
4141		return this;
4142
4143	}
4144
4145	applyQuaternion( q ) {
4146
4147		// quaternion q is assumed to have unit length
4148
4149		const vx = this.x, vy = this.y, vz = this.z;
4150		const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
4151
4152		// t = 2 * cross( q.xyz, v );
4153		const tx = 2 * ( qy * vz - qz * vy );
4154		const ty = 2 * ( qz * vx - qx * vz );
4155		const tz = 2 * ( qx * vy - qy * vx );
4156
4157		// v + q.w * t + cross( q.xyz, t );
4158		this.x = vx + qw * tx + qy * tz - qz * ty;
4159		this.y = vy + qw * ty + qz * tx - qx * tz;
4160		this.z = vz + qw * tz + qx * ty - qy * tx;
4161
4162		return this;
4163
4164	}
4165
4166	project( camera ) {
4167
4168		return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
4169
4170	}
4171
4172	unproject( camera ) {
4173
4174		return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
4175
4176	}
4177
4178	transformDirection( m ) {
4179
4180		// input: THREE.Matrix4 affine matrix
4181		// vector interpreted as a direction
4182
4183		const x = this.x, y = this.y, z = this.z;
4184		const e = m.elements;
4185
4186		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
4187		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
4188		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
4189
4190		return this.normalize();
4191
4192	}
4193
4194	divide( v ) {
4195
4196		this.x /= v.x;
4197		this.y /= v.y;
4198		this.z /= v.z;
4199
4200		return this;
4201
4202	}
4203
4204	divideScalar( scalar ) {
4205
4206		return this.multiplyScalar( 1 / scalar );
4207
4208	}
4209
4210	min( v ) {
4211
4212		this.x = Math.min( this.x, v.x );
4213		this.y = Math.min( this.y, v.y );
4214		this.z = Math.min( this.z, v.z );
4215
4216		return this;
4217
4218	}
4219
4220	max( v ) {
4221
4222		this.x = Math.max( this.x, v.x );
4223		this.y = Math.max( this.y, v.y );
4224		this.z = Math.max( this.z, v.z );
4225
4226		return this;
4227
4228	}
4229
4230	clamp( min, max ) {
4231
4232		// assumes min < max, componentwise
4233
4234		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
4235		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
4236		this.z = Math.max( min.z, Math.min( max.z, this.z ) );
4237
4238		return this;
4239
4240	}
4241
4242	clampScalar( minVal, maxVal ) {
4243
4244		this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
4245		this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
4246		this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
4247
4248		return this;
4249
4250	}
4251
4252	clampLength( min, max ) {
4253
4254		const length = this.length();
4255
4256		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
4257
4258	}
4259
4260	floor() {
4261
4262		this.x = Math.floor( this.x );
4263		this.y = Math.floor( this.y );
4264		this.z = Math.floor( this.z );
4265
4266		return this;
4267
4268	}
4269
4270	ceil() {
4271
4272		this.x = Math.ceil( this.x );
4273		this.y = Math.ceil( this.y );
4274		this.z = Math.ceil( this.z );
4275
4276		return this;
4277
4278	}
4279
4280	round() {
4281
4282		this.x = Math.round( this.x );
4283		this.y = Math.round( this.y );
4284		this.z = Math.round( this.z );
4285
4286		return this;
4287
4288	}
4289
4290	roundToZero() {
4291
4292		this.x = Math.trunc( this.x );
4293		this.y = Math.trunc( this.y );
4294		this.z = Math.trunc( this.z );
4295
4296		return this;
4297
4298	}
4299
4300	negate() {
4301
4302		this.x = - this.x;
4303		this.y = - this.y;
4304		this.z = - this.z;
4305
4306		return this;
4307
4308	}
4309
4310	dot( v ) {
4311
4312		return this.x * v.x + this.y * v.y + this.z * v.z;
4313
4314	}
4315
4316	// TODO lengthSquared?
4317
4318	lengthSq() {
4319
4320		return this.x * this.x + this.y * this.y + this.z * this.z;
4321
4322	}
4323
4324	length() {
4325
4326		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
4327
4328	}
4329
4330	manhattanLength() {
4331
4332		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
4333
4334	}
4335
4336	normalize() {
4337
4338		return this.divideScalar( this.length() || 1 );
4339
4340	}
4341
4342	setLength( length ) {
4343
4344		return this.normalize().multiplyScalar( length );
4345
4346	}
4347
4348	lerp( v, alpha ) {
4349
4350		this.x += ( v.x - this.x ) * alpha;
4351		this.y += ( v.y - this.y ) * alpha;
4352		this.z += ( v.z - this.z ) * alpha;
4353
4354		return this;
4355
4356	}
4357
4358	lerpVectors( v1, v2, alpha ) {
4359
4360		this.x = v1.x + ( v2.x - v1.x ) * alpha;
4361		this.y = v1.y + ( v2.y - v1.y ) * alpha;
4362		this.z = v1.z + ( v2.z - v1.z ) * alpha;
4363
4364		return this;
4365
4366	}
4367
4368	cross( v ) {
4369
4370		return this.crossVectors( this, v );
4371
4372	}
4373
4374	crossVectors( a, b ) {
4375
4376		const ax = a.x, ay = a.y, az = a.z;
4377		const bx = b.x, by = b.y, bz = b.z;
4378
4379		this.x = ay * bz - az * by;
4380		this.y = az * bx - ax * bz;
4381		this.z = ax * by - ay * bx;
4382
4383		return this;
4384
4385	}
4386
4387	projectOnVector( v ) {
4388
4389		const denominator = v.lengthSq();
4390
4391		if ( denominator === 0 ) return this.set( 0, 0, 0 );
4392
4393		const scalar = v.dot( this ) / denominator;
4394
4395		return this.copy( v ).multiplyScalar( scalar );
4396
4397	}
4398
4399	projectOnPlane( planeNormal ) {
4400
4401		_vector$c.copy( this ).projectOnVector( planeNormal );
4402
4403		return this.sub( _vector$c );
4404
4405	}
4406
4407	reflect( normal ) {
4408
4409		// reflect incident vector off plane orthogonal to normal
4410		// normal is assumed to have unit length
4411
4412		return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
4413
4414	}
4415
4416	angleTo( v ) {
4417
4418		const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
4419
4420		if ( denominator === 0 ) return Math.PI / 2;
4421
4422		const theta = this.dot( v ) / denominator;
4423
4424		// clamp, to handle numerical problems
4425
4426		return Math.acos( clamp( theta, - 1, 1 ) );
4427
4428	}
4429
4430	distanceTo( v ) {
4431
4432		return Math.sqrt( this.distanceToSquared( v ) );
4433
4434	}
4435
4436	distanceToSquared( v ) {
4437
4438		const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
4439
4440		return dx * dx + dy * dy + dz * dz;
4441
4442	}
4443
4444	manhattanDistanceTo( v ) {
4445
4446		return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
4447
4448	}
4449
4450	setFromSpherical( s ) {
4451
4452		return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
4453
4454	}
4455
4456	setFromSphericalCoords( radius, phi, theta ) {
4457
4458		const sinPhiRadius = Math.sin( phi ) * radius;
4459
4460		this.x = sinPhiRadius * Math.sin( theta );
4461		this.y = Math.cos( phi ) * radius;
4462		this.z = sinPhiRadius * Math.cos( theta );
4463
4464		return this;
4465
4466	}
4467
4468	setFromCylindrical( c ) {
4469
4470		return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
4471
4472	}
4473
4474	setFromCylindricalCoords( radius, theta, y ) {
4475
vendor: 4,724 bytes, lines 4476-4770
4476		this.x = radius * Math.sin( theta );
4477		this.y = y;
4478		this.z = radius * Math.cos( theta );
4479
4480		return this;
4481
4482	}
4483
4484	setFromMatrixPosition( m ) {
4485
4486		const e = m.elements;
4487
4488		this.x = e[ 12 ];
4489		this.y = e[ 13 ];
4490		this.z = e[ 14 ];
4491
4492		return this;
4493
4494	}
4495
4496	setFromMatrixScale( m ) {
4497
4498		const sx = this.setFromMatrixColumn( m, 0 ).length();
4499		const sy = this.setFromMatrixColumn( m, 1 ).length();
4500		const sz = this.setFromMatrixColumn( m, 2 ).length();
4501
4502		this.x = sx;
4503		this.y = sy;
4504		this.z = sz;
4505
4506		return this;
4507
4508	}
4509
4510	setFromMatrixColumn( m, index ) {
4511
4512		return this.fromArray( m.elements, index * 4 );
4513
4514	}
4515
4516	setFromMatrix3Column( m, index ) {
4517
4518		return this.fromArray( m.elements, index * 3 );
4519
4520	}
4521
4522	setFromEuler( e ) {
4523
4524		this.x = e._x;
4525		this.y = e._y;
4526		this.z = e._z;
4527
4528		return this;
4529
4530	}
4531
4532	setFromColor( c ) {
4533
4534		this.x = c.r;
4535		this.y = c.g;
4536		this.z = c.b;
4537
4538		return this;
4539
4540	}
4541
4542	equals( v ) {
4543
4544		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
4545
4546	}
4547
4548	fromArray( array, offset = 0 ) {
4549
4550		this.x = array[ offset ];
4551		this.y = array[ offset + 1 ];
4552		this.z = array[ offset + 2 ];
4553
4554		return this;
4555
4556	}
4557
4558	toArray( array = [], offset = 0 ) {
4559
4560		array[ offset ] = this.x;
4561		array[ offset + 1 ] = this.y;
4562		array[ offset + 2 ] = this.z;
4563
4564		return array;
4565
4566	}
4567
4568	fromBufferAttribute( attribute, index ) {
4569
4570		this.x = attribute.getX( index );
4571		this.y = attribute.getY( index );
4572		this.z = attribute.getZ( index );
4573
4574		return this;
4575
4576	}
4577
4578	random() {
4579
4580		this.x = Math.random();
4581		this.y = Math.random();
4582		this.z = Math.random();
4583
4584		return this;
4585
4586	}
4587
4588	randomDirection() {
4589
4590		// Derived from https://mathworld.wolfram.com/SpherePointPicking.html
4591
4592		const u = ( Math.random() - 0.5 ) * 2;
4593		const t = Math.random() * Math.PI * 2;
4594		const f = Math.sqrt( 1 - u ** 2 );
4595
4596		this.x = f * Math.cos( t );
4597		this.y = f * Math.sin( t );
4598		this.z = u;
4599
4600		return this;
4601
4602	}
4603
4604	*[ Symbol.iterator ]() {
4605
4606		yield this.x;
4607		yield this.y;
4608		yield this.z;
4609
4610	}
4611
4612}
4613
4614const _vector$c = /*@__PURE__*/ new Vector3();
4615const _quaternion$4 = /*@__PURE__*/ new Quaternion();
4616
4617class Box3 {
4618
4619	constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {
4620
4621		this.isBox3 = true;
4622
4623		this.min = min;
4624		this.max = max;
4625
4626	}
4627
4628	set( min, max ) {
4629
4630		this.min.copy( min );
4631		this.max.copy( max );
4632
4633		return this;
4634
4635	}
4636
4637	setFromArray( array ) {
4638
4639		this.makeEmpty();
4640
4641		for ( let i = 0, il = array.length; i < il; i += 3 ) {
4642
4643			this.expandByPoint( _vector$b.fromArray( array, i ) );
4644
4645		}
4646
4647		return this;
4648
4649	}
4650
4651	setFromBufferAttribute( attribute ) {
4652
4653		this.makeEmpty();
4654
4655		for ( let i = 0, il = attribute.count; i < il; i ++ ) {
4656
4657			this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) );
4658
4659		}
4660
4661		return this;
4662
4663	}
4664
4665	setFromPoints( points ) {
4666
4667		this.makeEmpty();
4668
4669		for ( let i = 0, il = points.length; i < il; i ++ ) {
4670
4671			this.expandByPoint( points[ i ] );
4672
4673		}
4674
4675		return this;
4676
4677	}
4678
4679	setFromCenterAndSize( center, size ) {
4680
4681		const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );
4682
4683		this.min.copy( center ).sub( halfSize );
4684		this.max.copy( center ).add( halfSize );
4685
4686		return this;
4687
4688	}
4689
4690	setFromObject( object, precise = false ) {
4691
4692		this.makeEmpty();
4693
4694		return this.expandByObject( object, precise );
4695
4696	}
4697
4698	clone() {
4699
4700		return new this.constructor().copy( this );
4701
4702	}
4703
4704	copy( box ) {
4705
4706		this.min.copy( box.min );
4707		this.max.copy( box.max );
4708
4709		return this;
4710
4711	}
4712
4713	makeEmpty() {
4714
4715		this.min.x = this.min.y = this.min.z = + Infinity;
4716		this.max.x = this.max.y = this.max.z = - Infinity;
4717
4718		return this;
4719
4720	}
4721
4722	isEmpty() {
4723
4724		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
4725
4726		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
4727
4728	}
4729
4730	getCenter( target ) {
4731
4732		return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
4733
4734	}
4735
4736	getSize( target ) {
4737
4738		return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
4739
4740	}
4741
4742	expandByPoint( point ) {
4743
4744		this.min.min( point );
4745		this.max.max( point );
4746
4747		return this;
4748
4749	}
4750
4751	expandByVector( vector ) {
4752
4753		this.min.sub( vector );
4754		this.max.add( vector );
4755
4756		return this;
4757
4758	}
4759
4760	expandByScalar( scalar ) {
4761
4762		this.min.addScalar( - scalar );
4763		this.max.addScalar( scalar );
4764
4765		return this;
4766
4767	}
4768
4769	expandByObject( object, precise = false ) {
4770
vendor: 9,756 bytes, lines 4771-5158
4771		// Computes the world-axis-aligned bounding box of an object (including its children),
4772		// accounting for both the object's, and children's, world transforms
4773
4774		object.updateWorldMatrix( false, false );
4775
4776		const geometry = object.geometry;
4777
4778		if ( geometry !== undefined ) {
4779
4780			const positionAttribute = geometry.getAttribute( 'position' );
4781
4782			// precise AABB computation based on vertex data requires at least a position attribute.
4783			// instancing isn't supported so far and uses the normal (conservative) code path.
4784
4785			if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {
4786
4787				for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
4788
4789					if ( object.isMesh === true ) {
4790
4791						object.getVertexPosition( i, _vector$b );
4792
4793					} else {
4794
4795						_vector$b.fromBufferAttribute( positionAttribute, i );
4796
4797					}
4798
4799					_vector$b.applyMatrix4( object.matrixWorld );
4800					this.expandByPoint( _vector$b );
4801
4802				}
4803
4804			} else {
4805
4806				if ( object.boundingBox !== undefined ) {
4807
4808					// object-level bounding box
4809
4810					if ( object.boundingBox === null ) {
4811
4812						object.computeBoundingBox();
4813
4814					}
4815
4816					_box$4.copy( object.boundingBox );
4817
4818
4819				} else {
4820
4821					// geometry-level bounding box
4822
4823					if ( geometry.boundingBox === null ) {
4824
4825						geometry.computeBoundingBox();
4826
4827					}
4828
4829					_box$4.copy( geometry.boundingBox );
4830
4831				}
4832
4833				_box$4.applyMatrix4( object.matrixWorld );
4834
4835				this.union( _box$4 );
4836
4837			}
4838
4839		}
4840
4841		const children = object.children;
4842
4843		for ( let i = 0, l = children.length; i < l; i ++ ) {
4844
4845			this.expandByObject( children[ i ], precise );
4846
4847		}
4848
4849		return this;
4850
4851	}
4852
4853	containsPoint( point ) {
4854
4855		return point.x < this.min.x || point.x > this.max.x ||
4856			point.y < this.min.y || point.y > this.max.y ||
4857			point.z < this.min.z || point.z > this.max.z ? false : true;
4858
4859	}
4860
4861	containsBox( box ) {
4862
4863		return this.min.x <= box.min.x && box.max.x <= this.max.x &&
4864			this.min.y <= box.min.y && box.max.y <= this.max.y &&
4865			this.min.z <= box.min.z && box.max.z <= this.max.z;
4866
4867	}
4868
4869	getParameter( point, target ) {
4870
4871		// This can potentially have a divide by zero if the box
4872		// has a size dimension of 0.
4873
4874		return target.set(
4875			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
4876			( point.y - this.min.y ) / ( this.max.y - this.min.y ),
4877			( point.z - this.min.z ) / ( this.max.z - this.min.z )
4878		);
4879
4880	}
4881
4882	intersectsBox( box ) {
4883
4884		// using 6 splitting planes to rule out intersections.
4885		return box.max.x < this.min.x || box.min.x > this.max.x ||
4886			box.max.y < this.min.y || box.min.y > this.max.y ||
4887			box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
4888
4889	}
4890
4891	intersectsSphere( sphere ) {
4892
4893		// Find the point on the AABB closest to the sphere center.
4894		this.clampPoint( sphere.center, _vector$b );
4895
4896		// If that point is inside the sphere, the AABB and sphere intersect.
4897		return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
4898
4899	}
4900
4901	intersectsPlane( plane ) {
4902
4903		// We compute the minimum and maximum dot product values. If those values
4904		// are on the same side (back or front) of the plane, then there is no intersection.
4905
4906		let min, max;
4907
4908		if ( plane.normal.x > 0 ) {
4909
4910			min = plane.normal.x * this.min.x;
4911			max = plane.normal.x * this.max.x;
4912
4913		} else {
4914
4915			min = plane.normal.x * this.max.x;
4916			max = plane.normal.x * this.min.x;
4917
4918		}
4919
4920		if ( plane.normal.y > 0 ) {
4921
4922			min += plane.normal.y * this.min.y;
4923			max += plane.normal.y * this.max.y;
4924
4925		} else {
4926
4927			min += plane.normal.y * this.max.y;
4928			max += plane.normal.y * this.min.y;
4929
4930		}
4931
4932		if ( plane.normal.z > 0 ) {
4933
4934			min += plane.normal.z * this.min.z;
4935			max += plane.normal.z * this.max.z;
4936
4937		} else {
4938
4939			min += plane.normal.z * this.max.z;
4940			max += plane.normal.z * this.min.z;
4941
4942		}
4943
4944		return ( min <= - plane.constant && max >= - plane.constant );
4945
4946	}
4947
4948	intersectsTriangle( triangle ) {
4949
4950		if ( this.isEmpty() ) {
4951
4952			return false;
4953
4954		}
4955
4956		// compute box center and extents
4957		this.getCenter( _center );
4958		_extents.subVectors( this.max, _center );
4959
4960		// translate triangle to aabb origin
4961		_v0$2.subVectors( triangle.a, _center );
4962		_v1$7.subVectors( triangle.b, _center );
4963		_v2$4.subVectors( triangle.c, _center );
4964
4965		// compute edge vectors for triangle
4966		_f0.subVectors( _v1$7, _v0$2 );
4967		_f1.subVectors( _v2$4, _v1$7 );
4968		_f2.subVectors( _v0$2, _v2$4 );
4969
4970		// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
4971		// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
4972		// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
4973		let axes = [
4974			0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
4975			_f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
4976			- _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
4977		];
4978		if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
4979
4980			return false;
4981
4982		}
4983
4984		// test 3 face normals from the aabb
4985		axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
4986		if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
4987
4988			return false;
4989
4990		}
4991
4992		// finally testing the face normal of the triangle
4993		// use already existing triangle edge vectors here
4994		_triangleNormal.crossVectors( _f0, _f1 );
4995		axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
4996
4997		return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents );
4998
4999	}
5000
5001	clampPoint( point, target ) {
5002
5003		return target.copy( point ).clamp( this.min, this.max );
5004
5005	}
5006
5007	distanceToPoint( point ) {
5008
5009		return this.clampPoint( point, _vector$b ).distanceTo( point );
5010
5011	}
5012
5013	getBoundingSphere( target ) {
5014
5015		if ( this.isEmpty() ) {
5016
5017			target.makeEmpty();
5018
5019		} else {
5020
5021			this.getCenter( target.center );
5022
5023			target.radius = this.getSize( _vector$b ).length() * 0.5;
5024
5025		}
5026
5027		return target;
5028
5029	}
5030
5031	intersect( box ) {
5032
5033		this.min.max( box.min );
5034		this.max.min( box.max );
5035
5036		// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
5037		if ( this.isEmpty() ) this.makeEmpty();
5038
5039		return this;
5040
5041	}
5042
5043	union( box ) {
5044
5045		this.min.min( box.min );
5046		this.max.max( box.max );
5047
5048		return this;
5049
5050	}
5051
5052	applyMatrix4( matrix ) {
5053
5054		// transform of empty box is an empty box.
5055		if ( this.isEmpty() ) return this;
5056
5057		// NOTE: I am using a binary pattern to specify all 2^3 combinations below
5058		_points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
5059		_points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
5060		_points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
5061		_points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
5062		_points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
5063		_points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
5064		_points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
5065		_points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
5066
5067		this.setFromPoints( _points );
5068
5069		return this;
5070
5071	}
5072
5073	translate( offset ) {
5074
5075		this.min.add( offset );
5076		this.max.add( offset );
5077
5078		return this;
5079
5080	}
5081
5082	equals( box ) {
5083
5084		return box.min.equals( this.min ) && box.max.equals( this.max );
5085
5086	}
5087
5088}
5089
5090const _points = [
5091	/*@__PURE__*/ new Vector3(),
5092	/*@__PURE__*/ new Vector3(),
5093	/*@__PURE__*/ new Vector3(),
5094	/*@__PURE__*/ new Vector3(),
5095	/*@__PURE__*/ new Vector3(),
5096	/*@__PURE__*/ new Vector3(),
5097	/*@__PURE__*/ new Vector3(),
5098	/*@__PURE__*/ new Vector3()
5099];
5100
5101const _vector$b = /*@__PURE__*/ new Vector3();
5102
5103const _box$4 = /*@__PURE__*/ new Box3();
5104
5105// triangle centered vertices
5106
5107const _v0$2 = /*@__PURE__*/ new Vector3();
5108const _v1$7 = /*@__PURE__*/ new Vector3();
5109const _v2$4 = /*@__PURE__*/ new Vector3();
5110
5111// triangle edge vectors
5112
5113const _f0 = /*@__PURE__*/ new Vector3();
5114const _f1 = /*@__PURE__*/ new Vector3();
5115const _f2 = /*@__PURE__*/ new Vector3();
5116
5117const _center = /*@__PURE__*/ new Vector3();
5118const _extents = /*@__PURE__*/ new Vector3();
5119const _triangleNormal = /*@__PURE__*/ new Vector3();
5120const _testAxis = /*@__PURE__*/ new Vector3();
5121
5122function satForAxes( axes, v0, v1, v2, extents ) {
5123
5124	for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
5125
5126		_testAxis.fromArray( axes, i );
5127		// project the aabb onto the separating axis
5128		const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
5129		// project all 3 vertices of the triangle onto the separating axis
5130		const p0 = v0.dot( _testAxis );
5131		const p1 = v1.dot( _testAxis );
5132		const p2 = v2.dot( _testAxis );
5133		// actual test, basically see if either of the most extreme of the triangle points intersects r
5134		if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
5135
5136			// points of the projected triangle are outside the projected half-length of the aabb
5137			// the axis is separating and we can exit
5138			return false;
5139
5140		}
5141
5142	}
5143
5144	return true;
5145
5146}
5147
5148const _box$3 = /*@__PURE__*/ new Box3();
5149const _v1$6 = /*@__PURE__*/ new Vector3();
5150const _v2$3 = /*@__PURE__*/ new Vector3();
5151
5152class Sphere {
5153
5154	constructor( center = new Vector3(), radius = - 1 ) {
5155
5156		this.isSphere = true;
5157
5158		this.center = center;
vendor: 4,718 bytes, lines 5159-5450
5159		this.radius = radius;
5160
5161	}
5162
5163	set( center, radius ) {
5164
5165		this.center.copy( center );
5166		this.radius = radius;
5167
5168		return this;
5169
5170	}
5171
5172	setFromPoints( points, optionalCenter ) {
5173
5174		const center = this.center;
5175
5176		if ( optionalCenter !== undefined ) {
5177
5178			center.copy( optionalCenter );
5179
5180		} else {
5181
5182			_box$3.setFromPoints( points ).getCenter( center );
5183
5184		}
5185
5186		let maxRadiusSq = 0;
5187
5188		for ( let i = 0, il = points.length; i < il; i ++ ) {
5189
5190			maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
5191
5192		}
5193
5194		this.radius = Math.sqrt( maxRadiusSq );
5195
5196		return this;
5197
5198	}
5199
5200	copy( sphere ) {
5201
5202		this.center.copy( sphere.center );
5203		this.radius = sphere.radius;
5204
5205		return this;
5206
5207	}
5208
5209	isEmpty() {
5210
5211		return ( this.radius < 0 );
5212
5213	}
5214
5215	makeEmpty() {
5216
5217		this.center.set( 0, 0, 0 );
5218		this.radius = - 1;
5219
5220		return this;
5221
5222	}
5223
5224	containsPoint( point ) {
5225
5226		return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
5227
5228	}
5229
5230	distanceToPoint( point ) {
5231
5232		return ( point.distanceTo( this.center ) - this.radius );
5233
5234	}
5235
5236	intersectsSphere( sphere ) {
5237
5238		const radiusSum = this.radius + sphere.radius;
5239
5240		return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
5241
5242	}
5243
5244	intersectsBox( box ) {
5245
5246		return box.intersectsSphere( this );
5247
5248	}
5249
5250	intersectsPlane( plane ) {
5251
5252		return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
5253
5254	}
5255
5256	clampPoint( point, target ) {
5257
5258		const deltaLengthSq = this.center.distanceToSquared( point );
5259
5260		target.copy( point );
5261
5262		if ( deltaLengthSq > ( this.radius * this.radius ) ) {
5263
5264			target.sub( this.center ).normalize();
5265			target.multiplyScalar( this.radius ).add( this.center );
5266
5267		}
5268
5269		return target;
5270
5271	}
5272
5273	getBoundingBox( target ) {
5274
5275		if ( this.isEmpty() ) {
5276
5277			// Empty sphere produces empty bounding box
5278			target.makeEmpty();
5279			return target;
5280
5281		}
5282
5283		target.set( this.center, this.center );
5284		target.expandByScalar( this.radius );
5285
5286		return target;
5287
5288	}
5289
5290	applyMatrix4( matrix ) {
5291
5292		this.center.applyMatrix4( matrix );
5293		this.radius = this.radius * matrix.getMaxScaleOnAxis();
5294
5295		return this;
5296
5297	}
5298
5299	translate( offset ) {
5300
5301		this.center.add( offset );
5302
5303		return this;
5304
5305	}
5306
5307	expandByPoint( point ) {
5308
5309		if ( this.isEmpty() ) {
5310
5311			this.center.copy( point );
5312
5313			this.radius = 0;
5314
5315			return this;
5316
5317		}
5318
5319		_v1$6.subVectors( point, this.center );
5320
5321		const lengthSq = _v1$6.lengthSq();
5322
5323		if ( lengthSq > ( this.radius * this.radius ) ) {
5324
5325			// calculate the minimal sphere
5326
5327			const length = Math.sqrt( lengthSq );
5328
5329			const delta = ( length - this.radius ) * 0.5;
5330
5331			this.center.addScaledVector( _v1$6, delta / length );
5332
5333			this.radius += delta;
5334
5335		}
5336
5337		return this;
5338
5339	}
5340
5341	union( sphere ) {
5342
5343		if ( sphere.isEmpty() ) {
5344
5345			return this;
5346
5347		}
5348
5349		if ( this.isEmpty() ) {
5350
5351			this.copy( sphere );
5352
5353			return this;
5354
5355		}
5356
5357		if ( this.center.equals( sphere.center ) === true ) {
5358
5359			 this.radius = Math.max( this.radius, sphere.radius );
5360
5361		} else {
5362
5363			_v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius );
5364
5365			this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) );
5366
5367			this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) );
5368
5369		}
5370
5371		return this;
5372
5373	}
5374
5375	equals( sphere ) {
5376
5377		return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
5378
5379	}
5380
5381	clone() {
5382
5383		return new this.constructor().copy( this );
5384
5385	}
5386
5387}
5388
5389const _vector$a = /*@__PURE__*/ new Vector3();
5390const _segCenter = /*@__PURE__*/ new Vector3();
5391const _segDir = /*@__PURE__*/ new Vector3();
5392const _diff = /*@__PURE__*/ new Vector3();
5393
5394const _edge1 = /*@__PURE__*/ new Vector3();
5395const _edge2 = /*@__PURE__*/ new Vector3();
5396const _normal$1 = /*@__PURE__*/ new Vector3();
5397
5398class Ray {
5399
5400	constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {
5401
5402		this.origin = origin;
5403		this.direction = direction;
5404
5405	}
5406
5407	set( origin, direction ) {
5408
5409		this.origin.copy( origin );
5410		this.direction.copy( direction );
5411
5412		return this;
5413
5414	}
5415
5416	copy( ray ) {
5417
5418		this.origin.copy( ray.origin );
5419		this.direction.copy( ray.direction );
5420
5421		return this;
5422
5423	}
5424
5425	at( t, target ) {
5426
5427		return target.copy( this.origin ).addScaledVector( this.direction, t );
5428
5429	}
5430
5431	lookAt( v ) {
5432
5433		this.direction.copy( v ).sub( this.origin ).normalize();
5434
5435		return this;
5436
5437	}
5438
5439	recast( t ) {
5440
5441		this.origin.copy( this.at( t, _vector$a ) );
5442
5443		return this;
5444
5445	}
5446
5447	closestPointToPoint( point, target ) {
5448
5449		target.subVectors( point, this.origin );
5450
vendor: 8,776 bytes, lines 5451-5841
5451		const directionDistance = target.dot( this.direction );
5452
5453		if ( directionDistance < 0 ) {
5454
5455			return target.copy( this.origin );
5456
5457		}
5458
5459		return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );
5460
5461	}
5462
5463	distanceToPoint( point ) {
5464
5465		return Math.sqrt( this.distanceSqToPoint( point ) );
5466
5467	}
5468
5469	distanceSqToPoint( point ) {
5470
5471		const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );
5472
5473		// point behind the ray
5474
5475		if ( directionDistance < 0 ) {
5476
5477			return this.origin.distanceToSquared( point );
5478
5479		}
5480
5481		_vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance );
5482
5483		return _vector$a.distanceToSquared( point );
5484
5485	}
5486
5487	distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
5488
5489		// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
5490		// It returns the min distance between the ray and the segment
5491		// defined by v0 and v1
5492		// It can also set two optional targets :
5493		// - The closest point on the ray
5494		// - The closest point on the segment
5495
5496		_segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
5497		_segDir.copy( v1 ).sub( v0 ).normalize();
5498		_diff.copy( this.origin ).sub( _segCenter );
5499
5500		const segExtent = v0.distanceTo( v1 ) * 0.5;
5501		const a01 = - this.direction.dot( _segDir );
5502		const b0 = _diff.dot( this.direction );
5503		const b1 = - _diff.dot( _segDir );
5504		const c = _diff.lengthSq();
5505		const det = Math.abs( 1 - a01 * a01 );
5506		let s0, s1, sqrDist, extDet;
5507
5508		if ( det > 0 ) {
5509
5510			// The ray and segment are not parallel.
5511
5512			s0 = a01 * b1 - b0;
5513			s1 = a01 * b0 - b1;
5514			extDet = segExtent * det;
5515
5516			if ( s0 >= 0 ) {
5517
5518				if ( s1 >= - extDet ) {
5519
5520					if ( s1 <= extDet ) {
5521
5522						// region 0
5523						// Minimum at interior points of ray and segment.
5524
5525						const invDet = 1 / det;
5526						s0 *= invDet;
5527						s1 *= invDet;
5528						sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
5529
5530					} else {
5531
5532						// region 1
5533
5534						s1 = segExtent;
5535						s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5536						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5537
5538					}
5539
5540				} else {
5541
5542					// region 5
5543
5544					s1 = - segExtent;
5545					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5546					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5547
5548				}
5549
5550			} else {
5551
5552				if ( s1 <= - extDet ) {
5553
5554					// region 4
5555
5556					s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
5557					s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
5558					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5559
5560				} else if ( s1 <= extDet ) {
5561
5562					// region 3
5563
5564					s0 = 0;
5565					s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
5566					sqrDist = s1 * ( s1 + 2 * b1 ) + c;
5567
5568				} else {
5569
5570					// region 2
5571
5572					s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
5573					s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
5574					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5575
5576				}
5577
5578			}
5579
5580		} else {
5581
5582			// Ray and segment are parallel.
5583
5584			s1 = ( a01 > 0 ) ? - segExtent : segExtent;
5585			s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5586			sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5587
5588		}
5589
5590		if ( optionalPointOnRay ) {
5591
5592			optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );
5593
5594		}
5595
5596		if ( optionalPointOnSegment ) {
5597
5598			optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );
5599
5600		}
5601
5602		return sqrDist;
5603
5604	}
5605
5606	intersectSphere( sphere, target ) {
5607
5608		_vector$a.subVectors( sphere.center, this.origin );
5609		const tca = _vector$a.dot( this.direction );
5610		const d2 = _vector$a.dot( _vector$a ) - tca * tca;
5611		const radius2 = sphere.radius * sphere.radius;
5612
5613		if ( d2 > radius2 ) return null;
5614
5615		const thc = Math.sqrt( radius2 - d2 );
5616
5617		// t0 = first intersect point - entrance on front of sphere
5618		const t0 = tca - thc;
5619
5620		// t1 = second intersect point - exit point on back of sphere
5621		const t1 = tca + thc;
5622
5623		// test to see if t1 is behind the ray - if so, return null
5624		if ( t1 < 0 ) return null;
5625
5626		// test to see if t0 is behind the ray:
5627		// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
5628		// in order to always return an intersect point that is in front of the ray.
5629		if ( t0 < 0 ) return this.at( t1, target );
5630
5631		// else t0 is in front of the ray, so return the first collision point scaled by t0
5632		return this.at( t0, target );
5633
5634	}
5635
5636	intersectsSphere( sphere ) {
5637
5638		return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
5639
5640	}
5641
5642	distanceToPlane( plane ) {
5643
5644		const denominator = plane.normal.dot( this.direction );
5645
5646		if ( denominator === 0 ) {
5647
5648			// line is coplanar, return origin
5649			if ( plane.distanceToPoint( this.origin ) === 0 ) {
5650
5651				return 0;
5652
5653			}
5654
5655			// Null is preferable to undefined since undefined means.... it is undefined
5656
5657			return null;
5658
5659		}
5660
5661		const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
5662
5663		// Return if the ray never intersects the plane
5664
5665		return t >= 0 ? t : null;
5666
5667	}
5668
5669	intersectPlane( plane, target ) {
5670
5671		const t = this.distanceToPlane( plane );
5672
5673		if ( t === null ) {
5674
5675			return null;
5676
5677		}
5678
5679		return this.at( t, target );
5680
5681	}
5682
5683	intersectsPlane( plane ) {
5684
5685		// check if the ray lies on the plane first
5686
5687		const distToPoint = plane.distanceToPoint( this.origin );
5688
5689		if ( distToPoint === 0 ) {
5690
5691			return true;
5692
5693		}
5694
5695		const denominator = plane.normal.dot( this.direction );
5696
5697		if ( denominator * distToPoint < 0 ) {
5698
5699			return true;
5700
5701		}
5702
5703		// ray origin is behind the plane (and is pointing behind it)
5704
5705		return false;
5706
5707	}
5708
5709	intersectBox( box, target ) {
5710
5711		let tmin, tmax, tymin, tymax, tzmin, tzmax;
5712
5713		const invdirx = 1 / this.direction.x,
5714			invdiry = 1 / this.direction.y,
5715			invdirz = 1 / this.direction.z;
5716
5717		const origin = this.origin;
5718
5719		if ( invdirx >= 0 ) {
5720
5721			tmin = ( box.min.x - origin.x ) * invdirx;
5722			tmax = ( box.max.x - origin.x ) * invdirx;
5723
5724		} else {
5725
5726			tmin = ( box.max.x - origin.x ) * invdirx;
5727			tmax = ( box.min.x - origin.x ) * invdirx;
5728
5729		}
5730
5731		if ( invdiry >= 0 ) {
5732
5733			tymin = ( box.min.y - origin.y ) * invdiry;
5734			tymax = ( box.max.y - origin.y ) * invdiry;
5735
5736		} else {
5737
5738			tymin = ( box.max.y - origin.y ) * invdiry;
5739			tymax = ( box.min.y - origin.y ) * invdiry;
5740
5741		}
5742
5743		if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
5744
5745		if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;
5746
5747		if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;
5748
5749		if ( invdirz >= 0 ) {
5750
5751			tzmin = ( box.min.z - origin.z ) * invdirz;
5752			tzmax = ( box.max.z - origin.z ) * invdirz;
5753
5754		} else {
5755
5756			tzmin = ( box.max.z - origin.z ) * invdirz;
5757			tzmax = ( box.min.z - origin.z ) * invdirz;
5758
5759		}
5760
5761		if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
5762
5763		if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
5764
5765		if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
5766
5767		//return point closest to the ray (positive side)
5768
5769		if ( tmax < 0 ) return null;
5770
5771		return this.at( tmin >= 0 ? tmin : tmax, target );
5772
5773	}
5774
5775	intersectsBox( box ) {
5776
5777		return this.intersectBox( box, _vector$a ) !== null;
5778
5779	}
5780
5781	intersectTriangle( a, b, c, backfaceCulling, target ) {
5782
5783		// Compute the offset origin, edges, and normal.
5784
5785		// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
5786
5787		_edge1.subVectors( b, a );
5788		_edge2.subVectors( c, a );
5789		_normal$1.crossVectors( _edge1, _edge2 );
5790
5791		// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
5792		// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
5793		//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
5794		//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
5795		//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
5796		let DdN = this.direction.dot( _normal$1 );
5797		let sign;
5798
5799		if ( DdN > 0 ) {
5800
5801			if ( backfaceCulling ) return null;
5802			sign = 1;
5803
5804		} else if ( DdN < 0 ) {
5805
5806			sign = - 1;
5807			DdN = - DdN;
5808
5809		} else {
5810
5811			return null;
5812
5813		}
5814
5815		_diff.subVectors( this.origin, a );
5816		const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
5817
5818		// b1 < 0, no intersection
5819		if ( DdQxE2 < 0 ) {
5820
5821			return null;
5822
5823		}
5824
5825		const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
5826
5827		// b2 < 0, no intersection
5828		if ( DdE1xQ < 0 ) {
5829
5830			return null;
5831
5832		}
5833
5834		// b1+b2 > 1, no intersection
5835		if ( DdQxE2 + DdE1xQ > DdN ) {
5836
5837			return null;
5838
5839		}
5840
5841		// Line intersects triangle, check if ray does.
vendor: 5,044 bytes, lines 5842-6107
5842		const QdN = - sign * _diff.dot( _normal$1 );
5843
5844		// t < 0, no intersection
5845		if ( QdN < 0 ) {
5846
5847			return null;
5848
5849		}
5850
5851		// Ray intersects triangle.
5852		return this.at( QdN / DdN, target );
5853
5854	}
5855
5856	applyMatrix4( matrix4 ) {
5857
5858		this.origin.applyMatrix4( matrix4 );
5859		this.direction.transformDirection( matrix4 );
5860
5861		return this;
5862
5863	}
5864
5865	equals( ray ) {
5866
5867		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
5868
5869	}
5870
5871	clone() {
5872
5873		return new this.constructor().copy( this );
5874
5875	}
5876
5877}
5878
5879class Matrix4 {
5880
5881	constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5882
5883		Matrix4.prototype.isMatrix4 = true;
5884
5885		this.elements = [
5886
5887			1, 0, 0, 0,
5888			0, 1, 0, 0,
5889			0, 0, 1, 0,
5890			0, 0, 0, 1
5891
5892		];
5893
5894		if ( n11 !== undefined ) {
5895
5896			this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );
5897
5898		}
5899
5900	}
5901
5902	set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5903
5904		const te = this.elements;
5905
5906		te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
5907		te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
5908		te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
5909		te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
5910
5911		return this;
5912
5913	}
5914
5915	identity() {
5916
5917		this.set(
5918
5919			1, 0, 0, 0,
5920			0, 1, 0, 0,
5921			0, 0, 1, 0,
5922			0, 0, 0, 1
5923
5924		);
5925
5926		return this;
5927
5928	}
5929
5930	clone() {
5931
5932		return new Matrix4().fromArray( this.elements );
5933
5934	}
5935
5936	copy( m ) {
5937
5938		const te = this.elements;
5939		const me = m.elements;
5940
5941		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
5942		te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
5943		te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
5944		te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
5945
5946		return this;
5947
5948	}
5949
5950	copyPosition( m ) {
5951
5952		const te = this.elements, me = m.elements;
5953
5954		te[ 12 ] = me[ 12 ];
5955		te[ 13 ] = me[ 13 ];
5956		te[ 14 ] = me[ 14 ];
5957
5958		return this;
5959
5960	}
5961
5962	setFromMatrix3( m ) {
5963
5964		const me = m.elements;
5965
5966		this.set(
5967
5968			me[ 0 ], me[ 3 ], me[ 6 ], 0,
5969			me[ 1 ], me[ 4 ], me[ 7 ], 0,
5970			me[ 2 ], me[ 5 ], me[ 8 ], 0,
5971			0, 0, 0, 1
5972
5973		);
5974
5975		return this;
5976
5977	}
5978
5979	extractBasis( xAxis, yAxis, zAxis ) {
5980
5981		xAxis.setFromMatrixColumn( this, 0 );
5982		yAxis.setFromMatrixColumn( this, 1 );
5983		zAxis.setFromMatrixColumn( this, 2 );
5984
5985		return this;
5986
5987	}
5988
5989	makeBasis( xAxis, yAxis, zAxis ) {
5990
5991		this.set(
5992			xAxis.x, yAxis.x, zAxis.x, 0,
5993			xAxis.y, yAxis.y, zAxis.y, 0,
5994			xAxis.z, yAxis.z, zAxis.z, 0,
5995			0, 0, 0, 1
5996		);
5997
5998		return this;
5999
6000	}
6001
6002	extractRotation( m ) {
6003
6004		// this method does not support reflection matrices
6005
6006		const te = this.elements;
6007		const me = m.elements;
6008
6009		const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();
6010		const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();
6011		const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();
6012
6013		te[ 0 ] = me[ 0 ] * scaleX;
6014		te[ 1 ] = me[ 1 ] * scaleX;
6015		te[ 2 ] = me[ 2 ] * scaleX;
6016		te[ 3 ] = 0;
6017
6018		te[ 4 ] = me[ 4 ] * scaleY;
6019		te[ 5 ] = me[ 5 ] * scaleY;
6020		te[ 6 ] = me[ 6 ] * scaleY;
6021		te[ 7 ] = 0;
6022
6023		te[ 8 ] = me[ 8 ] * scaleZ;
6024		te[ 9 ] = me[ 9 ] * scaleZ;
6025		te[ 10 ] = me[ 10 ] * scaleZ;
6026		te[ 11 ] = 0;
6027
6028		te[ 12 ] = 0;
6029		te[ 13 ] = 0;
6030		te[ 14 ] = 0;
6031		te[ 15 ] = 1;
6032
6033		return this;
6034
6035	}
6036
6037	makeRotationFromEuler( euler ) {
6038
6039		const te = this.elements;
6040
6041		const x = euler.x, y = euler.y, z = euler.z;
6042		const a = Math.cos( x ), b = Math.sin( x );
6043		const c = Math.cos( y ), d = Math.sin( y );
6044		const e = Math.cos( z ), f = Math.sin( z );
6045
6046		if ( euler.order === 'XYZ' ) {
6047
6048			const ae = a * e, af = a * f, be = b * e, bf = b * f;
6049
6050			te[ 0 ] = c * e;
6051			te[ 4 ] = - c * f;
6052			te[ 8 ] = d;
6053
6054			te[ 1 ] = af + be * d;
6055			te[ 5 ] = ae - bf * d;
6056			te[ 9 ] = - b * c;
6057
6058			te[ 2 ] = bf - ae * d;
6059			te[ 6 ] = be + af * d;
6060			te[ 10 ] = a * c;
6061
6062		} else if ( euler.order === 'YXZ' ) {
6063
6064			const ce = c * e, cf = c * f, de = d * e, df = d * f;
6065
6066			te[ 0 ] = ce + df * b;
6067			te[ 4 ] = de * b - cf;
6068			te[ 8 ] = a * d;
6069
6070			te[ 1 ] = a * f;
6071			te[ 5 ] = a * e;
6072			te[ 9 ] = - b;
6073
6074			te[ 2 ] = cf * b - de;
6075			te[ 6 ] = df + ce * b;
6076			te[ 10 ] = a * c;
6077
6078		} else if ( euler.order === 'ZXY' ) {
6079
6080			const ce = c * e, cf = c * f, de = d * e, df = d * f;
6081
6082			te[ 0 ] = ce - df * b;
6083			te[ 4 ] = - a * f;
6084			te[ 8 ] = de + cf * b;
6085
6086			te[ 1 ] = cf + de * b;
6087			te[ 5 ] = a * e;
6088			te[ 9 ] = df - ce * b;
6089
6090			te[ 2 ] = - a * d;
6091			te[ 6 ] = b;
6092			te[ 10 ] = a * c;
6093
6094		} else if ( euler.order === 'ZYX' ) {
6095
6096			const ae = a * e, af = a * f, be = b * e, bf = b * f;
6097
6098			te[ 0 ] = c * e;
6099			te[ 4 ] = be * d - af;
6100			te[ 8 ] = ae * d + bf;
6101
6102			te[ 1 ] = c * f;
6103			te[ 5 ] = bf * d + ae;
6104			te[ 9 ] = af * d - be;
6105
6106			te[ 2 ] = - d;
6107			te[ 6 ] = b * c;
vendor: 42,655 bytes, lines 6108-8206
6108			te[ 10 ] = a * c;
6109
6110		} else if ( euler.order === 'YZX' ) {
6111
6112			const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
6113
6114			te[ 0 ] = c * e;
6115			te[ 4 ] = bd - ac * f;
6116			te[ 8 ] = bc * f + ad;
6117
6118			te[ 1 ] = f;
6119			te[ 5 ] = a * e;
6120			te[ 9 ] = - b * e;
6121
6122			te[ 2 ] = - d * e;
6123			te[ 6 ] = ad * f + bc;
6124			te[ 10 ] = ac - bd * f;
6125
6126		} else if ( euler.order === 'XZY' ) {
6127
6128			const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
6129
6130			te[ 0 ] = c * e;
6131			te[ 4 ] = - f;
6132			te[ 8 ] = d * e;
6133
6134			te[ 1 ] = ac * f + bd;
6135			te[ 5 ] = a * e;
6136			te[ 9 ] = ad * f - bc;
6137
6138			te[ 2 ] = bc * f - ad;
6139			te[ 6 ] = b * e;
6140			te[ 10 ] = bd * f + ac;
6141
6142		}
6143
6144		// bottom row
6145		te[ 3 ] = 0;
6146		te[ 7 ] = 0;
6147		te[ 11 ] = 0;
6148
6149		// last column
6150		te[ 12 ] = 0;
6151		te[ 13 ] = 0;
6152		te[ 14 ] = 0;
6153		te[ 15 ] = 1;
6154
6155		return this;
6156
6157	}
6158
6159	makeRotationFromQuaternion( q ) {
6160
6161		return this.compose( _zero, q, _one );
6162
6163	}
6164
6165	lookAt( eye, target, up ) {
6166
6167		const te = this.elements;
6168
6169		_z.subVectors( eye, target );
6170
6171		if ( _z.lengthSq() === 0 ) {
6172
6173			// eye and target are in the same position
6174
6175			_z.z = 1;
6176
6177		}
6178
6179		_z.normalize();
6180		_x.crossVectors( up, _z );
6181
6182		if ( _x.lengthSq() === 0 ) {
6183
6184			// up and z are parallel
6185
6186			if ( Math.abs( up.z ) === 1 ) {
6187
6188				_z.x += 0.0001;
6189
6190			} else {
6191
6192				_z.z += 0.0001;
6193
6194			}
6195
6196			_z.normalize();
6197			_x.crossVectors( up, _z );
6198
6199		}
6200
6201		_x.normalize();
6202		_y.crossVectors( _z, _x );
6203
6204		te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
6205		te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
6206		te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
6207
6208		return this;
6209
6210	}
6211
6212	multiply( m ) {
6213
6214		return this.multiplyMatrices( this, m );
6215
6216	}
6217
6218	premultiply( m ) {
6219
6220		return this.multiplyMatrices( m, this );
6221
6222	}
6223
6224	multiplyMatrices( a, b ) {
6225
6226		const ae = a.elements;
6227		const be = b.elements;
6228		const te = this.elements;
6229
6230		const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
6231		const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
6232		const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
6233		const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
6234
6235		const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
6236		const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
6237		const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
6238		const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
6239
6240		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
6241		te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
6242		te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
6243		te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
6244
6245		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
6246		te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
6247		te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
6248		te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
6249
6250		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
6251		te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
6252		te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
6253		te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
6254
6255		te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
6256		te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
6257		te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
6258		te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
6259
6260		return this;
6261
6262	}
6263
6264	multiplyScalar( s ) {
6265
6266		const te = this.elements;
6267
6268		te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
6269		te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
6270		te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
6271		te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
6272
6273		return this;
6274
6275	}
6276
6277	determinant() {
6278
6279		const te = this.elements;
6280
6281		const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
6282		const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
6283		const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
6284		const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
6285
6286		//TODO: make this more efficient
6287		//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
6288
6289		return (
6290			n41 * (
6291				+ n14 * n23 * n32
6292				 - n13 * n24 * n32
6293				 - n14 * n22 * n33
6294				 + n12 * n24 * n33
6295				 + n13 * n22 * n34
6296				 - n12 * n23 * n34
6297			) +
6298			n42 * (
6299				+ n11 * n23 * n34
6300				 - n11 * n24 * n33
6301				 + n14 * n21 * n33
6302				 - n13 * n21 * n34
6303				 + n13 * n24 * n31
6304				 - n14 * n23 * n31
6305			) +
6306			n43 * (
6307				+ n11 * n24 * n32
6308				 - n11 * n22 * n34
6309				 - n14 * n21 * n32
6310				 + n12 * n21 * n34
6311				 + n14 * n22 * n31
6312				 - n12 * n24 * n31
6313			) +
6314			n44 * (
6315				- n13 * n22 * n31
6316				 - n11 * n23 * n32
6317				 + n11 * n22 * n33
6318				 + n13 * n21 * n32
6319				 - n12 * n21 * n33
6320				 + n12 * n23 * n31
6321			)
6322
6323		);
6324
6325	}
6326
6327	transpose() {
6328
6329		const te = this.elements;
6330		let tmp;
6331
6332		tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
6333		tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
6334		tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
6335
6336		tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
6337		tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
6338		tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
6339
6340		return this;
6341
6342	}
6343
6344	setPosition( x, y, z ) {
6345
6346		const te = this.elements;
6347
6348		if ( x.isVector3 ) {
6349
6350			te[ 12 ] = x.x;
6351			te[ 13 ] = x.y;
6352			te[ 14 ] = x.z;
6353
6354		} else {
6355
6356			te[ 12 ] = x;
6357			te[ 13 ] = y;
6358			te[ 14 ] = z;
6359
6360		}
6361
6362		return this;
6363
6364	}
6365
6366	invert() {
6367
6368		// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
6369		const te = this.elements,
6370
6371			n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
6372			n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
6373			n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
6374			n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
6375
6376			t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
6377			t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
6378			t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
6379			t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
6380
6381		const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
6382
6383		if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
6384
6385		const detInv = 1 / det;
6386
6387		te[ 0 ] = t11 * detInv;
6388		te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
6389		te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
6390		te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
6391
6392		te[ 4 ] = t12 * detInv;
6393		te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
6394		te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
6395		te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
6396
6397		te[ 8 ] = t13 * detInv;
6398		te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
6399		te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
6400		te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
6401
6402		te[ 12 ] = t14 * detInv;
6403		te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
6404		te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
6405		te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
6406
6407		return this;
6408
6409	}
6410
6411	scale( v ) {
6412
6413		const te = this.elements;
6414		const x = v.x, y = v.y, z = v.z;
6415
6416		te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
6417		te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
6418		te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
6419		te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
6420
6421		return this;
6422
6423	}
6424
6425	getMaxScaleOnAxis() {
6426
6427		const te = this.elements;
6428
6429
6430		const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
6431		const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
6432		const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
6433
6434		return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
6435
6436	}
6437
6438	makeTranslation( x, y, z ) {
6439
6440		if ( x.isVector3 ) {
6441
6442			this.set(
6443
6444				1, 0, 0, x.x,
6445				0, 1, 0, x.y,
6446				0, 0, 1, x.z,
6447				0, 0, 0, 1
6448
6449			);
6450
6451		} else {
6452
6453			this.set(
6454
6455				1, 0, 0, x,
6456				0, 1, 0, y,
6457				0, 0, 1, z,
6458				0, 0, 0, 1
6459
6460			);
6461
6462		}
6463
6464		return this;
6465
6466	}
6467
6468	makeRotationX( theta ) {
6469
6470		const c = Math.cos( theta ), s = Math.sin( theta );
6471
6472		this.set(
6473
6474			1, 0, 0, 0,
6475			0, c, - s, 0,
6476			0, s, c, 0,
6477			0, 0, 0, 1
6478
6479		);
6480
6481		return this;
6482
6483	}
6484
6485	makeRotationY( theta ) {
6486
6487		const c = Math.cos( theta ), s = Math.sin( theta );
6488
6489		this.set(
6490
6491			 c, 0, s, 0,
6492			 0, 1, 0, 0,
6493			- s, 0, c, 0,
6494			 0, 0, 0, 1
6495
6496		);
6497
6498		return this;
6499
6500	}
6501
6502	makeRotationZ( theta ) {
6503
6504		const c = Math.cos( theta ), s = Math.sin( theta );
6505
6506		this.set(
6507
6508			c, - s, 0, 0,
6509			s, c, 0, 0,
6510			0, 0, 1, 0,
6511			0, 0, 0, 1
6512
6513		);
6514
6515		return this;
6516
6517	}
6518
6519	makeRotationAxis( axis, angle ) {
6520
6521		// Based on http://www.gamedev.net/reference/articles/article1199.asp
6522
6523		const c = Math.cos( angle );
6524		const s = Math.sin( angle );
6525		const t = 1 - c;
6526		const x = axis.x, y = axis.y, z = axis.z;
6527		const tx = t * x, ty = t * y;
6528
6529		this.set(
6530
6531			tx * x + c, tx * y - s * z, tx * z + s * y, 0,
6532			tx * y + s * z, ty * y + c, ty * z - s * x, 0,
6533			tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
6534			0, 0, 0, 1
6535
6536		);
6537
6538		return this;
6539
6540	}
6541
6542	makeScale( x, y, z ) {
6543
6544		this.set(
6545
6546			x, 0, 0, 0,
6547			0, y, 0, 0,
6548			0, 0, z, 0,
6549			0, 0, 0, 1
6550
6551		);
6552
6553		return this;
6554
6555	}
6556
6557	makeShear( xy, xz, yx, yz, zx, zy ) {
6558
6559		this.set(
6560
6561			1, yx, zx, 0,
6562			xy, 1, zy, 0,
6563			xz, yz, 1, 0,
6564			0, 0, 0, 1
6565
6566		);
6567
6568		return this;
6569
6570	}
6571
6572	compose( position, quaternion, scale ) {
6573
6574		const te = this.elements;
6575
6576		const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
6577		const x2 = x + x,	y2 = y + y, z2 = z + z;
6578		const xx = x * x2, xy = x * y2, xz = x * z2;
6579		const yy = y * y2, yz = y * z2, zz = z * z2;
6580		const wx = w * x2, wy = w * y2, wz = w * z2;
6581
6582		const sx = scale.x, sy = scale.y, sz = scale.z;
6583
6584		te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
6585		te[ 1 ] = ( xy + wz ) * sx;
6586		te[ 2 ] = ( xz - wy ) * sx;
6587		te[ 3 ] = 0;
6588
6589		te[ 4 ] = ( xy - wz ) * sy;
6590		te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
6591		te[ 6 ] = ( yz + wx ) * sy;
6592		te[ 7 ] = 0;
6593
6594		te[ 8 ] = ( xz + wy ) * sz;
6595		te[ 9 ] = ( yz - wx ) * sz;
6596		te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
6597		te[ 11 ] = 0;
6598
6599		te[ 12 ] = position.x;
6600		te[ 13 ] = position.y;
6601		te[ 14 ] = position.z;
6602		te[ 15 ] = 1;
6603
6604		return this;
6605
6606	}
6607
6608	decompose( position, quaternion, scale ) {
6609
6610		const te = this.elements;
6611
6612		let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
6613		const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
6614		const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
6615
6616		// if determine is negative, we need to invert one scale
6617		const det = this.determinant();
6618		if ( det < 0 ) sx = - sx;
6619
6620		position.x = te[ 12 ];
6621		position.y = te[ 13 ];
6622		position.z = te[ 14 ];
6623
6624		// scale the rotation part
6625		_m1$2.copy( this );
6626
6627		const invSX = 1 / sx;
6628		const invSY = 1 / sy;
6629		const invSZ = 1 / sz;
6630
6631		_m1$2.elements[ 0 ] *= invSX;
6632		_m1$2.elements[ 1 ] *= invSX;
6633		_m1$2.elements[ 2 ] *= invSX;
6634
6635		_m1$2.elements[ 4 ] *= invSY;
6636		_m1$2.elements[ 5 ] *= invSY;
6637		_m1$2.elements[ 6 ] *= invSY;
6638
6639		_m1$2.elements[ 8 ] *= invSZ;
6640		_m1$2.elements[ 9 ] *= invSZ;
6641		_m1$2.elements[ 10 ] *= invSZ;
6642
6643		quaternion.setFromRotationMatrix( _m1$2 );
6644
6645		scale.x = sx;
6646		scale.y = sy;
6647		scale.z = sz;
6648
6649		return this;
6650
6651	}
6652
6653	makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
6654
6655		const te = this.elements;
6656		const x = 2 * near / ( right - left );
6657		const y = 2 * near / ( top - bottom );
6658
6659		const a = ( right + left ) / ( right - left );
6660		const b = ( top + bottom ) / ( top - bottom );
6661
6662		let c, d;
6663
6664		if ( coordinateSystem === WebGLCoordinateSystem ) {
6665
6666			c = - ( far + near ) / ( far - near );
6667			d = ( - 2 * far * near ) / ( far - near );
6668
6669		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6670
6671			c = - far / ( far - near );
6672			d = ( - far * near ) / ( far - near );
6673
6674		} else {
6675
6676			throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );
6677
6678		}
6679
6680		te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a; 	te[ 12 ] = 0;
6681		te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b; 	te[ 13 ] = 0;
6682		te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c; 	te[ 14 ] = d;
6683		te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = - 1;	te[ 15 ] = 0;
6684
6685		return this;
6686
6687	}
6688
6689	makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
6690
6691		const te = this.elements;
6692		const w = 1.0 / ( right - left );
6693		const h = 1.0 / ( top - bottom );
6694		const p = 1.0 / ( far - near );
6695
6696		const x = ( right + left ) * w;
6697		const y = ( top + bottom ) * h;
6698
6699		let z, zInv;
6700
6701		if ( coordinateSystem === WebGLCoordinateSystem ) {
6702
6703			z = ( far + near ) * p;
6704			zInv = - 2 * p;
6705
6706		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6707
6708			z = near * p;
6709			zInv = - 1 * p;
6710
6711		} else {
6712
6713			throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );
6714
6715		}
6716
6717		te[ 0 ] = 2 * w;	te[ 4 ] = 0;		te[ 8 ] = 0; 		te[ 12 ] = - x;
6718		te[ 1 ] = 0; 		te[ 5 ] = 2 * h;	te[ 9 ] = 0; 		te[ 13 ] = - y;
6719		te[ 2 ] = 0; 		te[ 6 ] = 0;		te[ 10 ] = zInv;	te[ 14 ] = - z;
6720		te[ 3 ] = 0; 		te[ 7 ] = 0;		te[ 11 ] = 0;		te[ 15 ] = 1;
6721
6722		return this;
6723
6724	}
6725
6726	equals( matrix ) {
6727
6728		const te = this.elements;
6729		const me = matrix.elements;
6730
6731		for ( let i = 0; i < 16; i ++ ) {
6732
6733			if ( te[ i ] !== me[ i ] ) return false;
6734
6735		}
6736
6737		return true;
6738
6739	}
6740
6741	fromArray( array, offset = 0 ) {
6742
6743		for ( let i = 0; i < 16; i ++ ) {
6744
6745			this.elements[ i ] = array[ i + offset ];
6746
6747		}
6748
6749		return this;
6750
6751	}
6752
6753	toArray( array = [], offset = 0 ) {
6754
6755		const te = this.elements;
6756
6757		array[ offset ] = te[ 0 ];
6758		array[ offset + 1 ] = te[ 1 ];
6759		array[ offset + 2 ] = te[ 2 ];
6760		array[ offset + 3 ] = te[ 3 ];
6761
6762		array[ offset + 4 ] = te[ 4 ];
6763		array[ offset + 5 ] = te[ 5 ];
6764		array[ offset + 6 ] = te[ 6 ];
6765		array[ offset + 7 ] = te[ 7 ];
6766
6767		array[ offset + 8 ] = te[ 8 ];
6768		array[ offset + 9 ] = te[ 9 ];
6769		array[ offset + 10 ] = te[ 10 ];
6770		array[ offset + 11 ] = te[ 11 ];
6771
6772		array[ offset + 12 ] = te[ 12 ];
6773		array[ offset + 13 ] = te[ 13 ];
6774		array[ offset + 14 ] = te[ 14 ];
6775		array[ offset + 15 ] = te[ 15 ];
6776
6777		return array;
6778
6779	}
6780
6781}
6782
6783const _v1$5 = /*@__PURE__*/ new Vector3();
6784const _m1$2 = /*@__PURE__*/ new Matrix4();
6785const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
6786const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
6787const _x = /*@__PURE__*/ new Vector3();
6788const _y = /*@__PURE__*/ new Vector3();
6789const _z = /*@__PURE__*/ new Vector3();
6790
6791const _matrix$1 = /*@__PURE__*/ new Matrix4();
6792const _quaternion$3 = /*@__PURE__*/ new Quaternion();
6793
6794class Euler {
6795
6796	constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {
6797
6798		this.isEuler = true;
6799
6800		this._x = x;
6801		this._y = y;
6802		this._z = z;
6803		this._order = order;
6804
6805	}
6806
6807	get x() {
6808
6809		return this._x;
6810
6811	}
6812
6813	set x( value ) {
6814
6815		this._x = value;
6816		this._onChangeCallback();
6817
6818	}
6819
6820	get y() {
6821
6822		return this._y;
6823
6824	}
6825
6826	set y( value ) {
6827
6828		this._y = value;
6829		this._onChangeCallback();
6830
6831	}
6832
6833	get z() {
6834
6835		return this._z;
6836
6837	}
6838
6839	set z( value ) {
6840
6841		this._z = value;
6842		this._onChangeCallback();
6843
6844	}
6845
6846	get order() {
6847
6848		return this._order;
6849
6850	}
6851
6852	set order( value ) {
6853
6854		this._order = value;
6855		this._onChangeCallback();
6856
6857	}
6858
6859	set( x, y, z, order = this._order ) {
6860
6861		this._x = x;
6862		this._y = y;
6863		this._z = z;
6864		this._order = order;
6865
6866		this._onChangeCallback();
6867
6868		return this;
6869
6870	}
6871
6872	clone() {
6873
6874		return new this.constructor( this._x, this._y, this._z, this._order );
6875
6876	}
6877
6878	copy( euler ) {
6879
6880		this._x = euler._x;
6881		this._y = euler._y;
6882		this._z = euler._z;
6883		this._order = euler._order;
6884
6885		this._onChangeCallback();
6886
6887		return this;
6888
6889	}
6890
6891	setFromRotationMatrix( m, order = this._order, update = true ) {
6892
6893		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6894
6895		const te = m.elements;
6896		const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
6897		const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
6898		const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6899
6900		switch ( order ) {
6901
6902			case 'XYZ':
6903
6904				this._y = Math.asin( clamp( m13, - 1, 1 ) );
6905
6906				if ( Math.abs( m13 ) < 0.9999999 ) {
6907
6908					this._x = Math.atan2( - m23, m33 );
6909					this._z = Math.atan2( - m12, m11 );
6910
6911				} else {
6912
6913					this._x = Math.atan2( m32, m22 );
6914					this._z = 0;
6915
6916				}
6917
6918				break;
6919
6920			case 'YXZ':
6921
6922				this._x = Math.asin( - clamp( m23, - 1, 1 ) );
6923
6924				if ( Math.abs( m23 ) < 0.9999999 ) {
6925
6926					this._y = Math.atan2( m13, m33 );
6927					this._z = Math.atan2( m21, m22 );
6928
6929				} else {
6930
6931					this._y = Math.atan2( - m31, m11 );
6932					this._z = 0;
6933
6934				}
6935
6936				break;
6937
6938			case 'ZXY':
6939
6940				this._x = Math.asin( clamp( m32, - 1, 1 ) );
6941
6942				if ( Math.abs( m32 ) < 0.9999999 ) {
6943
6944					this._y = Math.atan2( - m31, m33 );
6945					this._z = Math.atan2( - m12, m22 );
6946
6947				} else {
6948
6949					this._y = 0;
6950					this._z = Math.atan2( m21, m11 );
6951
6952				}
6953
6954				break;
6955
6956			case 'ZYX':
6957
6958				this._y = Math.asin( - clamp( m31, - 1, 1 ) );
6959
6960				if ( Math.abs( m31 ) < 0.9999999 ) {
6961
6962					this._x = Math.atan2( m32, m33 );
6963					this._z = Math.atan2( m21, m11 );
6964
6965				} else {
6966
6967					this._x = 0;
6968					this._z = Math.atan2( - m12, m22 );
6969
6970				}
6971
6972				break;
6973
6974			case 'YZX':
6975
6976				this._z = Math.asin( clamp( m21, - 1, 1 ) );
6977
6978				if ( Math.abs( m21 ) < 0.9999999 ) {
6979
6980					this._x = Math.atan2( - m23, m22 );
6981					this._y = Math.atan2( - m31, m11 );
6982
6983				} else {
6984
6985					this._x = 0;
6986					this._y = Math.atan2( m13, m33 );
6987
6988				}
6989
6990				break;
6991
6992			case 'XZY':
6993
6994				this._z = Math.asin( - clamp( m12, - 1, 1 ) );
6995
6996				if ( Math.abs( m12 ) < 0.9999999 ) {
6997
6998					this._x = Math.atan2( m32, m22 );
6999					this._y = Math.atan2( m13, m11 );
7000
7001				} else {
7002
7003					this._x = Math.atan2( - m23, m33 );
7004					this._y = 0;
7005
7006				}
7007
7008				break;
7009
7010			default:
7011
7012				console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
7013
7014		}
7015
7016		this._order = order;
7017
7018		if ( update === true ) this._onChangeCallback();
7019
7020		return this;
7021
7022	}
7023
7024	setFromQuaternion( q, order, update ) {
7025
7026		_matrix$1.makeRotationFromQuaternion( q );
7027
7028		return this.setFromRotationMatrix( _matrix$1, order, update );
7029
7030	}
7031
7032	setFromVector3( v, order = this._order ) {
7033
7034		return this.set( v.x, v.y, v.z, order );
7035
7036	}
7037
7038	reorder( newOrder ) {
7039
7040		// WARNING: this discards revolution information -bhouston
7041
7042		_quaternion$3.setFromEuler( this );
7043
7044		return this.setFromQuaternion( _quaternion$3, newOrder );
7045
7046	}
7047
7048	equals( euler ) {
7049
7050		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
7051
7052	}
7053
7054	fromArray( array ) {
7055
7056		this._x = array[ 0 ];
7057		this._y = array[ 1 ];
7058		this._z = array[ 2 ];
7059		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
7060
7061		this._onChangeCallback();
7062
7063		return this;
7064
7065	}
7066
7067	toArray( array = [], offset = 0 ) {
7068
7069		array[ offset ] = this._x;
7070		array[ offset + 1 ] = this._y;
7071		array[ offset + 2 ] = this._z;
7072		array[ offset + 3 ] = this._order;
7073
7074		return array;
7075
7076	}
7077
7078	_onChange( callback ) {
7079
7080		this._onChangeCallback = callback;
7081
7082		return this;
7083
7084	}
7085
7086	_onChangeCallback() {}
7087
7088	*[ Symbol.iterator ]() {
7089
7090		yield this._x;
7091		yield this._y;
7092		yield this._z;
7093		yield this._order;
7094
7095	}
7096
7097}
7098
7099Euler.DEFAULT_ORDER = 'XYZ';
7100
7101class Layers {
7102
7103	constructor() {
7104
7105		this.mask = 1 | 0;
7106
7107	}
7108
7109	set( channel ) {
7110
7111		this.mask = ( 1 << channel | 0 ) >>> 0;
7112
7113	}
7114
7115	enable( channel ) {
7116
7117		this.mask |= 1 << channel | 0;
7118
7119	}
7120
7121	enableAll() {
7122
7123		this.mask = 0xffffffff | 0;
7124
7125	}
7126
7127	toggle( channel ) {
7128
7129		this.mask ^= 1 << channel | 0;
7130
7131	}
7132
7133	disable( channel ) {
7134
7135		this.mask &= ~ ( 1 << channel | 0 );
7136
7137	}
7138
7139	disableAll() {
7140
7141		this.mask = 0;
7142
7143	}
7144
7145	test( layers ) {
7146
7147		return ( this.mask & layers.mask ) !== 0;
7148
7149	}
7150
7151	isEnabled( channel ) {
7152
7153		return ( this.mask & ( 1 << channel | 0 ) ) !== 0;
7154
7155	}
7156
7157}
7158
7159let _object3DId = 0;
7160
7161const _v1$4 = /*@__PURE__*/ new Vector3();
7162const _q1 = /*@__PURE__*/ new Quaternion();
7163const _m1$1 = /*@__PURE__*/ new Matrix4();
7164const _target = /*@__PURE__*/ new Vector3();
7165
7166const _position$3 = /*@__PURE__*/ new Vector3();
7167const _scale$2 = /*@__PURE__*/ new Vector3();
7168const _quaternion$2 = /*@__PURE__*/ new Quaternion();
7169
7170const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
7171const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
7172const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
7173
7174const _addedEvent = { type: 'added' };
7175const _removedEvent = { type: 'removed' };
7176
7177class Object3D extends EventDispatcher {
7178
7179	constructor() {
7180
7181		super();
7182
7183		this.isObject3D = true;
7184
7185		Object.defineProperty( this, 'id', { value: _object3DId ++ } );
7186
7187		this.uuid = generateUUID();
7188
7189		this.name = '';
7190		this.type = 'Object3D';
7191
7192		this.parent = null;
7193		this.children = [];
7194
7195		this.up = Object3D.DEFAULT_UP.clone();
7196
7197		const position = new Vector3();
7198		const rotation = new Euler();
7199		const quaternion = new Quaternion();
7200		const scale = new Vector3( 1, 1, 1 );
7201
7202		function onRotationChange() {
7203
7204			quaternion.setFromEuler( rotation, false );
7205
7206		}
7207
7208		function onQuaternionChange() {
7209
7210			rotation.setFromQuaternion( quaternion, undefined, false );
7211
7212		}
7213
7214		rotation._onChange( onRotationChange );
7215		quaternion._onChange( onQuaternionChange );
7216
7217		Object.defineProperties( this, {
7218			position: {
7219				configurable: true,
7220				enumerable: true,
7221				value: position
7222			},
7223			rotation: {
7224				configurable: true,
7225				enumerable: true,
7226				value: rotation
7227			},
7228			quaternion: {
7229				configurable: true,
7230				enumerable: true,
7231				value: quaternion
7232			},
7233			scale: {
7234				configurable: true,
7235				enumerable: true,
7236				value: scale
7237			},
7238			modelViewMatrix: {
7239				value: new Matrix4()
7240			},
7241			normalMatrix: {
7242				value: new Matrix3()
7243			}
7244		} );
7245
7246		this.matrix = new Matrix4();
7247		this.matrixWorld = new Matrix4();
7248
7249		this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
7250
7251		this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
7252		this.matrixWorldNeedsUpdate = false;
7253
7254		this.layers = new Layers();
7255		this.visible = true;
7256
7257		this.castShadow = false;
7258		this.receiveShadow = false;
7259
7260		this.frustumCulled = true;
7261		this.renderOrder = 0;
7262
7263		this.animations = [];
7264
7265		this.userData = {};
7266
7267	}
7268
7269	onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7270
7271	onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7272
7273	onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7274
7275	onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7276
7277	applyMatrix4( matrix ) {
7278
7279		if ( this.matrixAutoUpdate ) this.updateMatrix();
7280
7281		this.matrix.premultiply( matrix );
7282
7283		this.matrix.decompose( this.position, this.quaternion, this.scale );
7284
7285	}
7286
7287	applyQuaternion( q ) {
7288
7289		this.quaternion.premultiply( q );
7290
7291		return this;
7292
7293	}
7294
7295	setRotationFromAxisAngle( axis, angle ) {
7296
7297		// assumes axis is normalized
7298
7299		this.quaternion.setFromAxisAngle( axis, angle );
7300
7301	}
7302
7303	setRotationFromEuler( euler ) {
7304
7305		this.quaternion.setFromEuler( euler, true );
7306
7307	}
7308
7309	setRotationFromMatrix( m ) {
7310
7311		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
7312
7313		this.quaternion.setFromRotationMatrix( m );
7314
7315	}
7316
7317	setRotationFromQuaternion( q ) {
7318
7319		// assumes q is normalized
7320
7321		this.quaternion.copy( q );
7322
7323
7324	}
7325
7326	rotateOnAxis( axis, angle ) {
7327
7328		// rotate object on axis in object space
7329		// axis is assumed to be normalized
7330
7331		_q1.setFromAxisAngle( axis, angle );
7332
7333		this.quaternion.multiply( _q1 );
7334
7335		return this;
7336
7337	}
7338
7339	rotateOnWorldAxis( axis, angle ) {
7340
7341		// rotate object on axis in world space
7342		// axis is assumed to be normalized
7343		// method assumes no rotated parent
7344
7345		_q1.setFromAxisAngle( axis, angle );
7346
7347		this.quaternion.premultiply( _q1 );
7348
7349		return this;
7350
7351	}
7352
7353	rotateX( angle ) {
7354
7355		return this.rotateOnAxis( _xAxis, angle );
7356
7357	}
7358
7359	rotateY( angle ) {
7360
7361		return this.rotateOnAxis( _yAxis, angle );
7362
7363	}
7364
7365	rotateZ( angle ) {
7366
7367		return this.rotateOnAxis( _zAxis, angle );
7368
7369	}
7370
7371	translateOnAxis( axis, distance ) {
7372
7373		// translate object by distance along axis in object space
7374		// axis is assumed to be normalized
7375
7376		_v1$4.copy( axis ).applyQuaternion( this.quaternion );
7377
7378		this.position.add( _v1$4.multiplyScalar( distance ) );
7379
7380		return this;
7381
7382	}
7383
7384	translateX( distance ) {
7385
7386		return this.translateOnAxis( _xAxis, distance );
7387
7388	}
7389
7390	translateY( distance ) {
7391
7392		return this.translateOnAxis( _yAxis, distance );
7393
7394	}
7395
7396	translateZ( distance ) {
7397
7398		return this.translateOnAxis( _zAxis, distance );
7399
7400	}
7401
7402	localToWorld( vector ) {
7403
7404		this.updateWorldMatrix( true, false );
7405
7406		return vector.applyMatrix4( this.matrixWorld );
7407
7408	}
7409
7410	worldToLocal( vector ) {
7411
7412		this.updateWorldMatrix( true, false );
7413
7414		return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
7415
7416	}
7417
7418	lookAt( x, y, z ) {
7419
7420		// This method does not support objects having non-uniformly-scaled parent(s)
7421
7422		if ( x.isVector3 ) {
7423
7424			_target.copy( x );
7425
7426		} else {
7427
7428			_target.set( x, y, z );
7429
7430		}
7431
7432		const parent = this.parent;
7433
7434		this.updateWorldMatrix( true, false );
7435
7436		_position$3.setFromMatrixPosition( this.matrixWorld );
7437
7438		if ( this.isCamera || this.isLight ) {
7439
7440			_m1$1.lookAt( _position$3, _target, this.up );
7441
7442		} else {
7443
7444			_m1$1.lookAt( _target, _position$3, this.up );
7445
7446		}
7447
7448		this.quaternion.setFromRotationMatrix( _m1$1 );
7449
7450		if ( parent ) {
7451
7452			_m1$1.extractRotation( parent.matrixWorld );
7453			_q1.setFromRotationMatrix( _m1$1 );
7454			this.quaternion.premultiply( _q1.invert() );
7455
7456		}
7457
7458	}
7459
7460	add( object ) {
7461
7462		if ( arguments.length > 1 ) {
7463
7464			for ( let i = 0; i < arguments.length; i ++ ) {
7465
7466				this.add( arguments[ i ] );
7467
7468			}
7469
7470			return this;
7471
7472		}
7473
7474		if ( object === this ) {
7475
7476			console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
7477			return this;
7478
7479		}
7480
7481		if ( object && object.isObject3D ) {
7482
7483			if ( object.parent !== null ) {
7484
7485				object.parent.remove( object );
7486
7487			}
7488
7489			object.parent = this;
7490			this.children.push( object );
7491
7492			object.dispatchEvent( _addedEvent );
7493
7494		} else {
7495
7496			console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
7497
7498		}
7499
7500		return this;
7501
7502	}
7503
7504	remove( object ) {
7505
7506		if ( arguments.length > 1 ) {
7507
7508			for ( let i = 0; i < arguments.length; i ++ ) {
7509
7510				this.remove( arguments[ i ] );
7511
7512			}
7513
7514			return this;
7515
7516		}
7517
7518		const index = this.children.indexOf( object );
7519
7520		if ( index !== - 1 ) {
7521
7522			object.parent = null;
7523			this.children.splice( index, 1 );
7524
7525			object.dispatchEvent( _removedEvent );
7526
7527		}
7528
7529		return this;
7530
7531	}
7532
7533	removeFromParent() {
7534
7535		const parent = this.parent;
7536
7537		if ( parent !== null ) {
7538
7539			parent.remove( this );
7540
7541		}
7542
7543		return this;
7544
7545	}
7546
7547	clear() {
7548
7549		return this.remove( ... this.children );
7550
7551	}
7552
7553	attach( object ) {
7554
7555		// adds object as a child of this, while maintaining the object's world transform
7556
7557		// Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
7558
7559		this.updateWorldMatrix( true, false );
7560
7561		_m1$1.copy( this.matrixWorld ).invert();
7562
7563		if ( object.parent !== null ) {
7564
7565			object.parent.updateWorldMatrix( true, false );
7566
7567			_m1$1.multiply( object.parent.matrixWorld );
7568
7569		}
7570
7571		object.applyMatrix4( _m1$1 );
7572
7573		this.add( object );
7574
7575		object.updateWorldMatrix( false, true );
7576
7577		return this;
7578
7579	}
7580
7581	getObjectById( id ) {
7582
7583		return this.getObjectByProperty( 'id', id );
7584
7585	}
7586
7587	getObjectByName( name ) {
7588
7589		return this.getObjectByProperty( 'name', name );
7590
7591	}
7592
7593	getObjectByProperty( name, value ) {
7594
7595		if ( this[ name ] === value ) return this;
7596
7597		for ( let i = 0, l = this.children.length; i < l; i ++ ) {
7598
7599			const child = this.children[ i ];
7600			const object = child.getObjectByProperty( name, value );
7601
7602			if ( object !== undefined ) {
7603
7604				return object;
7605
7606			}
7607
7608		}
7609
7610		return undefined;
7611
7612	}
7613
7614	getObjectsByProperty( name, value, result = [] ) {
7615
7616		if ( this[ name ] === value ) result.push( this );
7617
7618		const children = this.children;
7619
7620		for ( let i = 0, l = children.length; i < l; i ++ ) {
7621
7622			children[ i ].getObjectsByProperty( name, value, result );
7623
7624		}
7625
7626		return result;
7627
7628	}
7629
7630	getWorldPosition( target ) {
7631
7632		this.updateWorldMatrix( true, false );
7633
7634		return target.setFromMatrixPosition( this.matrixWorld );
7635
7636	}
7637
7638	getWorldQuaternion( target ) {
7639
7640		this.updateWorldMatrix( true, false );
7641
7642		this.matrixWorld.decompose( _position$3, target, _scale$2 );
7643
7644		return target;
7645
7646	}
7647
7648	getWorldScale( target ) {
7649
7650		this.updateWorldMatrix( true, false );
7651
7652		this.matrixWorld.decompose( _position$3, _quaternion$2, target );
7653
7654		return target;
7655
7656	}
7657
7658	getWorldDirection( target ) {
7659
7660		this.updateWorldMatrix( true, false );
7661
7662		const e = this.matrixWorld.elements;
7663
7664		return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
7665
7666	}
7667
7668	raycast( /* raycaster, intersects */ ) {}
7669
7670	traverse( callback ) {
7671
7672		callback( this );
7673
7674		const children = this.children;
7675
7676		for ( let i = 0, l = children.length; i < l; i ++ ) {
7677
7678			children[ i ].traverse( callback );
7679
7680		}
7681
7682	}
7683
7684	traverseVisible( callback ) {
7685
7686		if ( this.visible === false ) return;
7687
7688		callback( this );
7689
7690		const children = this.children;
7691
7692		for ( let i = 0, l = children.length; i < l; i ++ ) {
7693
7694			children[ i ].traverseVisible( callback );
7695
7696		}
7697
7698	}
7699
7700	traverseAncestors( callback ) {
7701
7702		const parent = this.parent;
7703
7704		if ( parent !== null ) {
7705
7706			callback( parent );
7707
7708			parent.traverseAncestors( callback );
7709
7710		}
7711
7712	}
7713
7714	updateMatrix() {
7715
7716		this.matrix.compose( this.position, this.quaternion, this.scale );
7717
7718		this.matrixWorldNeedsUpdate = true;
7719
7720	}
7721
7722	updateMatrixWorld( force ) {
7723
7724		if ( this.matrixAutoUpdate ) this.updateMatrix();
7725
7726		if ( this.matrixWorldNeedsUpdate || force ) {
7727
7728			if ( this.parent === null ) {
7729
7730				this.matrixWorld.copy( this.matrix );
7731
7732			} else {
7733
7734				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7735
7736			}
7737
7738			this.matrixWorldNeedsUpdate = false;
7739
7740			force = true;
7741
7742		}
7743
7744		// update children
7745
7746		const children = this.children;
7747
7748		for ( let i = 0, l = children.length; i < l; i ++ ) {
7749
7750			const child = children[ i ];
7751
7752			if ( child.matrixWorldAutoUpdate === true || force === true ) {
7753
7754				child.updateMatrixWorld( force );
7755
7756			}
7757
7758		}
7759
7760	}
7761
7762	updateWorldMatrix( updateParents, updateChildren ) {
7763
7764		const parent = this.parent;
7765
7766		if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) {
7767
7768			parent.updateWorldMatrix( true, false );
7769
7770		}
7771
7772		if ( this.matrixAutoUpdate ) this.updateMatrix();
7773
7774		if ( this.parent === null ) {
7775
7776			this.matrixWorld.copy( this.matrix );
7777
7778		} else {
7779
7780			this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7781
7782		}
7783
7784		// update children
7785
7786		if ( updateChildren === true ) {
7787
7788			const children = this.children;
7789
7790			for ( let i = 0, l = children.length; i < l; i ++ ) {
7791
7792				const child = children[ i ];
7793
7794				if ( child.matrixWorldAutoUpdate === true ) {
7795
7796					child.updateWorldMatrix( false, true );
7797
7798				}
7799
7800			}
7801
7802		}
7803
7804	}
7805
7806	toJSON( meta ) {
7807
7808		// meta is a string when called from JSON.stringify
7809		const isRootObject = ( meta === undefined || typeof meta === 'string' );
7810
7811		const output = {};
7812
7813		// meta is a hash used to collect geometries, materials.
7814		// not providing it implies that this is the root object
7815		// being serialized.
7816		if ( isRootObject ) {
7817
7818			// initialize meta obj
7819			meta = {
7820				geometries: {},
7821				materials: {},
7822				textures: {},
7823				images: {},
7824				shapes: {},
7825				skeletons: {},
7826				animations: {},
7827				nodes: {}
7828			};
7829
7830			output.metadata = {
7831				version: 4.6,
7832				type: 'Object',
7833				generator: 'Object3D.toJSON'
7834			};
7835
7836		}
7837
7838		// standard Object3D serialization
7839
7840		const object = {};
7841
7842		object.uuid = this.uuid;
7843		object.type = this.type;
7844
7845		if ( this.name !== '' ) object.name = this.name;
7846		if ( this.castShadow === true ) object.castShadow = true;
7847		if ( this.receiveShadow === true ) object.receiveShadow = true;
7848		if ( this.visible === false ) object.visible = false;
7849		if ( this.frustumCulled === false ) object.frustumCulled = false;
7850		if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
7851		if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
7852
7853		object.layers = this.layers.mask;
7854		object.matrix = this.matrix.toArray();
7855		object.up = this.up.toArray();
7856
7857		if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
7858
7859		// object specific properties
7860
7861		if ( this.isInstancedMesh ) {
7862
7863			object.type = 'InstancedMesh';
7864			object.count = this.count;
7865			object.instanceMatrix = this.instanceMatrix.toJSON();
7866			if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
7867
7868		}
7869
7870		if ( this.isBatchedMesh ) {
7871
7872			object.type = 'BatchedMesh';
7873			object.perObjectFrustumCulled = this.perObjectFrustumCulled;
7874			object.sortObjects = this.sortObjects;
7875
7876			object.drawRanges = this._drawRanges;
7877			object.reservedRanges = this._reservedRanges;
7878
7879			object.visibility = this._visibility;
7880			object.active = this._active;
7881			object.bounds = this._bounds.map( bound => ( {
7882				boxInitialized: bound.boxInitialized,
7883				boxMin: bound.box.min.toArray(),
7884				boxMax: bound.box.max.toArray(),
7885
7886				sphereInitialized: bound.sphereInitialized,
7887				sphereRadius: bound.sphere.radius,
7888				sphereCenter: bound.sphere.center.toArray()
7889			} ) );
7890
7891			object.maxGeometryCount = this._maxGeometryCount;
7892			object.maxVertexCount = this._maxVertexCount;
7893			object.maxIndexCount = this._maxIndexCount;
7894
7895			object.geometryInitialized = this._geometryInitialized;
7896			object.geometryCount = this._geometryCount;
7897
7898			object.matricesTexture = this._matricesTexture.toJSON( meta );
7899
7900			if ( this.boundingSphere !== null ) {
7901
7902				object.boundingSphere = {
7903					center: object.boundingSphere.center.toArray(),
7904					radius: object.boundingSphere.radius
7905				};
7906
7907			}
7908
7909			if ( this.boundingBox !== null ) {
7910
7911				object.boundingBox = {
7912					min: object.boundingBox.min.toArray(),
7913					max: object.boundingBox.max.toArray()
7914				};
7915
7916			}
7917
7918		}
7919
7920		//
7921
7922		function serialize( library, element ) {
7923
7924			if ( library[ element.uuid ] === undefined ) {
7925
7926				library[ element.uuid ] = element.toJSON( meta );
7927
7928			}
7929
7930			return element.uuid;
7931
7932		}
7933
7934		if ( this.isScene ) {
7935
7936			if ( this.background ) {
7937
7938				if ( this.background.isColor ) {
7939
7940					object.background = this.background.toJSON();
7941
7942				} else if ( this.background.isTexture ) {
7943
7944					object.background = this.background.toJSON( meta ).uuid;
7945
7946				}
7947
7948			}
7949
7950			if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
7951
7952				object.environment = this.environment.toJSON( meta ).uuid;
7953
7954			}
7955
7956		} else if ( this.isMesh || this.isLine || this.isPoints ) {
7957
7958			object.geometry = serialize( meta.geometries, this.geometry );
7959
7960			const parameters = this.geometry.parameters;
7961
7962			if ( parameters !== undefined && parameters.shapes !== undefined ) {
7963
7964				const shapes = parameters.shapes;
7965
7966				if ( Array.isArray( shapes ) ) {
7967
7968					for ( let i = 0, l = shapes.length; i < l; i ++ ) {
7969
7970						const shape = shapes[ i ];
7971
7972						serialize( meta.shapes, shape );
7973
7974					}
7975
7976				} else {
7977
7978					serialize( meta.shapes, shapes );
7979
7980				}
7981
7982			}
7983
7984		}
7985
7986		if ( this.isSkinnedMesh ) {
7987
7988			object.bindMode = this.bindMode;
7989			object.bindMatrix = this.bindMatrix.toArray();
7990
7991			if ( this.skeleton !== undefined ) {
7992
7993				serialize( meta.skeletons, this.skeleton );
7994
7995				object.skeleton = this.skeleton.uuid;
7996
7997			}
7998
7999		}
8000
8001		if ( this.material !== undefined ) {
8002
8003			if ( Array.isArray( this.material ) ) {
8004
8005				const uuids = [];
8006
8007				for ( let i = 0, l = this.material.length; i < l; i ++ ) {
8008
8009					uuids.push( serialize( meta.materials, this.material[ i ] ) );
8010
8011				}
8012
8013				object.material = uuids;
8014
8015			} else {
8016
8017				object.material = serialize( meta.materials, this.material );
8018
8019			}
8020
8021		}
8022
8023		//
8024
8025		if ( this.children.length > 0 ) {
8026
8027			object.children = [];
8028
8029			for ( let i = 0; i < this.children.length; i ++ ) {
8030
8031				object.children.push( this.children[ i ].toJSON( meta ).object );
8032
8033			}
8034
8035		}
8036
8037		//
8038
8039		if ( this.animations.length > 0 ) {
8040
8041			object.animations = [];
8042
8043			for ( let i = 0; i < this.animations.length; i ++ ) {
8044
8045				const animation = this.animations[ i ];
8046
8047				object.animations.push( serialize( meta.animations, animation ) );
8048
8049			}
8050
8051		}
8052
8053		if ( isRootObject ) {
8054
8055			const geometries = extractFromCache( meta.geometries );
8056			const materials = extractFromCache( meta.materials );
8057			const textures = extractFromCache( meta.textures );
8058			const images = extractFromCache( meta.images );
8059			const shapes = extractFromCache( meta.shapes );
8060			const skeletons = extractFromCache( meta.skeletons );
8061			const animations = extractFromCache( meta.animations );
8062			const nodes = extractFromCache( meta.nodes );
8063
8064			if ( geometries.length > 0 ) output.geometries = geometries;
8065			if ( materials.length > 0 ) output.materials = materials;
8066			if ( textures.length > 0 ) output.textures = textures;
8067			if ( images.length > 0 ) output.images = images;
8068			if ( shapes.length > 0 ) output.shapes = shapes;
8069			if ( skeletons.length > 0 ) output.skeletons = skeletons;
8070			if ( animations.length > 0 ) output.animations = animations;
8071			if ( nodes.length > 0 ) output.nodes = nodes;
8072
8073		}
8074
8075		output.object = object;
8076
8077		return output;
8078
8079		// extract data from the cache hash
8080		// remove metadata on each item
8081		// and return as array
8082		function extractFromCache( cache ) {
8083
8084			const values = [];
8085			for ( const key in cache ) {
8086
8087				const data = cache[ key ];
8088				delete data.metadata;
8089				values.push( data );
8090
8091			}
8092
8093			return values;
8094
8095		}
8096
8097	}
8098
8099	clone( recursive ) {
8100
8101		return new this.constructor().copy( this, recursive );
8102
8103	}
8104
8105	copy( source, recursive = true ) {
8106
8107		this.name = source.name;
8108
8109		this.up.copy( source.up );
8110
8111		this.position.copy( source.position );
8112		this.rotation.order = source.rotation.order;
8113		this.quaternion.copy( source.quaternion );
8114		this.scale.copy( source.scale );
8115
8116		this.matrix.copy( source.matrix );
8117		this.matrixWorld.copy( source.matrixWorld );
8118
8119		this.matrixAutoUpdate = source.matrixAutoUpdate;
8120
8121		this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
8122		this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
8123
8124		this.layers.mask = source.layers.mask;
8125		this.visible = source.visible;
8126
8127		this.castShadow = source.castShadow;
8128		this.receiveShadow = source.receiveShadow;
8129
8130		this.frustumCulled = source.frustumCulled;
8131		this.renderOrder = source.renderOrder;
8132
8133		this.animations = source.animations.slice();
8134
8135		this.userData = JSON.parse( JSON.stringify( source.userData ) );
8136
8137		if ( recursive === true ) {
8138
8139			for ( let i = 0; i < source.children.length; i ++ ) {
8140
8141				const child = source.children[ i ];
8142				this.add( child.clone() );
8143
8144			}
8145
8146		}
8147
8148		return this;
8149
8150	}
8151
8152}
8153
8154Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
8155Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true;
8156Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;
8157
8158const _v0$1 = /*@__PURE__*/ new Vector3();
8159const _v1$3 = /*@__PURE__*/ new Vector3();
8160const _v2$2 = /*@__PURE__*/ new Vector3();
8161const _v3$1 = /*@__PURE__*/ new Vector3();
8162
8163const _vab = /*@__PURE__*/ new Vector3();
8164const _vac = /*@__PURE__*/ new Vector3();
8165const _vbc = /*@__PURE__*/ new Vector3();
8166const _vap = /*@__PURE__*/ new Vector3();
8167const _vbp = /*@__PURE__*/ new Vector3();
8168const _vcp = /*@__PURE__*/ new Vector3();
8169
8170let warnedGetUV = false;
8171
8172class Triangle {
8173
8174	constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
8175
8176		this.a = a;
8177		this.b = b;
8178		this.c = c;
8179
8180	}
8181
8182	static getNormal( a, b, c, target ) {
8183
8184		target.subVectors( c, b );
8185		_v0$1.subVectors( a, b );
8186		target.cross( _v0$1 );
8187
8188		const targetLengthSq = target.lengthSq();
8189		if ( targetLengthSq > 0 ) {
8190
8191			return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
8192
8193		}
8194
8195		return target.set( 0, 0, 0 );
8196
8197	}
8198
8199	// static/instance method to calculate barycentric coordinates
8200	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
8201	static getBarycoord( point, a, b, c, target ) {
8202
8203		_v0$1.subVectors( c, a );
8204		_v1$3.subVectors( b, a );
8205		_v2$2.subVectors( point, a );
8206
vendor: 4,337 bytes, lines 8207-8414
8207		const dot00 = _v0$1.dot( _v0$1 );
8208		const dot01 = _v0$1.dot( _v1$3 );
8209		const dot02 = _v0$1.dot( _v2$2 );
8210		const dot11 = _v1$3.dot( _v1$3 );
8211		const dot12 = _v1$3.dot( _v2$2 );
8212
8213		const denom = ( dot00 * dot11 - dot01 * dot01 );
8214
8215		// collinear or singular triangle
8216		if ( denom === 0 ) {
8217
8218			target.set( 0, 0, 0 );
8219			return null;
8220
8221		}
8222
8223		const invDenom = 1 / denom;
8224		const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
8225		const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
8226
8227		// barycentric coordinates must always sum to 1
8228		return target.set( 1 - u - v, v, u );
8229
8230	}
8231
8232	static containsPoint( point, a, b, c ) {
8233
8234		// if the triangle is degenerate then we can't contain a point
8235		if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) {
8236
8237			return false;
8238
8239		}
8240
8241		return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 );
8242
8243	}
8244
8245	static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151
8246
8247		if ( warnedGetUV === false ) {
8248
8249			console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8250
8251			warnedGetUV = true;
8252
8253		}
8254
8255		return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target );
8256
8257	}
8258
8259	static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
8260
8261		if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) {
8262
8263			target.x = 0;
8264			target.y = 0;
8265			if ( 'z' in target ) target.z = 0;
8266			if ( 'w' in target ) target.w = 0;
8267			return null;
8268
8269		}
8270
8271		target.setScalar( 0 );
8272		target.addScaledVector( v1, _v3$1.x );
8273		target.addScaledVector( v2, _v3$1.y );
8274		target.addScaledVector( v3, _v3$1.z );
8275
8276		return target;
8277
8278	}
8279
8280	static isFrontFacing( a, b, c, direction ) {
8281
8282		_v0$1.subVectors( c, b );
8283		_v1$3.subVectors( a, b );
8284
8285		// strictly front facing
8286		return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
8287
8288	}
8289
8290	set( a, b, c ) {
8291
8292		this.a.copy( a );
8293		this.b.copy( b );
8294		this.c.copy( c );
8295
8296		return this;
8297
8298	}
8299
8300	setFromPointsAndIndices( points, i0, i1, i2 ) {
8301
8302		this.a.copy( points[ i0 ] );
8303		this.b.copy( points[ i1 ] );
8304		this.c.copy( points[ i2 ] );
8305
8306		return this;
8307
8308	}
8309
8310	setFromAttributeAndIndices( attribute, i0, i1, i2 ) {
8311
8312		this.a.fromBufferAttribute( attribute, i0 );
8313		this.b.fromBufferAttribute( attribute, i1 );
8314		this.c.fromBufferAttribute( attribute, i2 );
8315
8316		return this;
8317
8318	}
8319
8320	clone() {
8321
8322		return new this.constructor().copy( this );
8323
8324	}
8325
8326	copy( triangle ) {
8327
8328		this.a.copy( triangle.a );
8329		this.b.copy( triangle.b );
8330		this.c.copy( triangle.c );
8331
8332		return this;
8333
8334	}
8335
8336	getArea() {
8337
8338		_v0$1.subVectors( this.c, this.b );
8339		_v1$3.subVectors( this.a, this.b );
8340
8341		return _v0$1.cross( _v1$3 ).length() * 0.5;
8342
8343	}
8344
8345	getMidpoint( target ) {
8346
8347		return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
8348
8349	}
8350
8351	getNormal( target ) {
8352
8353		return Triangle.getNormal( this.a, this.b, this.c, target );
8354
8355	}
8356
8357	getPlane( target ) {
8358
8359		return target.setFromCoplanarPoints( this.a, this.b, this.c );
8360
8361	}
8362
8363	getBarycoord( point, target ) {
8364
8365		return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
8366
8367	}
8368
8369	getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151
8370
8371		if ( warnedGetUV === false ) {
8372
8373			console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8374
8375			warnedGetUV = true;
8376
8377		}
8378
8379		return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
8380
8381	}
8382
8383	getInterpolation( point, v1, v2, v3, target ) {
8384
8385		return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );
8386
8387	}
8388
8389	containsPoint( point ) {
8390
8391		return Triangle.containsPoint( point, this.a, this.b, this.c );
8392
8393	}
8394
8395	isFrontFacing( direction ) {
8396
8397		return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
8398
8399	}
8400
8401	intersectsBox( box ) {
8402
8403		return box.intersectsTriangle( this );
8404
8405	}
8406
8407	closestPointToPoint( p, target ) {
8408
8409		const a = this.a, b = this.b, c = this.c;
8410		let v, w;
8411
8412		// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
8413		// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
8414		// under the accompanying license; see chapter 5.1.5 for detailed explanation.
vendor: 27,169 bytes, lines 8415-9457
8415		// basically, we're distinguishing which of the voronoi regions of the triangle
8416		// the point lies in with the minimum amount of redundant computation.
8417
8418		_vab.subVectors( b, a );
8419		_vac.subVectors( c, a );
8420		_vap.subVectors( p, a );
8421		const d1 = _vab.dot( _vap );
8422		const d2 = _vac.dot( _vap );
8423		if ( d1 <= 0 && d2 <= 0 ) {
8424
8425			// vertex region of A; barycentric coords (1, 0, 0)
8426			return target.copy( a );
8427
8428		}
8429
8430		_vbp.subVectors( p, b );
8431		const d3 = _vab.dot( _vbp );
8432		const d4 = _vac.dot( _vbp );
8433		if ( d3 >= 0 && d4 <= d3 ) {
8434
8435			// vertex region of B; barycentric coords (0, 1, 0)
8436			return target.copy( b );
8437
8438		}
8439
8440		const vc = d1 * d4 - d3 * d2;
8441		if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
8442
8443			v = d1 / ( d1 - d3 );
8444			// edge region of AB; barycentric coords (1-v, v, 0)
8445			return target.copy( a ).addScaledVector( _vab, v );
8446
8447		}
8448
8449		_vcp.subVectors( p, c );
8450		const d5 = _vab.dot( _vcp );
8451		const d6 = _vac.dot( _vcp );
8452		if ( d6 >= 0 && d5 <= d6 ) {
8453
8454			// vertex region of C; barycentric coords (0, 0, 1)
8455			return target.copy( c );
8456
8457		}
8458
8459		const vb = d5 * d2 - d1 * d6;
8460		if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
8461
8462			w = d2 / ( d2 - d6 );
8463			// edge region of AC; barycentric coords (1-w, 0, w)
8464			return target.copy( a ).addScaledVector( _vac, w );
8465
8466		}
8467
8468		const va = d3 * d6 - d5 * d4;
8469		if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
8470
8471			_vbc.subVectors( c, b );
8472			w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
8473			// edge region of BC; barycentric coords (0, 1-w, w)
8474			return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
8475
8476		}
8477
8478		// face region
8479		const denom = 1 / ( va + vb + vc );
8480		// u = va * denom
8481		v = vb * denom;
8482		w = vc * denom;
8483
8484		return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
8485
8486	}
8487
8488	equals( triangle ) {
8489
8490		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
8491
8492	}
8493
8494}
8495
8496const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
8497	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
8498	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
8499	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
8500	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
8501	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
8502	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
8503	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
8504	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
8505	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
8506	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
8507	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
8508	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
8509	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
8510	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
8511	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
8512	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
8513	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
8514	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
8515	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
8516	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
8517	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
8518	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
8519	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
8520
8521const _hslA = { h: 0, s: 0, l: 0 };
8522const _hslB = { h: 0, s: 0, l: 0 };
8523
8524function hue2rgb( p, q, t ) {
8525
8526	if ( t < 0 ) t += 1;
8527	if ( t > 1 ) t -= 1;
8528	if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
8529	if ( t < 1 / 2 ) return q;
8530	if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
8531	return p;
8532
8533}
8534
8535class Color {
8536
8537	constructor( r, g, b ) {
8538
8539		this.isColor = true;
8540
8541		this.r = 1;
8542		this.g = 1;
8543		this.b = 1;
8544
8545		return this.set( r, g, b );
8546
8547	}
8548
8549	set( r, g, b ) {
8550
8551		if ( g === undefined && b === undefined ) {
8552
8553			// r is THREE.Color, hex or string
8554
8555			const value = r;
8556
8557			if ( value && value.isColor ) {
8558
8559				this.copy( value );
8560
8561			} else if ( typeof value === 'number' ) {
8562
8563				this.setHex( value );
8564
8565			} else if ( typeof value === 'string' ) {
8566
8567				this.setStyle( value );
8568
8569			}
8570
8571		} else {
8572
8573			this.setRGB( r, g, b );
8574
8575		}
8576
8577		return this;
8578
8579	}
8580
8581	setScalar( scalar ) {
8582
8583		this.r = scalar;
8584		this.g = scalar;
8585		this.b = scalar;
8586
8587		return this;
8588
8589	}
8590
8591	setHex( hex, colorSpace = SRGBColorSpace ) {
8592
8593		hex = Math.floor( hex );
8594
8595		this.r = ( hex >> 16 & 255 ) / 255;
8596		this.g = ( hex >> 8 & 255 ) / 255;
8597		this.b = ( hex & 255 ) / 255;
8598
8599		ColorManagement.toWorkingColorSpace( this, colorSpace );
8600
8601		return this;
8602
8603	}
8604
8605	setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {
8606
8607		this.r = r;
8608
8609		this.g = g;
8610		this.b = b;
8611
8612		ColorManagement.toWorkingColorSpace( this, colorSpace );
8613
8614		return this;
8615
8616	}
8617
8618	setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {
8619
8620		// h,s,l ranges are in 0.0 - 1.0
8621		h = euclideanModulo( h, 1 );
8622		s = clamp( s, 0, 1 );
8623		l = clamp( l, 0, 1 );
8624
8625		if ( s === 0 ) {
8626
8627			this.r = this.g = this.b = l;
8628
8629		} else {
8630
8631			const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
8632			const q = ( 2 * l ) - p;
8633
8634			this.r = hue2rgb( q, p, h + 1 / 3 );
8635			this.g = hue2rgb( q, p, h );
8636			this.b = hue2rgb( q, p, h - 1 / 3 );
8637
8638		}
8639
8640		ColorManagement.toWorkingColorSpace( this, colorSpace );
8641
8642		return this;
8643
8644	}
8645
8646	setStyle( style, colorSpace = SRGBColorSpace ) {
8647
8648		function handleAlpha( string ) {
8649
8650			if ( string === undefined ) return;
8651
8652			if ( parseFloat( string ) < 1 ) {
8653
8654				console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
8655
8656			}
8657
8658		}
8659
8660
8661		let m;
8662
8663		if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) {
8664
8665			// rgb / hsl
8666
8667			let color;
8668			const name = m[ 1 ];
8669			const components = m[ 2 ];
8670
8671			switch ( name ) {
8672
8673				case 'rgb':
8674				case 'rgba':
8675
8676					if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8677
8678						// rgb(255,0,0) rgba(255,0,0,0.5)
8679
8680						handleAlpha( color[ 4 ] );
8681
8682						return this.setRGB(
8683							Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,
8684							Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,
8685							Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,
8686							colorSpace
8687						);
8688
8689					}
8690
8691					if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8692
8693						// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
8694
8695						handleAlpha( color[ 4 ] );
8696
8697						return this.setRGB(
8698							Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,
8699							Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,
8700							Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,
8701							colorSpace
8702						);
8703
8704					}
8705
8706					break;
8707
8708				case 'hsl':
8709				case 'hsla':
8710
8711					if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8712
8713						// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
8714
8715						handleAlpha( color[ 4 ] );
8716
8717						return this.setHSL(
8718							parseFloat( color[ 1 ] ) / 360,
8719							parseFloat( color[ 2 ] ) / 100,
8720							parseFloat( color[ 3 ] ) / 100,
8721							colorSpace
8722						);
8723
8724					}
8725
8726					break;
8727
8728				default:
8729
8730					console.warn( 'THREE.Color: Unknown color model ' + style );
8731
8732			}
8733
8734		} else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
8735
8736			// hex color
8737
8738			const hex = m[ 1 ];
8739			const size = hex.length;
8740
8741			if ( size === 3 ) {
8742
8743				// #ff0
8744				return this.setRGB(
8745					parseInt( hex.charAt( 0 ), 16 ) / 15,
8746					parseInt( hex.charAt( 1 ), 16 ) / 15,
8747					parseInt( hex.charAt( 2 ), 16 ) / 15,
8748					colorSpace
8749				);
8750
8751			} else if ( size === 6 ) {
8752
8753				// #ff0000
8754				return this.setHex( parseInt( hex, 16 ), colorSpace );
8755
8756			} else {
8757
8758				console.warn( 'THREE.Color: Invalid hex color ' + style );
8759
8760			}
8761
8762		} else if ( style && style.length > 0 ) {
8763
8764			return this.setColorName( style, colorSpace );
8765
8766		}
8767
8768		return this;
8769
8770	}
8771
8772	setColorName( style, colorSpace = SRGBColorSpace ) {
8773
8774		// color keywords
8775		const hex = _colorKeywords[ style.toLowerCase() ];
8776
8777		if ( hex !== undefined ) {
8778
8779			// red
8780			this.setHex( hex, colorSpace );
8781
8782		} else {
8783
8784			// unknown color
8785			console.warn( 'THREE.Color: Unknown color ' + style );
8786
8787		}
8788
8789		return this;
8790
8791	}
8792
8793	clone() {
8794
8795		return new this.constructor( this.r, this.g, this.b );
8796
8797	}
8798
8799	copy( color ) {
8800
8801		this.r = color.r;
8802		this.g = color.g;
8803		this.b = color.b;
8804
8805		return this;
8806
8807	}
8808
8809	copySRGBToLinear( color ) {
8810
8811		this.r = SRGBToLinear( color.r );
8812		this.g = SRGBToLinear( color.g );
8813		this.b = SRGBToLinear( color.b );
8814
8815		return this;
8816
8817	}
8818
8819	copyLinearToSRGB( color ) {
8820
8821		this.r = LinearToSRGB( color.r );
8822		this.g = LinearToSRGB( color.g );
8823		this.b = LinearToSRGB( color.b );
8824
8825		return this;
8826
8827	}
8828
8829	convertSRGBToLinear() {
8830
8831		this.copySRGBToLinear( this );
8832
8833		return this;
8834
8835	}
8836
8837	convertLinearToSRGB() {
8838
8839		this.copyLinearToSRGB( this );
8840
8841		return this;
8842
8843	}
8844
8845	getHex( colorSpace = SRGBColorSpace ) {
8846
8847		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8848
8849		return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) );
8850
8851	}
8852
8853	getHexString( colorSpace = SRGBColorSpace ) {
8854
8855		return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );
8856
8857	}
8858
8859	getHSL( target, colorSpace = ColorManagement.workingColorSpace ) {
8860
8861		// h,s,l ranges are in 0.0 - 1.0
8862
8863		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8864
8865		const r = _color.r, g = _color.g, b = _color.b;
8866
8867		const max = Math.max( r, g, b );
8868		const min = Math.min( r, g, b );
8869
8870		let hue, saturation;
8871		const lightness = ( min + max ) / 2.0;
8872
8873		if ( min === max ) {
8874
8875			hue = 0;
8876			saturation = 0;
8877
8878		} else {
8879
8880			const delta = max - min;
8881
8882			saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
8883
8884			switch ( max ) {
8885
8886				case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
8887				case g: hue = ( b - r ) / delta + 2; break;
8888				case b: hue = ( r - g ) / delta + 4; break;
8889
8890			}
8891
8892			hue /= 6;
8893
8894		}
8895
8896		target.h = hue;
8897		target.s = saturation;
8898		target.l = lightness;
8899
8900		return target;
8901
8902	}
8903
8904	getRGB( target, colorSpace = ColorManagement.workingColorSpace ) {
8905
8906		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8907
8908		target.r = _color.r;
8909		target.g = _color.g;
8910		target.b = _color.b;
8911
8912		return target;
8913
8914	}
8915
8916	getStyle( colorSpace = SRGBColorSpace ) {
8917
8918		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8919
8920		const r = _color.r, g = _color.g, b = _color.b;
8921
8922		if ( colorSpace !== SRGBColorSpace ) {
8923
8924			// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
8925			return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;
8926
8927		}
8928
8929		return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;
8930
8931	}
8932
8933	offsetHSL( h, s, l ) {
8934
8935		this.getHSL( _hslA );
8936
8937		return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );
8938
8939	}
8940
8941	add( color ) {
8942
8943		this.r += color.r;
8944		this.g += color.g;
8945		this.b += color.b;
8946
8947		return this;
8948
8949	}
8950
8951	addColors( color1, color2 ) {
8952
8953		this.r = color1.r + color2.r;
8954		this.g = color1.g + color2.g;
8955		this.b = color1.b + color2.b;
8956
8957		return this;
8958
8959	}
8960
8961	addScalar( s ) {
8962
8963		this.r += s;
8964		this.g += s;
8965		this.b += s;
8966
8967		return this;
8968
8969	}
8970
8971	sub( color ) {
8972
8973		this.r = Math.max( 0, this.r - color.r );
8974		this.g = Math.max( 0, this.g - color.g );
8975		this.b = Math.max( 0, this.b - color.b );
8976
8977		return this;
8978
8979	}
8980
8981	multiply( color ) {
8982
8983		this.r *= color.r;
8984		this.g *= color.g;
8985		this.b *= color.b;
8986
8987		return this;
8988
8989	}
8990
8991	multiplyScalar( s ) {
8992
8993		this.r *= s;
8994		this.g *= s;
8995		this.b *= s;
8996
8997		return this;
8998
8999	}
9000
9001	lerp( color, alpha ) {
9002
9003		this.r += ( color.r - this.r ) * alpha;
9004		this.g += ( color.g - this.g ) * alpha;
9005		this.b += ( color.b - this.b ) * alpha;
9006
9007		return this;
9008
9009	}
9010
9011	lerpColors( color1, color2, alpha ) {
9012
9013		this.r = color1.r + ( color2.r - color1.r ) * alpha;
9014		this.g = color1.g + ( color2.g - color1.g ) * alpha;
9015		this.b = color1.b + ( color2.b - color1.b ) * alpha;
9016
9017		return this;
9018
9019	}
9020
9021	lerpHSL( color, alpha ) {
9022
9023		this.getHSL( _hslA );
9024		color.getHSL( _hslB );
9025
9026		const h = lerp( _hslA.h, _hslB.h, alpha );
9027		const s = lerp( _hslA.s, _hslB.s, alpha );
9028		const l = lerp( _hslA.l, _hslB.l, alpha );
9029
9030		this.setHSL( h, s, l );
9031
9032		return this;
9033
9034	}
9035
9036	setFromVector3( v ) {
9037
9038		this.r = v.x;
9039		this.g = v.y;
9040		this.b = v.z;
9041
9042		return this;
9043
9044	}
9045
9046	applyMatrix3( m ) {
9047
9048		const r = this.r, g = this.g, b = this.b;
9049		const e = m.elements;
9050
9051		this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;
9052		this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;
9053		this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;
9054
9055		return this;
9056
9057	}
9058
9059	equals( c ) {
9060
9061		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
9062
9063	}
9064
9065	fromArray( array, offset = 0 ) {
9066
9067		this.r = array[ offset ];
9068		this.g = array[ offset + 1 ];
9069		this.b = array[ offset + 2 ];
9070
9071		return this;
9072
9073	}
9074
9075	toArray( array = [], offset = 0 ) {
9076
9077		array[ offset ] = this.r;
9078		array[ offset + 1 ] = this.g;
9079		array[ offset + 2 ] = this.b;
9080
9081		return array;
9082
9083	}
9084
9085	fromBufferAttribute( attribute, index ) {
9086
9087		this.r = attribute.getX( index );
9088		this.g = attribute.getY( index );
9089		this.b = attribute.getZ( index );
9090
9091		return this;
9092
9093	}
9094
9095	toJSON() {
9096
9097		return this.getHex();
9098
9099	}
9100
9101	*[ Symbol.iterator ]() {
9102
9103		yield this.r;
9104		yield this.g;
9105		yield this.b;
9106
9107	}
9108
9109}
9110
9111const _color = /*@__PURE__*/ new Color();
9112
9113Color.NAMES = _colorKeywords;
9114
9115let _materialId = 0;
9116
9117class Material extends EventDispatcher {
9118
9119	constructor() {
9120
9121		super();
9122
9123		this.isMaterial = true;
9124
9125		Object.defineProperty( this, 'id', { value: _materialId ++ } );
9126
9127		this.uuid = generateUUID();
9128
9129		this.name = '';
9130		this.type = 'Material';
9131
9132		this.blending = NormalBlending;
9133		this.side = FrontSide;
9134		this.vertexColors = false;
9135
9136		this.opacity = 1;
9137		this.transparent = false;
9138		this.alphaHash = false;
9139
9140		this.blendSrc = SrcAlphaFactor;
9141		this.blendDst = OneMinusSrcAlphaFactor;
9142		this.blendEquation = AddEquation;
9143		this.blendSrcAlpha = null;
9144		this.blendDstAlpha = null;
9145		this.blendEquationAlpha = null;
9146		this.blendColor = new Color( 0, 0, 0 );
9147		this.blendAlpha = 0;
9148
9149		this.depthFunc = LessEqualDepth;
9150		this.depthTest = true;
9151		this.depthWrite = true;
9152
9153		this.stencilWriteMask = 0xff;
9154		this.stencilFunc = AlwaysStencilFunc;
9155		this.stencilRef = 0;
9156		this.stencilFuncMask = 0xff;
9157		this.stencilFail = KeepStencilOp;
9158		this.stencilZFail = KeepStencilOp;
9159		this.stencilZPass = KeepStencilOp;
9160		this.stencilWrite = false;
9161
9162		this.clippingPlanes = null;
9163		this.clipIntersection = false;
9164		this.clipShadows = false;
9165
9166		this.shadowSide = null;
9167
9168		this.colorWrite = true;
9169
9170		this.precision = null; // override the renderer's default precision for this material
9171
9172		this.polygonOffset = false;
9173		this.polygonOffsetFactor = 0;
9174		this.polygonOffsetUnits = 0;
9175
9176		this.dithering = false;
9177
9178		this.alphaToCoverage = false;
9179		this.premultipliedAlpha = false;
9180		this.forceSinglePass = false;
9181
9182		this.visible = true;
9183
9184		this.toneMapped = true;
9185
9186		this.userData = {};
9187
9188		this.version = 0;
9189
9190		this._alphaTest = 0;
9191
9192	}
9193
9194	get alphaTest() {
9195
9196		return this._alphaTest;
9197
9198	}
9199
9200	set alphaTest( value ) {
9201
9202		if ( this._alphaTest > 0 !== value > 0 ) {
9203
9204			this.version ++;
9205
9206		}
9207
9208		this._alphaTest = value;
9209
9210	}
9211
9212	onBuild( /* shaderobject, renderer */ ) {}
9213
9214	onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
9215
9216	onBeforeCompile( /* shaderobject, renderer */ ) {}
9217
9218	customProgramCacheKey() {
9219
9220		return this.onBeforeCompile.toString();
9221
9222	}
9223
9224	setValues( values ) {
9225
9226		if ( values === undefined ) return;
9227
9228		for ( const key in values ) {
9229
9230			const newValue = values[ key ];
9231
9232			if ( newValue === undefined ) {
9233
9234				console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );
9235				continue;
9236
9237			}
9238
9239			const currentValue = this[ key ];
9240
9241			if ( currentValue === undefined ) {
9242
9243				console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );
9244				continue;
9245
9246			}
9247
9248			if ( currentValue && currentValue.isColor ) {
9249
9250				currentValue.set( newValue );
9251
9252			} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
9253
9254				currentValue.copy( newValue );
9255
9256			} else {
9257
9258				this[ key ] = newValue;
9259
9260			}
9261
9262		}
9263
9264	}
9265
9266	toJSON( meta ) {
9267
9268		const isRootObject = ( meta === undefined || typeof meta === 'string' );
9269
9270		if ( isRootObject ) {
9271
9272			meta = {
9273				textures: {},
9274				images: {}
9275			};
9276
9277		}
9278
9279		const data = {
9280			metadata: {
9281				version: 4.6,
9282				type: 'Material',
9283				generator: 'Material.toJSON'
9284			}
9285		};
9286
9287		// standard Material serialization
9288		data.uuid = this.uuid;
9289		data.type = this.type;
9290
9291		if ( this.name !== '' ) data.name = this.name;
9292
9293		if ( this.color && this.color.isColor ) data.color = this.color.getHex();
9294
9295		if ( this.roughness !== undefined ) data.roughness = this.roughness;
9296		if ( this.metalness !== undefined ) data.metalness = this.metalness;
9297
9298		if ( this.sheen !== undefined ) data.sheen = this.sheen;
9299		if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
9300		if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
9301		if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
9302		if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
9303
9304		if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
9305		if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
9306		if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
9307		if ( this.shininess !== undefined ) data.shininess = this.shininess;
9308		if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
9309		if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
9310
9311		if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
9312
9313			data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
9314
9315		}
9316
9317		if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
9318
9319			data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
9320
9321		}
9322
9323		if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
9324
9325			data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
9326			data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
9327
9328		}
9329
9330		if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
9331		if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
9332		if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
9333
9334		if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
9335
9336			data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
9337
9338		}
9339
9340		if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
9341
9342			data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
9343
9344		}
9345
9346		if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
9347		if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
9348
9349		if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
9350
9351			data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
9352
9353		}
9354
9355		if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
9356		if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
9357		if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
9358
9359		if ( this.lightMap && this.lightMap.isTexture ) {
9360
9361			data.lightMap = this.lightMap.toJSON( meta ).uuid;
9362			data.lightMapIntensity = this.lightMapIntensity;
9363
9364		}
9365
9366		if ( this.aoMap && this.aoMap.isTexture ) {
9367
9368			data.aoMap = this.aoMap.toJSON( meta ).uuid;
9369			data.aoMapIntensity = this.aoMapIntensity;
9370
9371		}
9372
9373		if ( this.bumpMap && this.bumpMap.isTexture ) {
9374
9375			data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
9376			data.bumpScale = this.bumpScale;
9377
9378		}
9379
9380		if ( this.normalMap && this.normalMap.isTexture ) {
9381
9382			data.normalMap = this.normalMap.toJSON( meta ).uuid;
9383			data.normalMapType = this.normalMapType;
9384			data.normalScale = this.normalScale.toArray();
9385
9386		}
9387
9388		if ( this.displacementMap && this.displacementMap.isTexture ) {
9389
9390			data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
9391			data.displacementScale = this.displacementScale;
9392			data.displacementBias = this.displacementBias;
9393
9394		}
9395
9396		if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
9397		if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
9398
9399		if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
9400		if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
9401		if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
9402		if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
9403
9404		if ( this.envMap && this.envMap.isTexture ) {
9405
9406			data.envMap = this.envMap.toJSON( meta ).uuid;
9407
9408			if ( this.combine !== undefined ) data.combine = this.combine;
9409
9410		}
9411
9412		if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
9413		if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
9414		if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
9415
9416		if ( this.gradientMap && this.gradientMap.isTexture ) {
9417
9418			data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
9419
9420		}
9421
9422		if ( this.transmission !== undefined ) data.transmission = this.transmission;
9423		if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
9424		if ( this.thickness !== undefined ) data.thickness = this.thickness;
9425		if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
9426		if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
9427		if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
9428
9429		if ( this.size !== undefined ) data.size = this.size;
9430		if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
9431		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
9432
9433		if ( this.blending !== NormalBlending ) data.blending = this.blending;
9434		if ( this.side !== FrontSide ) data.side = this.side;
9435		if ( this.vertexColors === true ) data.vertexColors = true;
9436
9437		if ( this.opacity < 1 ) data.opacity = this.opacity;
9438		if ( this.transparent === true ) data.transparent = true;
9439
9440		if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
9441		if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
9442		if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
9443		if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
9444		if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
9445		if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
9446		if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
9447		if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
9448
9449		if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
9450		if ( this.depthTest === false ) data.depthTest = this.depthTest;
9451		if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
9452		if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
9453
9454		if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
9455		if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
9456		if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
9457		if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
vendor: 4,089 bytes, lines 9458-9586
9458		if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
9459		if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
9460		if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
9461		if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
9462
9463		// rotation (SpriteMaterial)
9464		if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
9465
9466		if ( this.polygonOffset === true ) data.polygonOffset = true;
9467		if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
9468		if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
9469
9470		if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
9471		if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
9472		if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
9473		if ( this.scale !== undefined ) data.scale = this.scale;
9474
9475		if ( this.dithering === true ) data.dithering = true;
9476
9477		if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
9478		if ( this.alphaHash === true ) data.alphaHash = true;
9479		if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
9480		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
9481		if ( this.forceSinglePass === true ) data.forceSinglePass = true;
9482
9483		if ( this.wireframe === true ) data.wireframe = true;
9484		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
9485		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
9486		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
9487
9488		if ( this.flatShading === true ) data.flatShading = true;
9489
9490		if ( this.visible === false ) data.visible = false;
9491
9492		if ( this.toneMapped === false ) data.toneMapped = false;
9493
9494		if ( this.fog === false ) data.fog = false;
9495
9496		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
9497
9498		// TODO: Copied from Object3D.toJSON
9499
9500		function extractFromCache( cache ) {
9501
9502			const values = [];
9503
9504			for ( const key in cache ) {
9505
9506				const data = cache[ key ];
9507				delete data.metadata;
9508				values.push( data );
9509
9510			}
9511
9512			return values;
9513
9514		}
9515
9516		if ( isRootObject ) {
9517
9518			const textures = extractFromCache( meta.textures );
9519			const images = extractFromCache( meta.images );
9520
9521			if ( textures.length > 0 ) data.textures = textures;
9522			if ( images.length > 0 ) data.images = images;
9523
9524		}
9525
9526		return data;
9527
9528	}
9529
9530	clone() {
9531
9532		return new this.constructor().copy( this );
9533
9534	}
9535
9536	copy( source ) {
9537
9538		this.name = source.name;
9539
9540		this.blending = source.blending;
9541		this.side = source.side;
9542		this.vertexColors = source.vertexColors;
9543
9544		this.opacity = source.opacity;
9545		this.transparent = source.transparent;
9546
9547		this.blendSrc = source.blendSrc;
9548		this.blendDst = source.blendDst;
9549		this.blendEquation = source.blendEquation;
9550		this.blendSrcAlpha = source.blendSrcAlpha;
9551		this.blendDstAlpha = source.blendDstAlpha;
9552		this.blendEquationAlpha = source.blendEquationAlpha;
9553		this.blendColor.copy( source.blendColor );
9554		this.blendAlpha = source.blendAlpha;
9555
9556		this.depthFunc = source.depthFunc;
9557		this.depthTest = source.depthTest;
9558		this.depthWrite = source.depthWrite;
9559
9560		this.stencilWriteMask = source.stencilWriteMask;
9561		this.stencilFunc = source.stencilFunc;
9562		this.stencilRef = source.stencilRef;
9563		this.stencilFuncMask = source.stencilFuncMask;
9564		this.stencilFail = source.stencilFail;
9565		this.stencilZFail = source.stencilZFail;
9566		this.stencilZPass = source.stencilZPass;
9567		this.stencilWrite = source.stencilWrite;
9568
9569		const srcPlanes = source.clippingPlanes;
9570		let dstPlanes = null;
9571
9572		if ( srcPlanes !== null ) {
9573
9574			const n = srcPlanes.length;
9575			dstPlanes = new Array( n );
9576
9577			for ( let i = 0; i !== n; ++ i ) {
9578
9579				dstPlanes[ i ] = srcPlanes[ i ].clone();
9580
9581			}
9582
9583		}
9584
9585		this.clippingPlanes = dstPlanes;
9586		this.clipIntersection = source.clipIntersection;
vendor: 7,363 bytes, lines 9587-9946
9587		this.clipShadows = source.clipShadows;
9588
9589		this.shadowSide = source.shadowSide;
9590
9591		this.colorWrite = source.colorWrite;
9592
9593		this.precision = source.precision;
9594
9595
9596		this.polygonOffset = source.polygonOffset;
9597		this.polygonOffsetFactor = source.polygonOffsetFactor;
9598		this.polygonOffsetUnits = source.polygonOffsetUnits;
9599
9600		this.dithering = source.dithering;
9601
9602		this.alphaTest = source.alphaTest;
9603		this.alphaHash = source.alphaHash;
9604		this.alphaToCoverage = source.alphaToCoverage;
9605		this.premultipliedAlpha = source.premultipliedAlpha;
9606		this.forceSinglePass = source.forceSinglePass;
9607
9608		this.visible = source.visible;
9609
9610		this.toneMapped = source.toneMapped;
9611
9612		this.userData = JSON.parse( JSON.stringify( source.userData ) );
9613
9614		return this;
9615
9616	}
9617
9618	dispose() {
9619
9620		this.dispatchEvent( { type: 'dispose' } );
9621
9622	}
9623
9624	set needsUpdate( value ) {
9625
9626		if ( value === true ) this.version ++;
9627
9628	}
9629
9630}
9631
9632class MeshBasicMaterial extends Material {
9633
9634	constructor( parameters ) {
9635
9636		super();
9637
9638		this.isMeshBasicMaterial = true;
9639
9640		this.type = 'MeshBasicMaterial';
9641
9642		this.color = new Color( 0xffffff ); // emissive
9643
9644		this.map = null;
9645
9646		this.lightMap = null;
9647		this.lightMapIntensity = 1.0;
9648
9649		this.aoMap = null;
9650		this.aoMapIntensity = 1.0;
9651
9652		this.specularMap = null;
9653
9654		this.alphaMap = null;
9655
9656		this.envMap = null;
9657		this.combine = MultiplyOperation;
9658		this.reflectivity = 1;
9659		this.refractionRatio = 0.98;
9660
9661		this.wireframe = false;
9662		this.wireframeLinewidth = 1;
9663		this.wireframeLinecap = 'round';
9664		this.wireframeLinejoin = 'round';
9665
9666		this.fog = true;
9667
9668		this.setValues( parameters );
9669
9670	}
9671
9672	copy( source ) {
9673
9674		super.copy( source );
9675
9676		this.color.copy( source.color );
9677
9678		this.map = source.map;
9679
9680		this.lightMap = source.lightMap;
9681		this.lightMapIntensity = source.lightMapIntensity;
9682
9683		this.aoMap = source.aoMap;
9684		this.aoMapIntensity = source.aoMapIntensity;
9685
9686		this.specularMap = source.specularMap;
9687
9688		this.alphaMap = source.alphaMap;
9689
9690		this.envMap = source.envMap;
9691		this.combine = source.combine;
9692		this.reflectivity = source.reflectivity;
9693		this.refractionRatio = source.refractionRatio;
9694
9695		this.wireframe = source.wireframe;
9696		this.wireframeLinewidth = source.wireframeLinewidth;
9697		this.wireframeLinecap = source.wireframeLinecap;
9698		this.wireframeLinejoin = source.wireframeLinejoin;
9699
9700		this.fog = source.fog;
9701
9702		return this;
9703
9704	}
9705
9706}
9707
9708// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
9709
9710const _tables = /*@__PURE__*/ _generateTables();
9711
9712function _generateTables() {
9713
9714	// float32 to float16 helpers
9715
9716	const buffer = new ArrayBuffer( 4 );
9717	const floatView = new Float32Array( buffer );
9718	const uint32View = new Uint32Array( buffer );
9719
9720	const baseTable = new Uint32Array( 512 );
9721	const shiftTable = new Uint32Array( 512 );
9722
9723	for ( let i = 0; i < 256; ++ i ) {
9724
9725		const e = i - 127;
9726
9727		// very small number (0, -0)
9728
9729		if ( e < - 27 ) {
9730
9731			baseTable[ i ] = 0x0000;
9732			baseTable[ i | 0x100 ] = 0x8000;
9733			shiftTable[ i ] = 24;
9734			shiftTable[ i | 0x100 ] = 24;
9735
9736			// small number (denorm)
9737
9738		} else if ( e < - 14 ) {
9739
9740			baseTable[ i ] = 0x0400 >> ( - e - 14 );
9741			baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;
9742			shiftTable[ i ] = - e - 1;
9743			shiftTable[ i | 0x100 ] = - e - 1;
9744
9745			// normal number
9746
9747		} else if ( e <= 15 ) {
9748
9749			baseTable[ i ] = ( e + 15 ) << 10;
9750			baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;
9751			shiftTable[ i ] = 13;
9752			shiftTable[ i | 0x100 ] = 13;
9753
9754			// large number (Infinity, -Infinity)
9755
9756		} else if ( e < 128 ) {
9757
9758			baseTable[ i ] = 0x7c00;
9759			baseTable[ i | 0x100 ] = 0xfc00;
9760			shiftTable[ i ] = 24;
9761			shiftTable[ i | 0x100 ] = 24;
9762
9763			// stay (NaN, Infinity, -Infinity)
9764
9765		} else {
9766
9767			baseTable[ i ] = 0x7c00;
9768			baseTable[ i | 0x100 ] = 0xfc00;
9769			shiftTable[ i ] = 13;
9770			shiftTable[ i | 0x100 ] = 13;
9771
9772		}
9773
9774	}
9775
9776	// float16 to float32 helpers
9777
9778	const mantissaTable = new Uint32Array( 2048 );
9779	const exponentTable = new Uint32Array( 64 );
9780	const offsetTable = new Uint32Array( 64 );
9781
9782	for ( let i = 1; i < 1024; ++ i ) {
9783
9784		let m = i << 13; // zero pad mantissa bits
9785		let e = 0; // zero exponent
9786
9787		// normalized
9788		while ( ( m & 0x00800000 ) === 0 ) {
9789
9790			m <<= 1;
9791			e -= 0x00800000; // decrement exponent
9792
9793		}
9794
9795		m &= ~ 0x00800000; // clear leading 1 bit
9796		e += 0x38800000; // adjust bias
9797
9798		mantissaTable[ i ] = m | e;
9799
9800	}
9801
9802	for ( let i = 1024; i < 2048; ++ i ) {
9803
9804		mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );
9805
9806	}
9807
9808	for ( let i = 1; i < 31; ++ i ) {
9809
9810		exponentTable[ i ] = i << 23;
9811
9812	}
9813
9814	exponentTable[ 31 ] = 0x47800000;
9815	exponentTable[ 32 ] = 0x80000000;
9816
9817	for ( let i = 33; i < 63; ++ i ) {
9818
9819		exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );
9820
9821	}
9822
9823	exponentTable[ 63 ] = 0xc7800000;
9824
9825	for ( let i = 1; i < 64; ++ i ) {
9826
9827		if ( i !== 32 ) {
9828
9829			offsetTable[ i ] = 1024;
9830
9831		}
9832
9833	}
9834
9835	return {
9836		floatView: floatView,
9837		uint32View: uint32View,
9838		baseTable: baseTable,
9839		shiftTable: shiftTable,
9840		mantissaTable: mantissaTable,
9841		exponentTable: exponentTable,
9842		offsetTable: offsetTable
9843	};
9844
9845}
9846
9847// float32 to float16
9848
9849function toHalfFloat( val ) {
9850
9851	if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );
9852
9853	val = clamp( val, - 65504, 65504 );
9854
9855	_tables.floatView[ 0 ] = val;
9856	const f = _tables.uint32View[ 0 ];
9857	const e = ( f >> 23 ) & 0x1ff;
9858	return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );
9859
9860}
9861
9862// float16 to float32
9863
9864function fromHalfFloat( val ) {
9865
9866	const m = val >> 10;
9867	_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];
9868	return _tables.floatView[ 0 ];
9869
9870}
9871
9872const DataUtils = {
9873	toHalfFloat: toHalfFloat,
9874	fromHalfFloat: fromHalfFloat,
9875};
9876
9877const _vector$9 = /*@__PURE__*/ new Vector3();
9878const _vector2$1 = /*@__PURE__*/ new Vector2();
9879
9880class BufferAttribute {
9881
9882	constructor( array, itemSize, normalized = false ) {
9883
9884		if ( Array.isArray( array ) ) {
9885
9886			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
9887
9888		}
9889
9890		this.isBufferAttribute = true;
9891
9892		this.name = '';
9893
9894		this.array = array;
9895		this.itemSize = itemSize;
9896		this.count = array !== undefined ? array.length / itemSize : 0;
9897		this.normalized = normalized;
9898
9899		this.usage = StaticDrawUsage;
9900		this._updateRange = { offset: 0, count: - 1 };
9901		this.updateRanges = [];
9902		this.gpuType = FloatType;
9903
9904		this.version = 0;
9905
9906	}
9907
9908	onUploadCallback() {}
9909
9910	set needsUpdate( value ) {
9911
9912		if ( value === true ) this.version ++;
9913
9914	}
9915
9916	get updateRange() {
9917
9918		console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
9919		return this._updateRange;
9920
9921	}
9922
9923	setUsage( value ) {
9924
9925		this.usage = value;
9926
9927		return this;
9928
9929	}
9930
9931	addUpdateRange( start, count ) {
9932
9933		this.updateRanges.push( { start, count } );
9934
9935	}
9936
9937	clearUpdateRanges() {
9938
9939		this.updateRanges.length = 0;
9940
9941	}
9942
9943	copy( source ) {
9944
9945		this.name = source.name;
9946		this.array = new source.array.constructor( source.array );
vendor: 9,812 bytes, lines 9947-10513
9947		this.itemSize = source.itemSize;
9948		this.count = source.count;
9949		this.normalized = source.normalized;
9950
9951		this.usage = source.usage;
9952		this.gpuType = source.gpuType;
9953
9954		return this;
9955
9956	}
9957
9958	copyAt( index1, attribute, index2 ) {
9959
9960		index1 *= this.itemSize;
9961		index2 *= attribute.itemSize;
9962
9963		for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
9964
9965			this.array[ index1 + i ] = attribute.array[ index2 + i ];
9966
9967		}
9968
9969		return this;
9970
9971	}
9972
9973	copyArray( array ) {
9974
9975		this.array.set( array );
9976
9977		return this;
9978
9979	}
9980
9981	applyMatrix3( m ) {
9982
9983		if ( this.itemSize === 2 ) {
9984
9985			for ( let i = 0, l = this.count; i < l; i ++ ) {
9986
9987				_vector2$1.fromBufferAttribute( this, i );
9988				_vector2$1.applyMatrix3( m );
9989
9990				this.setXY( i, _vector2$1.x, _vector2$1.y );
9991
9992			}
9993
9994		} else if ( this.itemSize === 3 ) {
9995
9996			for ( let i = 0, l = this.count; i < l; i ++ ) {
9997
9998				_vector$9.fromBufferAttribute( this, i );
9999				_vector$9.applyMatrix3( m );
10000
10001				this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10002
10003			}
10004
10005		}
10006
10007		return this;
10008
10009	}
10010
10011	applyMatrix4( m ) {
10012
10013		for ( let i = 0, l = this.count; i < l; i ++ ) {
10014
10015			_vector$9.fromBufferAttribute( this, i );
10016
10017			_vector$9.applyMatrix4( m );
10018
10019			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10020
10021		}
10022
10023		return this;
10024
10025	}
10026
10027	applyNormalMatrix( m ) {
10028
10029		for ( let i = 0, l = this.count; i < l; i ++ ) {
10030
10031			_vector$9.fromBufferAttribute( this, i );
10032
10033			_vector$9.applyNormalMatrix( m );
10034
10035			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10036
10037		}
10038
10039		return this;
10040
10041	}
10042
10043	transformDirection( m ) {
10044
10045		for ( let i = 0, l = this.count; i < l; i ++ ) {
10046
10047			_vector$9.fromBufferAttribute( this, i );
10048
10049			_vector$9.transformDirection( m );
10050
10051			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10052
10053		}
10054
10055		return this;
10056
10057	}
10058
10059	set( value, offset = 0 ) {
10060
10061		// Matching BufferAttribute constructor, do not normalize the array.
10062		this.array.set( value, offset );
10063
10064		return this;
10065
10066	}
10067
10068	getComponent( index, component ) {
10069
10070		let value = this.array[ index * this.itemSize + component ];
10071
10072		if ( this.normalized ) value = denormalize( value, this.array );
10073
10074		return value;
10075
10076	}
10077
10078	setComponent( index, component, value ) {
10079
10080		if ( this.normalized ) value = normalize( value, this.array );
10081
10082		this.array[ index * this.itemSize + component ] = value;
10083
10084		return this;
10085
10086	}
10087
10088	getX( index ) {
10089
10090		let x = this.array[ index * this.itemSize ];
10091
10092		if ( this.normalized ) x = denormalize( x, this.array );
10093
10094		return x;
10095
10096	}
10097
10098	setX( index, x ) {
10099
10100		if ( this.normalized ) x = normalize( x, this.array );
10101
10102		this.array[ index * this.itemSize ] = x;
10103
10104		return this;
10105
10106	}
10107
10108	getY( index ) {
10109
10110		let y = this.array[ index * this.itemSize + 1 ];
10111
10112		if ( this.normalized ) y = denormalize( y, this.array );
10113
10114		return y;
10115
10116	}
10117
10118	setY( index, y ) {
10119
10120		if ( this.normalized ) y = normalize( y, this.array );
10121
10122		this.array[ index * this.itemSize + 1 ] = y;
10123
10124		return this;
10125
10126	}
10127
10128	getZ( index ) {
10129
10130		let z = this.array[ index * this.itemSize + 2 ];
10131
10132		if ( this.normalized ) z = denormalize( z, this.array );
10133
10134		return z;
10135
10136	}
10137
10138	setZ( index, z ) {
10139
10140		if ( this.normalized ) z = normalize( z, this.array );
10141
10142		this.array[ index * this.itemSize + 2 ] = z;
10143
10144		return this;
10145
10146	}
10147
10148	getW( index ) {
10149
10150		let w = this.array[ index * this.itemSize + 3 ];
10151
10152		if ( this.normalized ) w = denormalize( w, this.array );
10153
10154		return w;
10155
10156	}
10157
10158	setW( index, w ) {
10159
10160		if ( this.normalized ) w = normalize( w, this.array );
10161
10162		this.array[ index * this.itemSize + 3 ] = w;
10163
10164		return this;
10165
10166	}
10167
10168	setXY( index, x, y ) {
10169
10170		index *= this.itemSize;
10171
10172		if ( this.normalized ) {
10173
10174			x = normalize( x, this.array );
10175			y = normalize( y, this.array );
10176
10177		}
10178
10179		this.array[ index + 0 ] = x;
10180		this.array[ index + 1 ] = y;
10181
10182		return this;
10183
10184	}
10185
10186	setXYZ( index, x, y, z ) {
10187
10188		index *= this.itemSize;
10189
10190		if ( this.normalized ) {
10191
10192			x = normalize( x, this.array );
10193			y = normalize( y, this.array );
10194			z = normalize( z, this.array );
10195
10196		}
10197
10198		this.array[ index + 0 ] = x;
10199		this.array[ index + 1 ] = y;
10200		this.array[ index + 2 ] = z;
10201
10202		return this;
10203
10204	}
10205
10206	setXYZW( index, x, y, z, w ) {
10207
10208		index *= this.itemSize;
10209
10210		if ( this.normalized ) {
10211
10212			x = normalize( x, this.array );
10213			y = normalize( y, this.array );
10214			z = normalize( z, this.array );
10215			w = normalize( w, this.array );
10216
10217		}
10218
10219		this.array[ index + 0 ] = x;
10220		this.array[ index + 1 ] = y;
10221		this.array[ index + 2 ] = z;
10222		this.array[ index + 3 ] = w;
10223
10224		return this;
10225
10226	}
10227
10228	onUpload( callback ) {
10229
10230		this.onUploadCallback = callback;
10231
10232		return this;
10233
10234	}
10235
10236	clone() {
10237
10238		return new this.constructor( this.array, this.itemSize ).copy( this );
10239
10240	}
10241
10242	toJSON() {
10243
10244		const data = {
10245			itemSize: this.itemSize,
10246			type: this.array.constructor.name,
10247			array: Array.from( this.array ),
10248			normalized: this.normalized
10249		};
10250
10251		if ( this.name !== '' ) data.name = this.name;
10252		if ( this.usage !== StaticDrawUsage ) data.usage = this.usage;
10253
10254		return data;
10255
10256	}
10257
10258}
10259
10260//
10261
10262class Int8BufferAttribute extends BufferAttribute {
10263
10264	constructor( array, itemSize, normalized ) {
10265
10266		super( new Int8Array( array ), itemSize, normalized );
10267
10268	}
10269
10270}
10271
10272class Uint8BufferAttribute extends BufferAttribute {
10273
10274	constructor( array, itemSize, normalized ) {
10275
10276		super( new Uint8Array( array ), itemSize, normalized );
10277
10278	}
10279
10280}
10281
10282class Uint8ClampedBufferAttribute extends BufferAttribute {
10283
10284	constructor( array, itemSize, normalized ) {
10285
10286		super( new Uint8ClampedArray( array ), itemSize, normalized );
10287
10288	}
10289
10290}
10291
10292class Int16BufferAttribute extends BufferAttribute {
10293
10294	constructor( array, itemSize, normalized ) {
10295
10296		super( new Int16Array( array ), itemSize, normalized );
10297
10298	}
10299
10300}
10301
10302class Uint16BufferAttribute extends BufferAttribute {
10303
10304	constructor( array, itemSize, normalized ) {
10305
10306		super( new Uint16Array( array ), itemSize, normalized );
10307
10308	}
10309
10310}
10311
10312class Int32BufferAttribute extends BufferAttribute {
10313
10314	constructor( array, itemSize, normalized ) {
10315
10316		super( new Int32Array( array ), itemSize, normalized );
10317
10318	}
10319
10320}
10321
10322class Uint32BufferAttribute extends BufferAttribute {
10323
10324	constructor( array, itemSize, normalized ) {
10325
10326		super( new Uint32Array( array ), itemSize, normalized );
10327
10328	}
10329
10330}
10331
10332class Float16BufferAttribute extends BufferAttribute {
10333
10334	constructor( array, itemSize, normalized ) {
10335
10336		super( new Uint16Array( array ), itemSize, normalized );
10337
10338		this.isFloat16BufferAttribute = true;
10339
10340	}
10341
10342	getX( index ) {
10343
10344		let x = fromHalfFloat( this.array[ index * this.itemSize ] );
10345
10346		if ( this.normalized ) x = denormalize( x, this.array );
10347
10348		return x;
10349
10350	}
10351
10352	setX( index, x ) {
10353
10354		if ( this.normalized ) x = normalize( x, this.array );
10355
10356		this.array[ index * this.itemSize ] = toHalfFloat( x );
10357
10358		return this;
10359
10360	}
10361
10362	getY( index ) {
10363
10364		let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );
10365
10366		if ( this.normalized ) y = denormalize( y, this.array );
10367
10368		return y;
10369
10370	}
10371
10372	setY( index, y ) {
10373
10374		if ( this.normalized ) y = normalize( y, this.array );
10375
10376		this.array[ index * this.itemSize + 1 ] = toHalfFloat( y );
10377
10378		return this;
10379
10380	}
10381
10382	getZ( index ) {
10383
10384		let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );
10385
10386		if ( this.normalized ) z = denormalize( z, this.array );
10387
10388		return z;
10389
10390	}
10391
10392	setZ( index, z ) {
10393
10394		if ( this.normalized ) z = normalize( z, this.array );
10395
10396		this.array[ index * this.itemSize + 2 ] = toHalfFloat( z );
10397
10398		return this;
10399
10400	}
10401
10402	getW( index ) {
10403
10404		let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );
10405
10406		if ( this.normalized ) w = denormalize( w, this.array );
10407
10408		return w;
10409
10410	}
10411
10412	setW( index, w ) {
10413
10414		if ( this.normalized ) w = normalize( w, this.array );
10415
10416		this.array[ index * this.itemSize + 3 ] = toHalfFloat( w );
10417
10418		return this;
10419
10420	}
10421
10422	setXY( index, x, y ) {
10423
10424		index *= this.itemSize;
10425
10426		if ( this.normalized ) {
10427
10428			x = normalize( x, this.array );
10429			y = normalize( y, this.array );
10430
10431		}
10432
10433		this.array[ index + 0 ] = toHalfFloat( x );
10434		this.array[ index + 1 ] = toHalfFloat( y );
10435
10436		return this;
10437
10438	}
10439
10440	setXYZ( index, x, y, z ) {
10441
10442		index *= this.itemSize;
10443
10444		if ( this.normalized ) {
10445
10446			x = normalize( x, this.array );
10447			y = normalize( y, this.array );
10448			z = normalize( z, this.array );
10449
10450		}
10451
10452		this.array[ index + 0 ] = toHalfFloat( x );
10453		this.array[ index + 1 ] = toHalfFloat( y );
10454		this.array[ index + 2 ] = toHalfFloat( z );
10455
10456		return this;
10457
10458	}
10459
10460	setXYZW( index, x, y, z, w ) {
10461
10462		index *= this.itemSize;
10463
10464		if ( this.normalized ) {
10465
10466			x = normalize( x, this.array );
10467			y = normalize( y, this.array );
10468			z = normalize( z, this.array );
10469			w = normalize( w, this.array );
10470
10471		}
10472
10473		this.array[ index + 0 ] = toHalfFloat( x );
10474		this.array[ index + 1 ] = toHalfFloat( y );
10475		this.array[ index + 2 ] = toHalfFloat( z );
10476		this.array[ index + 3 ] = toHalfFloat( w );
10477
10478		return this;
10479
10480	}
10481
10482}
10483
10484
10485class Float32BufferAttribute extends BufferAttribute {
10486
10487	constructor( array, itemSize, normalized ) {
10488
10489		super( new Float32Array( array ), itemSize, normalized );
10490
10491	}
10492
10493}
10494
10495class Float64BufferAttribute extends BufferAttribute {
10496
10497	constructor( array, itemSize, normalized ) {
10498
10499		super( new Float64Array( array ), itemSize, normalized );
10500
10501	}
10502
10503}
10504
10505let _id$2 = 0;
10506
10507const _m1 = /*@__PURE__*/ new Matrix4();
10508const _obj = /*@__PURE__*/ new Object3D();
10509const _offset = /*@__PURE__*/ new Vector3();
10510const _box$2 = /*@__PURE__*/ new Box3();
10511const _boxMorphTargets = /*@__PURE__*/ new Box3();
10512const _vector$8 = /*@__PURE__*/ new Vector3();
10513
vendor: 6,038 bytes, lines 10514-10865
10514class BufferGeometry extends EventDispatcher {
10515
10516	constructor() {
10517
10518		super();
10519
10520		this.isBufferGeometry = true;
10521
10522		Object.defineProperty( this, 'id', { value: _id$2 ++ } );
10523
10524		this.uuid = generateUUID();
10525
10526		this.name = '';
10527		this.type = 'BufferGeometry';
10528
10529		this.index = null;
10530		this.attributes = {};
10531
10532		this.morphAttributes = {};
10533		this.morphTargetsRelative = false;
10534
10535		this.groups = [];
10536
10537		this.boundingBox = null;
10538		this.boundingSphere = null;
10539
10540		this.drawRange = { start: 0, count: Infinity };
10541
10542		this.userData = {};
10543
10544	}
10545
10546	getIndex() {
10547
10548		return this.index;
10549
10550	}
10551
10552	setIndex( index ) {
10553
10554		if ( Array.isArray( index ) ) {
10555
10556			this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
10557
10558		} else {
10559
10560			this.index = index;
10561
10562		}
10563
10564		return this;
10565
10566	}
10567
10568	getAttribute( name ) {
10569
10570		return this.attributes[ name ];
10571
10572	}
10573
10574	setAttribute( name, attribute ) {
10575
10576		this.attributes[ name ] = attribute;
10577
10578		return this;
10579
10580	}
10581
10582	deleteAttribute( name ) {
10583
10584		delete this.attributes[ name ];
10585
10586		return this;
10587
10588	}
10589
10590	hasAttribute( name ) {
10591
10592		return this.attributes[ name ] !== undefined;
10593
10594	}
10595
10596	addGroup( start, count, materialIndex = 0 ) {
10597
10598		this.groups.push( {
10599
10600			start: start,
10601			count: count,
10602			materialIndex: materialIndex
10603
10604		} );
10605
10606	}
10607
10608	clearGroups() {
10609
10610		this.groups = [];
10611
10612	}
10613
10614	setDrawRange( start, count ) {
10615
10616		this.drawRange.start = start;
10617		this.drawRange.count = count;
10618
10619	}
10620
10621	applyMatrix4( matrix ) {
10622
10623		const position = this.attributes.position;
10624
10625		if ( position !== undefined ) {
10626
10627			position.applyMatrix4( matrix );
10628
10629			position.needsUpdate = true;
10630
10631		}
10632
10633		const normal = this.attributes.normal;
10634
10635		if ( normal !== undefined ) {
10636
10637			const normalMatrix = new Matrix3().getNormalMatrix( matrix );
10638
10639			normal.applyNormalMatrix( normalMatrix );
10640
10641			normal.needsUpdate = true;
10642
10643		}
10644
10645		const tangent = this.attributes.tangent;
10646
10647		if ( tangent !== undefined ) {
10648
10649			tangent.transformDirection( matrix );
10650
10651			tangent.needsUpdate = true;
10652
10653		}
10654
10655		if ( this.boundingBox !== null ) {
10656
10657			this.computeBoundingBox();
10658
10659		}
10660
10661		if ( this.boundingSphere !== null ) {
10662
10663			this.computeBoundingSphere();
10664
10665		}
10666
10667		return this;
10668
10669	}
10670
10671	applyQuaternion( q ) {
10672
10673		_m1.makeRotationFromQuaternion( q );
10674
10675		this.applyMatrix4( _m1 );
10676
10677		return this;
10678
10679	}
10680
10681	rotateX( angle ) {
10682
10683		// rotate geometry around world x-axis
10684
10685		_m1.makeRotationX( angle );
10686
10687		this.applyMatrix4( _m1 );
10688
10689		return this;
10690
10691	}
10692
10693	rotateY( angle ) {
10694
10695		// rotate geometry around world y-axis
10696
10697		_m1.makeRotationY( angle );
10698
10699		this.applyMatrix4( _m1 );
10700
10701		return this;
10702
10703	}
10704
10705	rotateZ( angle ) {
10706
10707		// rotate geometry around world z-axis
10708
10709		_m1.makeRotationZ( angle );
10710
10711		this.applyMatrix4( _m1 );
10712
10713		return this;
10714
10715	}
10716
10717	translate( x, y, z ) {
10718
10719		// translate geometry
10720
10721		_m1.makeTranslation( x, y, z );
10722
10723		this.applyMatrix4( _m1 );
10724
10725		return this;
10726
10727	}
10728
10729	scale( x, y, z ) {
10730
10731		// scale geometry
10732
10733		_m1.makeScale( x, y, z );
10734
10735		this.applyMatrix4( _m1 );
10736
10737		return this;
10738
10739	}
10740
10741	lookAt( vector ) {
10742
10743		_obj.lookAt( vector );
10744
10745		_obj.updateMatrix();
10746
10747		this.applyMatrix4( _obj.matrix );
10748
10749		return this;
10750
10751	}
10752
10753	center() {
10754
10755		this.computeBoundingBox();
10756
10757		this.boundingBox.getCenter( _offset ).negate();
10758
10759		this.translate( _offset.x, _offset.y, _offset.z );
10760
10761		return this;
10762
10763	}
10764
10765	setFromPoints( points ) {
10766
10767		const position = [];
10768
10769		for ( let i = 0, l = points.length; i < l; i ++ ) {
10770
10771			const point = points[ i ];
10772			position.push( point.x, point.y, point.z || 0 );
10773
10774		}
10775
10776		this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
10777
10778		return this;
10779
10780	}
10781
10782	computeBoundingBox() {
10783
10784		if ( this.boundingBox === null ) {
10785
10786			this.boundingBox = new Box3();
10787
10788		}
10789
10790		const position = this.attributes.position;
10791		const morphAttributesPosition = this.morphAttributes.position;
10792
10793		if ( position && position.isGLBufferAttribute ) {
10794
10795			console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
10796
10797			this.boundingBox.set(
10798				new Vector3( - Infinity, - Infinity, - Infinity ),
10799				new Vector3( + Infinity, + Infinity, + Infinity )
10800			);
10801
10802			return;
10803
10804		}
10805
10806		if ( position !== undefined ) {
10807
10808			this.boundingBox.setFromBufferAttribute( position );
10809
10810			// process morph attributes if present
10811
10812			if ( morphAttributesPosition ) {
10813
10814				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10815
10816					const morphAttribute = morphAttributesPosition[ i ];
10817					_box$2.setFromBufferAttribute( morphAttribute );
10818
10819					if ( this.morphTargetsRelative ) {
10820
10821						_vector$8.addVectors( this.boundingBox.min, _box$2.min );
10822						this.boundingBox.expandByPoint( _vector$8 );
10823
10824						_vector$8.addVectors( this.boundingBox.max, _box$2.max );
10825						this.boundingBox.expandByPoint( _vector$8 );
10826
10827					} else {
10828
10829						this.boundingBox.expandByPoint( _box$2.min );
10830						this.boundingBox.expandByPoint( _box$2.max );
10831
10832					}
10833
10834				}
10835
10836			}
10837
10838		} else {
10839
10840			this.boundingBox.makeEmpty();
10841
10842		}
10843
10844		if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
10845
10846			console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
10847
10848		}
10849
10850	}
10851
10852	computeBoundingSphere() {
10853
10854		if ( this.boundingSphere === null ) {
10855
10856			this.boundingSphere = new Sphere();
10857
10858		}
10859
10860		const position = this.attributes.position;
10861		const morphAttributesPosition = this.morphAttributes.position;
10862
10863		if ( position && position.isGLBufferAttribute ) {
10864
10865			console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "fal
vendor: 5,245 bytes, lines 10865-11093
10865se".', this );
10866
10867			this.boundingSphere.set( new Vector3(), Infinity );
10868
10869			return;
10870
10871		}
10872
10873		if ( position ) {
10874
10875			// first, find the center of the bounding sphere
10876
10877			const center = this.boundingSphere.center;
10878
10879			_box$2.setFromBufferAttribute( position );
10880
10881			// process morph attributes if present
10882
10883			if ( morphAttributesPosition ) {
10884
10885				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10886
10887					const morphAttribute = morphAttributesPosition[ i ];
10888					_boxMorphTargets.setFromBufferAttribute( morphAttribute );
10889
10890					if ( this.morphTargetsRelative ) {
10891
10892						_vector$8.addVectors( _box$2.min, _boxMorphTargets.min );
10893						_box$2.expandByPoint( _vector$8 );
10894
10895						_vector$8.addVectors( _box$2.max, _boxMorphTargets.max );
10896						_box$2.expandByPoint( _vector$8 );
10897
10898					} else {
10899
10900						_box$2.expandByPoint( _boxMorphTargets.min );
10901						_box$2.expandByPoint( _boxMorphTargets.max );
10902
10903					}
10904
10905				}
10906
10907			}
10908
10909			_box$2.getCenter( center );
10910
10911			// second, try to find a boundingSphere with a radius smaller than the
10912			// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
10913
10914			let maxRadiusSq = 0;
10915
10916			for ( let i = 0, il = position.count; i < il; i ++ ) {
10917
10918				_vector$8.fromBufferAttribute( position, i );
10919
10920				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10921
10922			}
10923
10924			// process morph attributes if present
10925
10926			if ( morphAttributesPosition ) {
10927
10928				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10929
10930					const morphAttribute = morphAttributesPosition[ i ];
10931					const morphTargetsRelative = this.morphTargetsRelative;
10932
10933					for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
10934
10935						_vector$8.fromBufferAttribute( morphAttribute, j );
10936
10937						if ( morphTargetsRelative ) {
10938
10939							_offset.fromBufferAttribute( position, j );
10940							_vector$8.add( _offset );
10941
10942						}
10943
10944						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10945
10946					}
10947
10948				}
10949
10950			}
10951
10952			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
10953
10954			if ( isNaN( this.boundingSphere.radius ) ) {
10955
10956				console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
10957
10958			}
10959
10960		}
10961
10962	}
10963
10964	computeTangents() {
10965
10966		const index = this.index;
10967		const attributes = this.attributes;
10968
10969		// based on http://www.terathon.com/code/tangent.html
10970		// (per vertex tangents)
10971
10972		if ( index === null ||
10973			 attributes.position === undefined ||
10974			 attributes.normal === undefined ||
10975			 attributes.uv === undefined ) {
10976
10977			console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
10978			return;
10979
10980		}
10981
10982		const indices = index.array;
10983		const positions = attributes.position.array;
10984		const normals = attributes.normal.array;
10985		const uvs = attributes.uv.array;
10986
10987		const nVertices = positions.length / 3;
10988
10989		if ( this.hasAttribute( 'tangent' ) === false ) {
10990
10991			this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
10992
10993		}
10994
10995		const tangents = this.getAttribute( 'tangent' ).array;
10996
10997		const tan1 = [], tan2 = [];
10998
10999		for ( let i = 0; i < nVertices; i ++ ) {
11000
11001			tan1[ i ] = new Vector3();
11002			tan2[ i ] = new Vector3();
11003
11004		}
11005
11006		const vA = new Vector3(),
11007			vB = new Vector3(),
11008			vC = new Vector3(),
11009
11010			uvA = new Vector2(),
11011			uvB = new Vector2(),
11012			uvC = new Vector2(),
11013
11014			sdir = new Vector3(),
11015			tdir = new Vector3();
11016
11017		function handleTriangle( a, b, c ) {
11018
11019			vA.fromArray( positions, a * 3 );
11020			vB.fromArray( positions, b * 3 );
11021			vC.fromArray( positions, c * 3 );
11022
11023			uvA.fromArray( uvs, a * 2 );
11024			uvB.fromArray( uvs, b * 2 );
11025			uvC.fromArray( uvs, c * 2 );
11026
11027			vB.sub( vA );
11028			vC.sub( vA );
11029
11030			uvB.sub( uvA );
11031			uvC.sub( uvA );
11032
11033			const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
11034
11035			// silently ignore degenerate uv triangles having coincident or colinear vertices
11036
11037			if ( ! isFinite( r ) ) return;
11038
11039			sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
11040			tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
11041
11042			tan1[ a ].add( sdir );
11043			tan1[ b ].add( sdir );
11044			tan1[ c ].add( sdir );
11045
11046			tan2[ a ].add( tdir );
11047			tan2[ b ].add( tdir );
11048			tan2[ c ].add( tdir );
11049
11050		}
11051
11052		let groups = this.groups;
11053
11054		if ( groups.length === 0 ) {
11055
11056			groups = [ {
11057				start: 0,
11058				count: indices.length
11059			} ];
11060
11061		}
11062
11063		for ( let i = 0, il = groups.length; i < il; ++ i ) {
11064
11065			const group = groups[ i ];
11066
11067			const start = group.start;
11068			const count = group.count;
11069
11070			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11071
11072				handleTriangle(
11073					indices[ j + 0 ],
11074					indices[ j + 1 ],
11075					indices[ j + 2 ]
11076				);
11077
11078			}
11079
11080		}
11081
11082		const tmp = new Vector3(), tmp2 = new Vector3();
11083		const n = new Vector3(), n2 = new Vector3();
11084
11085		function handleVertex( v ) {
11086
11087			n.fromArray( normals, v * 3 );
11088			n2.copy( n );
11089
11090			const t = tan1[ v ];
11091
11092			// Gram-Schmidt orthogonalize
11093
vendor: 4,805 bytes, lines 11094-11305
11094			tmp.copy( t );
11095			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
11096
11097			// Calculate handedness
11098
11099			tmp2.crossVectors( n2, t );
11100			const test = tmp2.dot( tan2[ v ] );
11101			const w = ( test < 0.0 ) ? - 1.0 : 1.0;
11102
11103			tangents[ v * 4 ] = tmp.x;
11104			tangents[ v * 4 + 1 ] = tmp.y;
11105			tangents[ v * 4 + 2 ] = tmp.z;
11106			tangents[ v * 4 + 3 ] = w;
11107
11108		}
11109
11110		for ( let i = 0, il = groups.length; i < il; ++ i ) {
11111
11112			const group = groups[ i ];
11113
11114			const start = group.start;
11115			const count = group.count;
11116
11117			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11118
11119				handleVertex( indices[ j + 0 ] );
11120				handleVertex( indices[ j + 1 ] );
11121				handleVertex( indices[ j + 2 ] );
11122
11123			}
11124
11125		}
11126
11127	}
11128
11129	computeVertexNormals() {
11130
11131		const index = this.index;
11132		const positionAttribute = this.getAttribute( 'position' );
11133
11134		if ( positionAttribute !== undefined ) {
11135
11136			let normalAttribute = this.getAttribute( 'normal' );
11137
11138			if ( normalAttribute === undefined ) {
11139
11140				normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
11141				this.setAttribute( 'normal', normalAttribute );
11142
11143			} else {
11144
11145				// reset existing normals to zero
11146
11147				for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
11148
11149					normalAttribute.setXYZ( i, 0, 0, 0 );
11150
11151				}
11152
11153			}
11154
11155			const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
11156			const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
11157			const cb = new Vector3(), ab = new Vector3();
11158
11159			// indexed elements
11160
11161			if ( index ) {
11162
11163				for ( let i = 0, il = index.count; i < il; i += 3 ) {
11164
11165					const vA = index.getX( i + 0 );
11166					const vB = index.getX( i + 1 );
11167					const vC = index.getX( i + 2 );
11168
11169					pA.fromBufferAttribute( positionAttribute, vA );
11170					pB.fromBufferAttribute( positionAttribute, vB );
11171					pC.fromBufferAttribute( positionAttribute, vC );
11172
11173					cb.subVectors( pC, pB );
11174					ab.subVectors( pA, pB );
11175					cb.cross( ab );
11176
11177					nA.fromBufferAttribute( normalAttribute, vA );
11178					nB.fromBufferAttribute( normalAttribute, vB );
11179					nC.fromBufferAttribute( normalAttribute, vC );
11180
11181					nA.add( cb );
11182					nB.add( cb );
11183					nC.add( cb );
11184
11185					normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
11186					normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
11187					normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
11188
11189				}
11190
11191			} else {
11192
11193				// non-indexed elements (unconnected triangle soup)
11194
11195				for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
11196
11197					pA.fromBufferAttribute( positionAttribute, i + 0 );
11198					pB.fromBufferAttribute( positionAttribute, i + 1 );
11199					pC.fromBufferAttribute( positionAttribute, i + 2 );
11200
11201					cb.subVectors( pC, pB );
11202					ab.subVectors( pA, pB );
11203					cb.cross( ab );
11204
11205					normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
11206					normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
11207					normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
11208
11209				}
11210
11211			}
11212
11213			this.normalizeNormals();
11214
11215			normalAttribute.needsUpdate = true;
11216
11217		}
11218
11219	}
11220
11221	normalizeNormals() {
11222
11223		const normals = this.attributes.normal;
11224
11225		for ( let i = 0, il = normals.count; i < il; i ++ ) {
11226
11227			_vector$8.fromBufferAttribute( normals, i );
11228
11229			_vector$8.normalize();
11230
11231			normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );
11232
11233		}
11234
11235	}
11236
11237	toNonIndexed() {
11238
11239		function convertBufferAttribute( attribute, indices ) {
11240
11241			const array = attribute.array;
11242			const itemSize = attribute.itemSize;
11243			const normalized = attribute.normalized;
11244
11245			const array2 = new array.constructor( indices.length * itemSize );
11246
11247			let index = 0, index2 = 0;
11248
11249			for ( let i = 0, l = indices.length; i < l; i ++ ) {
11250
11251				if ( attribute.isInterleavedBufferAttribute ) {
11252
11253					index = indices[ i ] * attribute.data.stride + attribute.offset;
11254
11255				} else {
11256
11257					index = indices[ i ] * itemSize;
11258
11259				}
11260
11261				for ( let j = 0; j < itemSize; j ++ ) {
11262
11263					array2[ index2 ++ ] = array[ index ++ ];
11264
11265				}
11266
11267			}
11268
11269			return new BufferAttribute( array2, itemSize, normalized );
11270
11271		}
11272
11273		//
11274
11275		if ( this.index === null ) {
11276
11277			console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
11278			return this;
11279
11280		}
11281
11282		const geometry2 = new BufferGeometry();
11283
11284		const indices = this.index.array;
11285		const attributes = this.attributes;
11286
11287		// attributes
11288
11289		for ( const name in attributes ) {
11290
11291			const attribute = attributes[ name ];
11292
11293			const newAttribute = convertBufferAttribute( attribute, indices );
11294
11295			geometry2.setAttribute( name, newAttribute );
11296
11297		}
11298
11299		// morph attributes
11300
11301		const morphAttributes = this.morphAttributes;
11302
11303		for ( const name in morphAttributes ) {
11304
11305			const morphArray = [];
vendor: 8,310 bytes, lines 11306-11716
11306			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11307
11308			for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
11309
11310				const attribute = morphAttribute[ i ];
11311
11312				const newAttribute = convertBufferAttribute( attribute, indices );
11313
11314				morphArray.push( newAttribute );
11315
11316			}
11317
11318			geometry2.morphAttributes[ name ] = morphArray;
11319
11320		}
11321
11322		geometry2.morphTargetsRelative = this.morphTargetsRelative;
11323
11324		// groups
11325
11326		const groups = this.groups;
11327
11328		for ( let i = 0, l = groups.length; i < l; i ++ ) {
11329
11330			const group = groups[ i ];
11331			geometry2.addGroup( group.start, group.count, group.materialIndex );
11332
11333		}
11334
11335		return geometry2;
11336
11337	}
11338
11339	toJSON() {
11340
11341		const data = {
11342			metadata: {
11343				version: 4.6,
11344				type: 'BufferGeometry',
11345				generator: 'BufferGeometry.toJSON'
11346			}
11347		};
11348
11349		// standard BufferGeometry serialization
11350
11351		data.uuid = this.uuid;
11352		data.type = this.type;
11353		if ( this.name !== '' ) data.name = this.name;
11354		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
11355
11356		if ( this.parameters !== undefined ) {
11357
11358			const parameters = this.parameters;
11359
11360			for ( const key in parameters ) {
11361
11362				if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
11363
11364			}
11365
11366			return data;
11367
11368		}
11369
11370		// for simplicity the code assumes attributes are not shared across geometries, see #15811
11371
11372		data.data = { attributes: {} };
11373
11374		const index = this.index;
11375
11376		if ( index !== null ) {
11377
11378			data.data.index = {
11379				type: index.array.constructor.name,
11380				array: Array.prototype.slice.call( index.array )
11381			};
11382
11383		}
11384
11385		const attributes = this.attributes;
11386
11387		for ( const key in attributes ) {
11388
11389			const attribute = attributes[ key ];
11390
11391			data.data.attributes[ key ] = attribute.toJSON( data.data );
11392
11393		}
11394
11395		const morphAttributes = {};
11396		let hasMorphAttributes = false;
11397
11398		for ( const key in this.morphAttributes ) {
11399
11400			const attributeArray = this.morphAttributes[ key ];
11401
11402			const array = [];
11403
11404			for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
11405
11406				const attribute = attributeArray[ i ];
11407
11408				array.push( attribute.toJSON( data.data ) );
11409
11410			}
11411
11412			if ( array.length > 0 ) {
11413
11414				morphAttributes[ key ] = array;
11415
11416				hasMorphAttributes = true;
11417
11418			}
11419
11420		}
11421
11422		if ( hasMorphAttributes ) {
11423
11424			data.data.morphAttributes = morphAttributes;
11425			data.data.morphTargetsRelative = this.morphTargetsRelative;
11426
11427		}
11428
11429		const groups = this.groups;
11430
11431		if ( groups.length > 0 ) {
11432
11433			data.data.groups = JSON.parse( JSON.stringify( groups ) );
11434
11435		}
11436
11437		const boundingSphere = this.boundingSphere;
11438
11439		if ( boundingSphere !== null ) {
11440
11441			data.data.boundingSphere = {
11442				center: boundingSphere.center.toArray(),
11443				radius: boundingSphere.radius
11444			};
11445
11446		}
11447
11448		return data;
11449
11450	}
11451
11452	clone() {
11453
11454		return new this.constructor().copy( this );
11455
11456	}
11457
11458	copy( source ) {
11459
11460		// reset
11461
11462		this.index = null;
11463		this.attributes = {};
11464		this.morphAttributes = {};
11465		this.groups = [];
11466		this.boundingBox = null;
11467		this.boundingSphere = null;
11468
11469		// used for storing cloned, shared data
11470
11471		const data = {};
11472
11473		// name
11474
11475		this.name = source.name;
11476
11477		// index
11478
11479		const index = source.index;
11480
11481		if ( index !== null ) {
11482
11483			this.setIndex( index.clone( data ) );
11484
11485		}
11486
11487		// attributes
11488
11489		const attributes = source.attributes;
11490
11491		for ( const name in attributes ) {
11492
11493			const attribute = attributes[ name ];
11494			this.setAttribute( name, attribute.clone( data ) );
11495
11496		}
11497
11498		// morph attributes
11499
11500		const morphAttributes = source.morphAttributes;
11501
11502		for ( const name in morphAttributes ) {
11503
11504			const array = [];
11505			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11506
11507			for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
11508
11509				array.push( morphAttribute[ i ].clone( data ) );
11510
11511			}
11512
11513			this.morphAttributes[ name ] = array;
11514
11515		}
11516
11517		this.morphTargetsRelative = source.morphTargetsRelative;
11518
11519		// groups
11520
11521		const groups = source.groups;
11522
11523		for ( let i = 0, l = groups.length; i < l; i ++ ) {
11524
11525			const group = groups[ i ];
11526			this.addGroup( group.start, group.count, group.materialIndex );
11527
11528		}
11529
11530		// bounding box
11531
11532		const boundingBox = source.boundingBox;
11533
11534		if ( boundingBox !== null ) {
11535
11536			this.boundingBox = boundingBox.clone();
11537
11538		}
11539
11540		// bounding sphere
11541
11542		const boundingSphere = source.boundingSphere;
11543
11544		if ( boundingSphere !== null ) {
11545
11546			this.boundingSphere = boundingSphere.clone();
11547
11548		}
11549
11550		// draw range
11551
11552		this.drawRange.start = source.drawRange.start;
11553		this.drawRange.count = source.drawRange.count;
11554
11555		// user data
11556
11557		this.userData = source.userData;
11558
11559		return this;
11560
11561	}
11562
11563	dispose() {
11564
11565		this.dispatchEvent( { type: 'dispose' } );
11566
11567	}
11568
11569}
11570
11571const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();
11572const _ray$3 = /*@__PURE__*/ new Ray();
11573const _sphere$6 = /*@__PURE__*/ new Sphere();
11574const _sphereHitAt = /*@__PURE__*/ new Vector3();
11575
11576const _vA$1 = /*@__PURE__*/ new Vector3();
11577const _vB$1 = /*@__PURE__*/ new Vector3();
11578const _vC$1 = /*@__PURE__*/ new Vector3();
11579
11580const _tempA = /*@__PURE__*/ new Vector3();
11581const _morphA = /*@__PURE__*/ new Vector3();
11582
11583const _uvA$1 = /*@__PURE__*/ new Vector2();
11584const _uvB$1 = /*@__PURE__*/ new Vector2();
11585const _uvC$1 = /*@__PURE__*/ new Vector2();
11586
11587const _normalA = /*@__PURE__*/ new Vector3();
11588const _normalB = /*@__PURE__*/ new Vector3();
11589const _normalC = /*@__PURE__*/ new Vector3();
11590
11591const _intersectionPoint = /*@__PURE__*/ new Vector3();
11592const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
11593
11594class Mesh extends Object3D {
11595
11596	constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
11597
11598		super();
11599
11600		this.isMesh = true;
11601
11602		this.type = 'Mesh';
11603
11604		this.geometry = geometry;
11605		this.material = material;
11606
11607		this.updateMorphTargets();
11608
11609	}
11610
11611	copy( source, recursive ) {
11612
11613		super.copy( source, recursive );
11614
11615		if ( source.morphTargetInfluences !== undefined ) {
11616
11617			this.morphTargetInfluences = source.morphTargetInfluences.slice();
11618
11619		}
11620
11621		if ( source.morphTargetDictionary !== undefined ) {
11622
11623			this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
11624
11625		}
11626
11627		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
11628		this.geometry = source.geometry;
11629
11630		return this;
11631
11632	}
11633
11634	updateMorphTargets() {
11635
11636		const geometry = this.geometry;
11637
11638		const morphAttributes = geometry.morphAttributes;
11639		const keys = Object.keys( morphAttributes );
11640
11641		if ( keys.length > 0 ) {
11642
11643			const morphAttribute = morphAttributes[ keys[ 0 ] ];
11644
11645			if ( morphAttribute !== undefined ) {
11646
11647				this.morphTargetInfluences = [];
11648				this.morphTargetDictionary = {};
11649
11650				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
11651
11652					const name = morphAttribute[ m ].name || String( m );
11653
11654					this.morphTargetInfluences.push( 0 );
11655					this.morphTargetDictionary[ name ] = m;
11656
11657				}
11658
11659			}
11660
11661		}
11662
11663	}
11664
11665	getVertexPosition( index, target ) {
11666
11667		const geometry = this.geometry;
11668		const position = geometry.attributes.position;
11669		const morphPosition = geometry.morphAttributes.position;
11670		const morphTargetsRelative = geometry.morphTargetsRelative;
11671
11672		target.fromBufferAttribute( position, index );
11673
11674		const morphInfluences = this.morphTargetInfluences;
11675
11676		if ( morphPosition && morphInfluences ) {
11677
11678			_morphA.set( 0, 0, 0 );
11679
11680			for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
11681
11682				const influence = morphInfluences[ i ];
11683				const morphAttribute = morphPosition[ i ];
11684
11685				if ( influence === 0 ) continue;
11686
11687				_tempA.fromBufferAttribute( morphAttribute, index );
11688
11689				if ( morphTargetsRelative ) {
11690
11691					_morphA.addScaledVector( _tempA, influence );
11692
11693				} else {
11694
11695					_morphA.addScaledVector( _tempA.sub( target ), influence );
11696
11697				}
11698
11699			}
11700
11701			target.add( _morphA );
11702
11703		}
11704
11705		return target;
11706
11707	}
11708
11709	raycast( raycaster, intersects ) {
11710
11711		const geometry = this.geometry;
11712		const material = this.material;
11713		const matrixWorld = this.matrixWorld;
11714
11715		if ( material === undefined ) return;
11716
vendor: 6,665 bytes, lines 11717-11959
11717		// test with bounding sphere in world space
11718
11719		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
11720
11721		_sphere$6.copy( geometry.boundingSphere );
11722		_sphere$6.applyMatrix4( matrixWorld );
11723
11724		// check distance from ray origin to bounding sphere
11725
11726		_ray$3.copy( raycaster.ray ).recast( raycaster.near );
11727
11728		if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {
11729
11730			if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;
11731
11732			if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;
11733
11734		}
11735
11736		// convert ray to local space of mesh
11737
11738		_inverseMatrix$3.copy( matrixWorld ).invert();
11739		_ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );
11740
11741		// test with bounding box in local space
11742
11743		if ( geometry.boundingBox !== null ) {
11744
11745			if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;
11746
11747		}
11748
11749		// test for intersections with geometry
11750
11751		this._computeIntersections( raycaster, intersects, _ray$3 );
11752
11753	}
11754
11755	_computeIntersections( raycaster, intersects, rayLocalSpace ) {
11756
11757		let intersection;
11758
11759		const geometry = this.geometry;
11760		const material = this.material;
11761
11762		const index = geometry.index;
11763		const position = geometry.attributes.position;
11764		const uv = geometry.attributes.uv;
11765		const uv1 = geometry.attributes.uv1;
11766		const normal = geometry.attributes.normal;
11767		const groups = geometry.groups;
11768		const drawRange = geometry.drawRange;
11769
11770		if ( index !== null ) {
11771
11772			// indexed buffer geometry
11773
11774			if ( Array.isArray( material ) ) {
11775
11776				for ( let i = 0, il = groups.length; i < il; i ++ ) {
11777
11778					const group = groups[ i ];
11779					const groupMaterial = material[ group.materialIndex ];
11780
11781					const start = Math.max( group.start, drawRange.start );
11782					const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11783
11784					for ( let j = start, jl = end; j < jl; j += 3 ) {
11785
11786						const a = index.getX( j );
11787						const b = index.getX( j + 1 );
11788						const c = index.getX( j + 2 );
11789
11790						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11791
11792						if ( intersection ) {
11793
11794							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
11795							intersection.face.materialIndex = group.materialIndex;
11796							intersects.push( intersection );
11797
11798						}
11799
11800					}
11801
11802				}
11803
11804			} else {
11805
11806				const start = Math.max( 0, drawRange.start );
11807				const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
11808
11809				for ( let i = start, il = end; i < il; i += 3 ) {
11810
11811					const a = index.getX( i );
11812					const b = index.getX( i + 1 );
11813					const c = index.getX( i + 2 );
11814
11815					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11816
11817					if ( intersection ) {
11818
11819						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
11820						intersects.push( intersection );
11821
11822					}
11823
11824				}
11825
11826			}
11827
11828		} else if ( position !== undefined ) {
11829
11830			// non-indexed buffer geometry
11831
11832			if ( Array.isArray( material ) ) {
11833
11834				for ( let i = 0, il = groups.length; i < il; i ++ ) {
11835
11836					const group = groups[ i ];
11837					const groupMaterial = material[ group.materialIndex ];
11838
11839					const start = Math.max( group.start, drawRange.start );
11840					const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11841
11842					for ( let j = start, jl = end; j < jl; j += 3 ) {
11843
11844						const a = j;
11845						const b = j + 1;
11846						const c = j + 2;
11847
11848						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11849
11850						if ( intersection ) {
11851
11852							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
11853							intersection.face.materialIndex = group.materialIndex;
11854							intersects.push( intersection );
11855
11856						}
11857
11858					}
11859
11860				}
11861
11862			} else {
11863
11864				const start = Math.max( 0, drawRange.start );
11865				const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
11866
11867				for ( let i = start, il = end; i < il; i += 3 ) {
11868
11869					const a = i;
11870					const b = i + 1;
11871					const c = i + 2;
11872
11873					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11874
11875					if ( intersection ) {
11876
11877						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
11878						intersects.push( intersection );
11879
11880					}
11881
11882				}
11883
11884			}
11885
11886		}
11887
11888	}
11889
11890}
11891
11892function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
11893
11894	let intersect;
11895
11896	if ( material.side === BackSide ) {
11897
11898		intersect = ray.intersectTriangle( pC, pB, pA, true, point );
11899
11900	} else {
11901
11902		intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );
11903
11904	}
11905
11906	if ( intersect === null ) return null;
11907
11908	_intersectionPointWorld.copy( point );
11909	_intersectionPointWorld.applyMatrix4( object.matrixWorld );
11910
11911	const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
11912
11913	if ( distance < raycaster.near || distance > raycaster.far ) return null;
11914
11915	return {
11916		distance: distance,
11917		point: _intersectionPointWorld.clone(),
11918		object: object
11919	};
11920
11921}
11922
11923function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {
11924
11925	object.getVertexPosition( a, _vA$1 );
11926	object.getVertexPosition( b, _vB$1 );
11927	object.getVertexPosition( c, _vC$1 );
11928
11929	const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );
11930
11931	if ( intersection ) {
11932
11933		if ( uv ) {
11934
11935			_uvA$1.fromBufferAttribute( uv, a );
11936			_uvB$1.fromBufferAttribute( uv, b );
11937			_uvC$1.fromBufferAttribute( uv, c );
11938
11939			intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11940
11941		}
11942
11943		if ( uv1 ) {
11944
11945			_uvA$1.fromBufferAttribute( uv1, a );
11946			_uvB$1.fromBufferAttribute( uv1, b );
11947			_uvC$1.fromBufferAttribute( uv1, c );
11948
11949			intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11950			intersection.uv2 = intersection.uv1; // @deprecated, r152
11951
11952		}
11953
11954		if ( normal ) {
11955
11956			_normalA.fromBufferAttribute( normal, a );
11957			_normalB.fromBufferAttribute( normal, b );
11958			_normalC.fromBufferAttribute( normal, c );
11959
vendor: 43,307 bytes, lines 11960-13849
11960			intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );
11961
11962			if ( intersection.normal.dot( ray.direction ) > 0 ) {
11963
11964				intersection.normal.multiplyScalar( - 1 );
11965
11966			}
11967
11968		}
11969
11970		const face = {
11971			a: a,
11972			b: b,
11973			c: c,
11974			normal: new Vector3(),
11975			materialIndex: 0
11976		};
11977
11978		Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
11979
11980		intersection.face = face;
11981
11982	}
11983
11984	return intersection;
11985
11986}
11987
11988class BoxGeometry extends BufferGeometry {
11989
11990	constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
11991
11992		super();
11993
11994		this.type = 'BoxGeometry';
11995
11996		this.parameters = {
11997			width: width,
11998			height: height,
11999			depth: depth,
12000			widthSegments: widthSegments,
12001			heightSegments: heightSegments,
12002			depthSegments: depthSegments
12003		};
12004
12005		const scope = this;
12006
12007		// segments
12008
12009		widthSegments = Math.floor( widthSegments );
12010		heightSegments = Math.floor( heightSegments );
12011		depthSegments = Math.floor( depthSegments );
12012
12013
12014		// buffers
12015
12016		const indices = [];
12017		const vertices = [];
12018		const normals = [];
12019		const uvs = [];
12020
12021		// helper variables
12022
12023		let numberOfVertices = 0;
12024		let groupStart = 0;
12025
12026		// build each side of the box geometry
12027
12028		buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
12029		buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
12030		buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
12031		buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
12032		buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
12033		buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
12034
12035		// build geometry
12036
12037		this.setIndex( indices );
12038		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
12039		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
12040		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
12041
12042		function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
12043
12044			const segmentWidth = width / gridX;
12045			const segmentHeight = height / gridY;
12046
12047			const widthHalf = width / 2;
12048			const heightHalf = height / 2;
12049			const depthHalf = depth / 2;
12050
12051			const gridX1 = gridX + 1;
12052			const gridY1 = gridY + 1;
12053
12054			let vertexCounter = 0;
12055			let groupCount = 0;
12056
12057			const vector = new Vector3();
12058
12059			// generate vertices, normals and uvs
12060
12061			for ( let iy = 0; iy < gridY1; iy ++ ) {
12062
12063				const y = iy * segmentHeight - heightHalf;
12064
12065				for ( let ix = 0; ix < gridX1; ix ++ ) {
12066
12067					const x = ix * segmentWidth - widthHalf;
12068
12069					// set values to correct vector component
12070
12071					vector[ u ] = x * udir;
12072					vector[ v ] = y * vdir;
12073					vector[ w ] = depthHalf;
12074
12075					// now apply vector to vertex buffer
12076
12077					vertices.push( vector.x, vector.y, vector.z );
12078
12079					// set values to correct vector component
12080
12081					vector[ u ] = 0;
12082					vector[ v ] = 0;
12083					vector[ w ] = depth > 0 ? 1 : - 1;
12084
12085					// now apply vector to normal buffer
12086
12087					normals.push( vector.x, vector.y, vector.z );
12088
12089					// uvs
12090
12091					uvs.push( ix / gridX );
12092					uvs.push( 1 - ( iy / gridY ) );
12093
12094					// counters
12095
12096					vertexCounter += 1;
12097
12098				}
12099
12100			}
12101
12102			// indices
12103
12104			// 1. you need three indices to draw a single face
12105			// 2. a single segment consists of two faces
12106			// 3. so we need to generate six (2*3) indices per segment
12107
12108			for ( let iy = 0; iy < gridY; iy ++ ) {
12109
12110				for ( let ix = 0; ix < gridX; ix ++ ) {
12111
12112					const a = numberOfVertices + ix + gridX1 * iy;
12113					const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
12114					const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
12115					const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
12116
12117					// faces
12118
12119					indices.push( a, b, d );
12120					indices.push( b, c, d );
12121
12122					// increase counter
12123
12124					groupCount += 6;
12125
12126				}
12127
12128			}
12129
12130			// add a group to the geometry. this will ensure multi material support
12131
12132			scope.addGroup( groupStart, groupCount, materialIndex );
12133
12134			// calculate new start value for groups
12135
12136			groupStart += groupCount;
12137
12138			// update total number of vertices
12139
12140			numberOfVertices += vertexCounter;
12141
12142		}
12143
12144	}
12145
12146	copy( source ) {
12147
12148		super.copy( source );
12149
12150		this.parameters = Object.assign( {}, source.parameters );
12151
12152		return this;
12153
12154	}
12155
12156	static fromJSON( data ) {
12157
12158		return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );
12159
12160	}
12161
12162}
12163
12164/**
12165 * Uniform Utilities
12166 */
12167
12168function cloneUniforms( src ) {
12169
12170	const dst = {};
12171
12172	for ( const u in src ) {
12173
12174		dst[ u ] = {};
12175
12176		for ( const p in src[ u ] ) {
12177
12178			const property = src[ u ][ p ];
12179
12180			if ( property && ( property.isColor ||
12181				property.isMatrix3 || property.isMatrix4 ||
12182				property.isVector2 || property.isVector3 || property.isVector4 ||
12183				property.isTexture || property.isQuaternion ) ) {
12184
12185				if ( property.isRenderTargetTexture ) {
12186
12187					console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );
12188					dst[ u ][ p ] = null;
12189
12190				} else {
12191
12192					dst[ u ][ p ] = property.clone();
12193
12194				}
12195
12196			} else if ( Array.isArray( property ) ) {
12197
12198				dst[ u ][ p ] = property.slice();
12199
12200			} else {
12201
12202				dst[ u ][ p ] = property;
12203
12204			}
12205
12206		}
12207
12208	}
12209
12210	return dst;
12211
12212}
12213
12214function mergeUniforms( uniforms ) {
12215
12216	const merged = {};
12217
12218	for ( let u = 0; u < uniforms.length; u ++ ) {
12219
12220		const tmp = cloneUniforms( uniforms[ u ] );
12221
12222		for ( const p in tmp ) {
12223
12224			merged[ p ] = tmp[ p ];
12225
12226		}
12227
12228	}
12229
12230	return merged;
12231
12232}
12233
12234function cloneUniformsGroups( src ) {
12235
12236	const dst = [];
12237
12238	for ( let u = 0; u < src.length; u ++ ) {
12239
12240		dst.push( src[ u ].clone() );
12241
12242	}
12243
12244	return dst;
12245
12246}
12247
12248function getUnlitUniformColorSpace( renderer ) {
12249
12250	if ( renderer.getRenderTarget() === null ) {
12251
12252		// https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398
12253		return renderer.outputColorSpace;
12254
12255	}
12256
12257	return ColorManagement.workingColorSpace;
12258
12259}
12260
12261// Legacy
12262
12263const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
12264
12265var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
12266
12267var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
12268
12269class ShaderMaterial extends Material {
12270
12271	constructor( parameters ) {
12272
12273		super();
12274
12275		this.isShaderMaterial = true;
12276
12277		this.type = 'ShaderMaterial';
12278
12279		this.defines = {};
12280		this.uniforms = {};
12281		this.uniformsGroups = [];
12282
12283		this.vertexShader = default_vertex;
12284		this.fragmentShader = default_fragment;
12285
12286		this.linewidth = 1;
12287
12288		this.wireframe = false;
12289		this.wireframeLinewidth = 1;
12290
12291		this.fog = false; // set to use scene fog
12292		this.lights = false; // set to use scene lights
12293		this.clipping = false; // set to use user-defined clipping planes
12294
12295		this.forceSinglePass = true;
12296
12297		this.extensions = {
12298			derivatives: false, // set to use derivatives
12299			fragDepth: false, // set to use fragment depth values
12300			drawBuffers: false, // set to use draw buffers
12301			shaderTextureLOD: false, // set to use shader texture LOD
12302			clipCullDistance: false // set to use vertex shader clipping
12303		};
12304
12305		// When rendered geometry doesn't include these attributes but the material does,
12306		// use these default values in WebGL. This avoids errors when buffer data is missing.
12307		this.defaultAttributeValues = {
12308			'color': [ 1, 1, 1 ],
12309			'uv': [ 0, 0 ],
12310			'uv1': [ 0, 0 ]
12311		};
12312
12313		this.index0AttributeName = undefined;
12314		this.uniformsNeedUpdate = false;
12315
12316		this.glslVersion = null;
12317
12318		if ( parameters !== undefined ) {
12319
12320			this.setValues( parameters );
12321
12322		}
12323
12324	}
12325
12326	copy( source ) {
12327
12328		super.copy( source );
12329
12330		this.fragmentShader = source.fragmentShader;
12331		this.vertexShader = source.vertexShader;
12332
12333		this.uniforms = cloneUniforms( source.uniforms );
12334		this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );
12335
12336		this.defines = Object.assign( {}, source.defines );
12337
12338		this.wireframe = source.wireframe;
12339		this.wireframeLinewidth = source.wireframeLinewidth;
12340
12341		this.fog = source.fog;
12342		this.lights = source.lights;
12343		this.clipping = source.clipping;
12344
12345		this.extensions = Object.assign( {}, source.extensions );
12346
12347		this.glslVersion = source.glslVersion;
12348
12349		return this;
12350
12351	}
12352
12353	toJSON( meta ) {
12354
12355		const data = super.toJSON( meta );
12356
12357		data.glslVersion = this.glslVersion;
12358		data.uniforms = {};
12359
12360		for ( const name in this.uniforms ) {
12361
12362			const uniform = this.uniforms[ name ];
12363			const value = uniform.value;
12364
12365			if ( value && value.isTexture ) {
12366
12367				data.uniforms[ name ] = {
12368					type: 't',
12369					value: value.toJSON( meta ).uuid
12370				};
12371
12372			} else if ( value && value.isColor ) {
12373
12374				data.uniforms[ name ] = {
12375					type: 'c',
12376					value: value.getHex()
12377				};
12378
12379			} else if ( value && value.isVector2 ) {
12380
12381				data.uniforms[ name ] = {
12382					type: 'v2',
12383					value: value.toArray()
12384				};
12385
12386			} else if ( value && value.isVector3 ) {
12387
12388				data.uniforms[ name ] = {
12389					type: 'v3',
12390					value: value.toArray()
12391				};
12392
12393			} else if ( value && value.isVector4 ) {
12394
12395				data.uniforms[ name ] = {
12396					type: 'v4',
12397					value: value.toArray()
12398				};
12399
12400			} else if ( value && value.isMatrix3 ) {
12401
12402				data.uniforms[ name ] = {
12403					type: 'm3',
12404					value: value.toArray()
12405				};
12406
12407			} else if ( value && value.isMatrix4 ) {
12408
12409				data.uniforms[ name ] = {
12410					type: 'm4',
12411					value: value.toArray()
12412				};
12413
12414			} else {
12415
12416				data.uniforms[ name ] = {
12417					value: value
12418				};
12419
12420				// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
12421
12422			}
12423
12424		}
12425
12426		if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
12427
12428		data.vertexShader = this.vertexShader;
12429		data.fragmentShader = this.fragmentShader;
12430
12431		data.lights = this.lights;
12432		data.clipping = this.clipping;
12433
12434		const extensions = {};
12435
12436		for ( const key in this.extensions ) {
12437
12438			if ( this.extensions[ key ] === true ) extensions[ key ] = true;
12439
12440		}
12441
12442		if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
12443
12444		return data;
12445
12446	}
12447
12448}
12449
12450class Camera extends Object3D {
12451
12452	constructor() {
12453
12454		super();
12455
12456		this.isCamera = true;
12457
12458		this.type = 'Camera';
12459
12460		this.matrixWorldInverse = new Matrix4();
12461
12462		this.projectionMatrix = new Matrix4();
12463		this.projectionMatrixInverse = new Matrix4();
12464
12465		this.coordinateSystem = WebGLCoordinateSystem;
12466
12467	}
12468
12469	copy( source, recursive ) {
12470
12471		super.copy( source, recursive );
12472
12473		this.matrixWorldInverse.copy( source.matrixWorldInverse );
12474
12475		this.projectionMatrix.copy( source.projectionMatrix );
12476		this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
12477
12478		this.coordinateSystem = source.coordinateSystem;
12479
12480		return this;
12481
12482	}
12483
12484	getWorldDirection( target ) {
12485
12486		return super.getWorldDirection( target ).negate();
12487
12488	}
12489
12490	updateMatrixWorld( force ) {
12491
12492		super.updateMatrixWorld( force );
12493
12494		this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12495
12496	}
12497
12498	updateWorldMatrix( updateParents, updateChildren ) {
12499
12500		super.updateWorldMatrix( updateParents, updateChildren );
12501
12502		this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12503
12504	}
12505
12506	clone() {
12507
12508		return new this.constructor().copy( this );
12509
12510	}
12511
12512}
12513
12514class PerspectiveCamera extends Camera {
12515
12516	constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
12517
12518		super();
12519
12520		this.isPerspectiveCamera = true;
12521
12522		this.type = 'PerspectiveCamera';
12523
12524		this.fov = fov;
12525		this.zoom = 1;
12526
12527		this.near = near;
12528		this.far = far;
12529		this.focus = 10;
12530
12531		this.aspect = aspect;
12532		this.view = null;
12533
12534		this.filmGauge = 35;	// width of the film (default in millimeters)
12535		this.filmOffset = 0;	// horizontal film offset (same unit as gauge)
12536
12537		this.updateProjectionMatrix();
12538
12539	}
12540
12541	copy( source, recursive ) {
12542
12543		super.copy( source, recursive );
12544
12545		this.fov = source.fov;
12546		this.zoom = source.zoom;
12547
12548		this.near = source.near;
12549		this.far = source.far;
12550		this.focus = source.focus;
12551
12552		this.aspect = source.aspect;
12553		this.view = source.view === null ? null : Object.assign( {}, source.view );
12554
12555		this.filmGauge = source.filmGauge;
12556		this.filmOffset = source.filmOffset;
12557
12558		return this;
12559
12560	}
12561
12562	/**
12563	 * Sets the FOV by focal length in respect to the current .filmGauge.
12564	 *
12565	 * The default film gauge is 35, so that the focal length can be specified for
12566	 * a 35mm (full frame) camera.
12567	 *
12568	 * Values for focal length and film gauge must have the same unit.
12569	 */
12570	setFocalLength( focalLength ) {
12571
12572		/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
12573		const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
12574
12575		this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );
12576		this.updateProjectionMatrix();
12577
12578	}
12579
12580	/**
12581	 * Calculates the focal length from the current .fov and .filmGauge.
12582	 */
12583	getFocalLength() {
12584
12585		const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );
12586
12587		return 0.5 * this.getFilmHeight() / vExtentSlope;
12588
12589	}
12590
12591	getEffectiveFOV() {
12592
12593		return RAD2DEG * 2 * Math.atan(
12594			Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );
12595
12596	}
12597
12598	getFilmWidth() {
12599
12600		// film not completely covered in portrait format (aspect < 1)
12601		return this.filmGauge * Math.min( this.aspect, 1 );
12602
12603	}
12604
12605	getFilmHeight() {
12606
12607		// film not completely covered in landscape format (aspect > 1)
12608		return this.filmGauge / Math.max( this.aspect, 1 );
12609
12610	}
12611
12612	/**
12613	 * Sets an offset in a larger frustum. This is useful for multi-window or
12614	 * multi-monitor/multi-machine setups.
12615	 *
12616	 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
12617	 * the monitors are in grid like this
12618	 *
12619	 *   +---+---+---+
12620	 *   | A | B | C |
12621	 *   +---+---+---+
12622	 *   | D | E | F |
12623	 *   +---+---+---+
12624	 *
12625	 * then for each monitor you would call it like this
12626	 *
12627	 *   const w = 1920;
12628	 *   const h = 1080;
12629	 *   const fullWidth = w * 3;
12630	 *   const fullHeight = h * 2;
12631	 *
12632	 *   --A--
12633	 *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
12634	 *   --B--
12635	 *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
12636	 *   --C--
12637	 *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
12638	 *   --D--
12639	 *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
12640	 *   --E--
12641	 *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
12642	 *   --F--
12643	 *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
12644	 *
12645	 *   Note there is no reason monitors have to be the same size or in a grid.
12646	 */
12647	setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
12648
12649		this.aspect = fullWidth / fullHeight;
12650
12651		if ( this.view === null ) {
12652
12653			this.view = {
12654				enabled: true,
12655				fullWidth: 1,
12656				fullHeight: 1,
12657				offsetX: 0,
12658				offsetY: 0,
12659				width: 1,
12660				height: 1
12661			};
12662
12663		}
12664
12665		this.view.enabled = true;
12666		this.view.fullWidth = fullWidth;
12667		this.view.fullHeight = fullHeight;
12668		this.view.offsetX = x;
12669		this.view.offsetY = y;
12670		this.view.width = width;
12671		this.view.height = height;
12672
12673		this.updateProjectionMatrix();
12674
12675	}
12676
12677	clearViewOffset() {
12678
12679		if ( this.view !== null ) {
12680
12681			this.view.enabled = false;
12682
12683		}
12684
12685		this.updateProjectionMatrix();
12686
12687	}
12688
12689	updateProjectionMatrix() {
12690
12691		const near = this.near;
12692		let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;
12693		let height = 2 * top;
12694		let width = this.aspect * height;
12695		let left = - 0.5 * width;
12696		const view = this.view;
12697
12698		if ( this.view !== null && this.view.enabled ) {
12699
12700			const fullWidth = view.fullWidth,
12701				fullHeight = view.fullHeight;
12702
12703			left += view.offsetX * width / fullWidth;
12704			top -= view.offsetY * height / fullHeight;
12705			width *= view.width / fullWidth;
12706			height *= view.height / fullHeight;
12707
12708		}
12709
12710		const skew = this.filmOffset;
12711		if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
12712
12713		this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );
12714
12715		this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
12716
12717	}
12718
12719	toJSON( meta ) {
12720
12721		const data = super.toJSON( meta );
12722
12723		data.object.fov = this.fov;
12724		data.object.zoom = this.zoom;
12725
12726		data.object.near = this.near;
12727		data.object.far = this.far;
12728		data.object.focus = this.focus;
12729
12730		data.object.aspect = this.aspect;
12731
12732		if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12733
12734		data.object.filmGauge = this.filmGauge;
12735		data.object.filmOffset = this.filmOffset;
12736
12737		return data;
12738
12739	}
12740
12741}
12742
12743const fov = - 90; // negative fov is not an error
12744const aspect = 1;
12745
12746class CubeCamera extends Object3D {
12747
12748	constructor( near, far, renderTarget ) {
12749
12750		super();
12751
12752		this.type = 'CubeCamera';
12753
12754		this.renderTarget = renderTarget;
12755		this.coordinateSystem = null;
12756		this.activeMipmapLevel = 0;
12757
12758		const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
12759		cameraPX.layers = this.layers;
12760		this.add( cameraPX );
12761
12762		const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
12763		cameraNX.layers = this.layers;
12764		this.add( cameraNX );
12765
12766		const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
12767		cameraPY.layers = this.layers;
12768		this.add( cameraPY );
12769
12770		const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
12771		cameraNY.layers = this.layers;
12772		this.add( cameraNY );
12773
12774		const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
12775		cameraPZ.layers = this.layers;
12776		this.add( cameraPZ );
12777
12778		const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
12779		cameraNZ.layers = this.layers;
12780		this.add( cameraNZ );
12781
12782	}
12783
12784	updateCoordinateSystem() {
12785
12786		const coordinateSystem = this.coordinateSystem;
12787
12788		const cameras = this.children.concat();
12789
12790		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras;
12791
12792		for ( const camera of cameras ) this.remove( camera );
12793
12794		if ( coordinateSystem === WebGLCoordinateSystem ) {
12795
12796			cameraPX.up.set( 0, 1, 0 );
12797			cameraPX.lookAt( 1, 0, 0 );
12798
12799			cameraNX.up.set( 0, 1, 0 );
12800			cameraNX.lookAt( - 1, 0, 0 );
12801
12802			cameraPY.up.set( 0, 0, - 1 );
12803			cameraPY.lookAt( 0, 1, 0 );
12804
12805			cameraNY.up.set( 0, 0, 1 );
12806			cameraNY.lookAt( 0, - 1, 0 );
12807
12808			cameraPZ.up.set( 0, 1, 0 );
12809			cameraPZ.lookAt( 0, 0, 1 );
12810
12811			cameraNZ.up.set( 0, 1, 0 );
12812			cameraNZ.lookAt( 0, 0, - 1 );
12813
12814		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
12815
12816			cameraPX.up.set( 0, - 1, 0 );
12817			cameraPX.lookAt( - 1, 0, 0 );
12818
12819			cameraNX.up.set( 0, - 1, 0 );
12820			cameraNX.lookAt( 1, 0, 0 );
12821
12822			cameraPY.up.set( 0, 0, 1 );
12823			cameraPY.lookAt( 0, 1, 0 );
12824
12825			cameraNY.up.set( 0, 0, - 1 );
12826			cameraNY.lookAt( 0, - 1, 0 );
12827
12828			cameraPZ.up.set( 0, - 1, 0 );
12829			cameraPZ.lookAt( 0, 0, 1 );
12830
12831			cameraNZ.up.set( 0, - 1, 0 );
12832			cameraNZ.lookAt( 0, 0, - 1 );
12833
12834		} else {
12835
12836			throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );
12837
12838		}
12839
12840		for ( const camera of cameras ) {
12841
12842			this.add( camera );
12843
12844			camera.updateMatrixWorld();
12845
12846		}
12847
12848	}
12849
12850	update( renderer, scene ) {
12851
12852		if ( this.parent === null ) this.updateMatrixWorld();
12853
12854		const { renderTarget, activeMipmapLevel } = this;
12855
12856		if ( this.coordinateSystem !== renderer.coordinateSystem ) {
12857
12858			this.coordinateSystem = renderer.coordinateSystem;
12859
12860			this.updateCoordinateSystem();
12861
12862		}
12863
12864		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;
12865
12866		const currentRenderTarget = renderer.getRenderTarget();
12867		const currentActiveCubeFace = renderer.getActiveCubeFace();
12868		const currentActiveMipmapLevel = renderer.getActiveMipmapLevel();
12869
12870		const currentXrEnabled = renderer.xr.enabled;
12871
12872		renderer.xr.enabled = false;
12873
12874		const generateMipmaps = renderTarget.texture.generateMipmaps;
12875
12876		renderTarget.texture.generateMipmaps = false;
12877
12878		renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel );
12879		renderer.render( scene, cameraPX );
12880
12881		renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel );
12882		renderer.render( scene, cameraNX );
12883
12884		renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel );
12885		renderer.render( scene, cameraPY );
12886
12887		renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel );
12888		renderer.render( scene, cameraNY );
12889
12890		renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel );
12891		renderer.render( scene, cameraPZ );
12892
12893		// mipmaps are generated during the last call of render()
12894		// at this point, all sides of the cube render target are defined
12895
12896		renderTarget.texture.generateMipmaps = generateMipmaps;
12897
12898		renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );
12899		renderer.render( scene, cameraNZ );
12900
12901		renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );
12902
12903		renderer.xr.enabled = currentXrEnabled;
12904
12905		renderTarget.texture.needsPMREMUpdate = true;
12906
12907	}
12908
12909}
12910
12911class CubeTexture extends Texture {
12912
12913	constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) {
12914
12915		images = images !== undefined ? images : [];
12916		mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
12917
12918		super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
12919
12920		this.isCubeTexture = true;
12921
12922		this.flipY = false;
12923
12924	}
12925
12926	get images() {
12927
12928		return this.image;
12929
12930	}
12931
12932	set images( value ) {
12933
12934		this.image = value;
12935
12936	}
12937
12938}
12939
12940class WebGLCubeRenderTarget extends WebGLRenderTarget {
12941
12942	constructor( size = 1, options = {} ) {
12943
12944		super( size, size, options );
12945
12946		this.isWebGLCubeRenderTarget = true;
12947
12948		const image = { width: size, height: size, depth: 1 };
12949		const images = [ image, image, image, image, image, image ];
12950
12951		if ( options.encoding !== undefined ) {
12952
12953			// @deprecated, r152
12954			warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' );
12955			options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
12956
12957		}
12958
12959		this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
12960
12961		// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
12962		// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
12963		// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
12964
12965		// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
12966		// and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture
12967		// as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).
12968
12969		this.texture.isRenderTargetTexture = true;
12970
12971		this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
12972		this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
12973
12974	}
12975
12976	fromEquirectangularTexture( renderer, texture ) {
12977
12978		this.texture.type = texture.type;
12979		this.texture.colorSpace = texture.colorSpace;
12980
12981		this.texture.generateMipmaps = texture.generateMipmaps;
12982		this.texture.minFilter = texture.minFilter;
12983		this.texture.magFilter = texture.magFilter;
12984
12985		const shader = {
12986
12987			uniforms: {
12988				tEquirect: { value: null },
12989			},
12990
12991			vertexShader: /* glsl */`
12992
12993				varying vec3 vWorldDirection;
12994
12995				vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
12996
12997					return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
12998
12999				}
13000
13001				void main() {
13002
13003					vWorldDirection = transformDirection( position, modelMatrix );
13004
13005					#include <begin_vertex>
13006					#include <project_vertex>
13007
13008				}
13009			`,
13010
13011			fragmentShader: /* glsl */`
13012
13013				uniform sampler2D tEquirect;
13014
13015				varying vec3 vWorldDirection;
13016
13017				#include <common>
13018
13019				void main() {
13020
13021					vec3 direction = normalize( vWorldDirection );
13022
13023					vec2 sampleUV = equirectUv( direction );
13024
13025					gl_FragColor = texture2D( tEquirect, sampleUV );
13026
13027				}
13028			`
13029		};
13030
13031		const geometry = new BoxGeometry( 5, 5, 5 );
13032
13033		const material = new ShaderMaterial( {
13034
13035			name: 'CubemapFromEquirect',
13036
13037			uniforms: cloneUniforms( shader.uniforms ),
13038			vertexShader: shader.vertexShader,
13039			fragmentShader: shader.fragmentShader,
13040			side: BackSide,
13041			blending: NoBlending
13042
13043		} );
13044
13045		material.uniforms.tEquirect.value = texture;
13046
13047		const mesh = new Mesh( geometry, material );
13048
13049		const currentMinFilter = texture.minFilter;
13050
13051		// Avoid blurred poles
13052		if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
13053
13054		const camera = new CubeCamera( 1, 10, this );
13055		camera.update( renderer, mesh );
13056
13057		texture.minFilter = currentMinFilter;
13058
13059		mesh.geometry.dispose();
13060		mesh.material.dispose();
13061
13062		return this;
13063
13064	}
13065
13066	clear( renderer, color, depth, stencil ) {
13067
13068		const currentRenderTarget = renderer.getRenderTarget();
13069
13070		for ( let i = 0; i < 6; i ++ ) {
13071
13072			renderer.setRenderTarget( this, i );
13073
13074			renderer.clear( color, depth, stencil );
13075
13076		}
13077
13078		renderer.setRenderTarget( currentRenderTarget );
13079
13080	}
13081
13082}
13083
13084const _vector1 = /*@__PURE__*/ new Vector3();
13085const _vector2 = /*@__PURE__*/ new Vector3();
13086const _normalMatrix = /*@__PURE__*/ new Matrix3();
13087
13088class Plane {
13089
13090	constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {
13091
13092		this.isPlane = true;
13093
13094		// normal is assumed to be normalized
13095
13096		this.normal = normal;
13097		this.constant = constant;
13098
13099	}
13100
13101	set( normal, constant ) {
13102
13103		this.normal.copy( normal );
13104		this.constant = constant;
13105
13106		return this;
13107
13108	}
13109
13110	setComponents( x, y, z, w ) {
13111
13112		this.normal.set( x, y, z );
13113		this.constant = w;
13114
13115		return this;
13116
13117	}
13118
13119	setFromNormalAndCoplanarPoint( normal, point ) {
13120
13121		this.normal.copy( normal );
13122		this.constant = - point.dot( this.normal );
13123
13124		return this;
13125
13126	}
13127
13128	setFromCoplanarPoints( a, b, c ) {
13129
13130		const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
13131
13132		// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
13133
13134		this.setFromNormalAndCoplanarPoint( normal, a );
13135
13136		return this;
13137
13138	}
13139
13140	copy( plane ) {
13141
13142		this.normal.copy( plane.normal );
13143		this.constant = plane.constant;
13144
13145		return this;
13146
13147	}
13148
13149	normalize() {
13150
13151		// Note: will lead to a divide by zero if the plane is invalid.
13152
13153		const inverseNormalLength = 1.0 / this.normal.length();
13154		this.normal.multiplyScalar( inverseNormalLength );
13155		this.constant *= inverseNormalLength;
13156
13157		return this;
13158
13159	}
13160
13161	negate() {
13162
13163		this.constant *= - 1;
13164		this.normal.negate();
13165
13166		return this;
13167
13168	}
13169
13170	distanceToPoint( point ) {
13171
13172		return this.normal.dot( point ) + this.constant;
13173
13174	}
13175
13176	distanceToSphere( sphere ) {
13177
13178		return this.distanceToPoint( sphere.center ) - sphere.radius;
13179
13180	}
13181
13182	projectPoint( point, target ) {
13183
13184		return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) );
13185
13186	}
13187
13188	intersectLine( line, target ) {
13189
13190		const direction = line.delta( _vector1 );
13191
13192		const denominator = this.normal.dot( direction );
13193
13194		if ( denominator === 0 ) {
13195
13196			// line is coplanar, return origin
13197			if ( this.distanceToPoint( line.start ) === 0 ) {
13198
13199				return target.copy( line.start );
13200
13201			}
13202
13203			// Unsure if this is the correct method to handle this case.
13204			return null;
13205
13206		}
13207
13208		const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
13209
13210		if ( t < 0 || t > 1 ) {
13211
13212			return null;
13213
13214		}
13215
13216		return target.copy( line.start ).addScaledVector( direction, t );
13217
13218	}
13219
13220	intersectsLine( line ) {
13221
13222		// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
13223
13224		const startSign = this.distanceToPoint( line.start );
13225		const endSign = this.distanceToPoint( line.end );
13226
13227		return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
13228
13229	}
13230
13231	intersectsBox( box ) {
13232
13233		return box.intersectsPlane( this );
13234
13235	}
13236
13237	intersectsSphere( sphere ) {
13238
13239		return sphere.intersectsPlane( this );
13240
13241	}
13242
13243	coplanarPoint( target ) {
13244
13245		return target.copy( this.normal ).multiplyScalar( - this.constant );
13246
13247	}
13248
13249	applyMatrix4( matrix, optionalNormalMatrix ) {
13250
13251		const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
13252
13253		const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
13254
13255		const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
13256
13257		this.constant = - referencePoint.dot( normal );
13258
13259		return this;
13260
13261	}
13262
13263	translate( offset ) {
13264
13265		this.constant -= offset.dot( this.normal );
13266
13267		return this;
13268
13269	}
13270
13271	equals( plane ) {
13272
13273		return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
13274
13275	}
13276
13277	clone() {
13278
13279		return new this.constructor().copy( this );
13280
13281	}
13282
13283}
13284
13285const _sphere$5 = /*@__PURE__*/ new Sphere();
13286const _vector$7 = /*@__PURE__*/ new Vector3();
13287
13288class Frustum {
13289
13290	constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {
13291
13292		this.planes = [ p0, p1, p2, p3, p4, p5 ];
13293
13294	}
13295
13296	set( p0, p1, p2, p3, p4, p5 ) {
13297
13298		const planes = this.planes;
13299
13300		planes[ 0 ].copy( p0 );
13301		planes[ 1 ].copy( p1 );
13302		planes[ 2 ].copy( p2 );
13303		planes[ 3 ].copy( p3 );
13304		planes[ 4 ].copy( p4 );
13305		planes[ 5 ].copy( p5 );
13306
13307		return this;
13308
13309	}
13310
13311	copy( frustum ) {
13312
13313		const planes = this.planes;
13314
13315		for ( let i = 0; i < 6; i ++ ) {
13316
13317			planes[ i ].copy( frustum.planes[ i ] );
13318
13319		}
13320
13321		return this;
13322
13323	}
13324
13325	setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) {
13326
13327		const planes = this.planes;
13328		const me = m.elements;
13329		const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
13330		const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
13331		const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
13332		const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
13333
13334		planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
13335		planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
13336		planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
13337		planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
13338		planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
13339
13340		if ( coordinateSystem === WebGLCoordinateSystem ) {
13341
13342			planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
13343
13344		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
13345
13346			planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();
13347
13348		} else {
13349
13350			throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );
13351
13352		}
13353
13354		return this;
13355
13356	}
13357
13358	intersectsObject( object ) {
13359
13360		if ( object.boundingSphere !== undefined ) {
13361
13362			if ( object.boundingSphere === null ) object.computeBoundingSphere();
13363
13364			_sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );
13365
13366		} else {
13367
13368			const geometry = object.geometry;
13369
13370			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
13371
13372			_sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
13373
13374		}
13375
13376		return this.intersectsSphere( _sphere$5 );
13377
13378	}
13379
13380	intersectsSprite( sprite ) {
13381
13382		_sphere$5.center.set( 0, 0, 0 );
13383		_sphere$5.radius = 0.7071067811865476;
13384		_sphere$5.applyMatrix4( sprite.matrixWorld );
13385
13386		return this.intersectsSphere( _sphere$5 );
13387
13388	}
13389
13390	intersectsSphere( sphere ) {
13391
13392		const planes = this.planes;
13393		const center = sphere.center;
13394		const negRadius = - sphere.radius;
13395
13396		for ( let i = 0; i < 6; i ++ ) {
13397
13398			const distance = planes[ i ].distanceToPoint( center );
13399
13400			if ( distance < negRadius ) {
13401
13402				return false;
13403
13404			}
13405
13406		}
13407
13408		return true;
13409
13410	}
13411
13412	intersectsBox( box ) {
13413
13414		const planes = this.planes;
13415
13416		for ( let i = 0; i < 6; i ++ ) {
13417
13418			const plane = planes[ i ];
13419
13420			// corner at max distance
13421
13422			_vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;
13423			_vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;
13424			_vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;
13425
13426			if ( plane.distanceToPoint( _vector$7 ) < 0 ) {
13427
13428				return false;
13429
13430			}
13431
13432		}
13433
13434		return true;
13435
13436	}
13437
13438	containsPoint( point ) {
13439
13440		const planes = this.planes;
13441
13442		for ( let i = 0; i < 6; i ++ ) {
13443
13444			if ( planes[ i ].distanceToPoint( point ) < 0 ) {
13445
13446				return false;
13447
13448			}
13449
13450		}
13451
13452		return true;
13453
13454	}
13455
13456	clone() {
13457
13458		return new this.constructor().copy( this );
13459
13460	}
13461
13462}
13463
13464function WebGLAnimation() {
13465
13466	let context = null;
13467	let isAnimating = false;
13468	let animationLoop = null;
13469	let requestId = null;
13470
13471	function onAnimationFrame( time, frame ) {
13472
13473		animationLoop( time, frame );
13474
13475		requestId = context.requestAnimationFrame( onAnimationFrame );
13476
13477	}
13478
13479	return {
13480
13481		start: function () {
13482
13483			if ( isAnimating === true ) return;
13484			if ( animationLoop === null ) return;
13485
13486			requestId = context.requestAnimationFrame( onAnimationFrame );
13487
13488			isAnimating = true;
13489
13490		},
13491
13492		stop: function () {
13493
13494			context.cancelAnimationFrame( requestId );
13495
13496			isAnimating = false;
13497
13498		},
13499
13500		setAnimationLoop: function ( callback ) {
13501
13502			animationLoop = callback;
13503
13504		},
13505
13506		setContext: function ( value ) {
13507
13508			context = value;
13509
13510		}
13511
13512	};
13513
13514}
13515
13516function WebGLAttributes( gl, capabilities ) {
13517
13518	const isWebGL2 = capabilities.isWebGL2;
13519
13520	const buffers = new WeakMap();
13521
13522	function createBuffer( attribute, bufferType ) {
13523
13524		const array = attribute.array;
13525		const usage = attribute.usage;
13526		const size = array.byteLength;
13527
13528		const buffer = gl.createBuffer();
13529
13530		gl.bindBuffer( bufferType, buffer );
13531		gl.bufferData( bufferType, array, usage );
13532
13533		attribute.onUploadCallback();
13534
13535		let type;
13536
13537		if ( array instanceof Float32Array ) {
13538
13539			type = gl.FLOAT;
13540
13541		} else if ( array instanceof Uint16Array ) {
13542
13543			if ( attribute.isFloat16BufferAttribute ) {
13544
13545				if ( isWebGL2 ) {
13546
13547					type = gl.HALF_FLOAT;
13548
13549				} else {
13550
13551					throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
13552
13553				}
13554
13555			} else {
13556
13557				type = gl.UNSIGNED_SHORT;
13558
13559			}
13560
13561		} else if ( array instanceof Int16Array ) {
13562
13563			type = gl.SHORT;
13564
13565		} else if ( array instanceof Uint32Array ) {
13566
13567			type = gl.UNSIGNED_INT;
13568
13569		} else if ( array instanceof Int32Array ) {
13570
13571			type = gl.INT;
13572
13573		} else if ( array instanceof Int8Array ) {
13574
13575			type = gl.BYTE;
13576
13577		} else if ( array instanceof Uint8Array ) {
13578
13579			type = gl.UNSIGNED_BYTE;
13580
13581		} else if ( array instanceof Uint8ClampedArray ) {
13582
13583			type = gl.UNSIGNED_BYTE;
13584
13585		} else {
13586
13587			throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );
13588
13589		}
13590
13591		return {
13592			buffer: buffer,
13593			type: type,
13594			bytesPerElement: array.BYTES_PER_ELEMENT,
13595			version: attribute.version,
13596			size: size
13597		};
13598
13599	}
13600
13601	function updateBuffer( buffer, attribute, bufferType ) {
13602
13603		const array = attribute.array;
13604		const updateRange = attribute._updateRange; // deprecated
13605		const updateRanges = attribute.updateRanges;
13606
13607		gl.bindBuffer( bufferType, buffer );
13608
13609		if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
13610
13611			// Not using update ranges
13612			gl.bufferSubData( bufferType, 0, array );
13613
13614		}
13615
13616		if ( updateRanges.length !== 0 ) {
13617
13618			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
13619
13620				const range = updateRanges[ i ];
13621				if ( isWebGL2 ) {
13622
13623					gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13624						array, range.start, range.count );
13625
13626				} else {
13627
13628					gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13629						array.subarray( range.start, range.start + range.count ) );
13630
13631				}
13632
13633			}
13634
13635			attribute.clearUpdateRanges();
13636
13637		}
13638
13639		// deprecated
13640		if ( updateRange.count !== - 1 ) {
13641
13642			if ( isWebGL2 ) {
13643
13644				gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13645					array, updateRange.offset, updateRange.count );
13646
13647			} else {
13648
13649				gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13650					array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
13651
13652			}
13653
13654			updateRange.count = - 1; // reset range
13655
13656		}
13657
13658		attribute.onUploadCallback();
13659
13660	}
13661
13662	//
13663
13664	function get( attribute ) {
13665
13666		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13667
13668		return buffers.get( attribute );
13669
13670	}
13671
13672	function remove( attribute ) {
13673
13674		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13675
13676		const data = buffers.get( attribute );
13677
13678		if ( data ) {
13679
13680			gl.deleteBuffer( data.buffer );
13681
13682			buffers.delete( attribute );
13683
13684		}
13685
13686	}
13687
13688	function update( attribute, bufferType ) {
13689
13690		if ( attribute.isGLBufferAttribute ) {
13691
13692			const cached = buffers.get( attribute );
13693
13694			if ( ! cached || cached.version < attribute.version ) {
13695
13696				buffers.set( attribute, {
13697					buffer: attribute.buffer,
13698					type: attribute.type,
13699					bytesPerElement: attribute.elementSize,
13700					version: attribute.version
13701				} );
13702
13703			}
13704
13705			return;
13706
13707		}
13708
13709		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13710
13711		const data = buffers.get( attribute );
13712
13713		if ( data === undefined ) {
13714
13715			buffers.set( attribute, createBuffer( attribute, bufferType ) );
13716
13717		} else if ( data.version < attribute.version ) {
13718
13719			if ( data.size !== attribute.array.byteLength ) {
13720
13721				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.' );
13722
13723			}
13724
13725			updateBuffer( data.buffer, attribute, bufferType );
13726
13727			data.version = attribute.version;
13728
13729		}
13730
13731	}
13732
13733	return {
13734
13735		get: get,
13736		remove: remove,
13737		update: update
13738
13739	};
13740
13741}
13742
13743class PlaneGeometry extends BufferGeometry {
13744
13745	constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
13746
13747		super();
13748
13749		this.type = 'PlaneGeometry';
13750
13751		this.parameters = {
13752			width: width,
13753			height: height,
13754			widthSegments: widthSegments,
13755			heightSegments: heightSegments
13756		};
13757
13758		const width_half = width / 2;
13759		const height_half = height / 2;
13760
13761		const gridX = Math.floor( widthSegments );
13762		const gridY = Math.floor( heightSegments );
13763
13764		const gridX1 = gridX + 1;
13765		const gridY1 = gridY + 1;
13766
13767		const segment_width = width / gridX;
13768		const segment_height = height / gridY;
13769
13770		//
13771
13772		const indices = [];
13773		const vertices = [];
13774		const normals = [];
13775		const uvs = [];
13776
13777		for ( let iy = 0; iy < gridY1; iy ++ ) {
13778
13779			const y = iy * segment_height - height_half;
13780
13781			for ( let ix = 0; ix < gridX1; ix ++ ) {
13782
13783				const x = ix * segment_width - width_half;
13784
13785				vertices.push( x, - y, 0 );
13786
13787				normals.push( 0, 0, 1 );
13788
13789				uvs.push( ix / gridX );
13790				uvs.push( 1 - ( iy / gridY ) );
13791
13792			}
13793
13794		}
13795
13796		for ( let iy = 0; iy < gridY; iy ++ ) {
13797
13798			for ( let ix = 0; ix < gridX; ix ++ ) {
13799
13800				const a = ix + gridX1 * iy;
13801				const b = ix + gridX1 * ( iy + 1 );
13802				const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
13803				const d = ( ix + 1 ) + gridX1 * iy;
13804
13805				indices.push( a, b, d );
13806				indices.push( b, c, d );
13807
13808			}
13809
13810		}
13811
13812		this.setIndex( indices );
13813		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
13814		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
13815		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
13816
13817	}
13818
13819	copy( source ) {
13820
13821		super.copy( source );
13822
13823		this.parameters = Object.assign( {}, source.parameters );
13824
13825		return this;
13826
13827	}
13828
13829	static fromJSON( data ) {
13830
13831		return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );
13832
13833	}
13834
13835}
13836
13837var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif";
13838
13839var 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";
13840
13841var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif";
13842
13843var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
13844
13845var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif";
13846
13847var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif";
13848
13849var 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
13849( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif";
13850
13851var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
13852
13853var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\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#endif";
13854
13855var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif";
13856
13857var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif";
13858
13859var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
13860
13861var 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";
13862
13863var 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 );
13863\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";
13864
13865var 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";
13866
13867var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
13868
13869var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
13870
13871var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
13872
13873var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
13874
13875var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif";
13876
13877var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif";
13878
13879var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
13880
13881var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
13882
13883var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\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";
13884
13885var 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";
13886
13887var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
13887\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
13888
13889var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
13890
13891var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif";
13892
13893var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
13894
13895var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
13896
13897var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
13898
13899var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}";
13900
13901var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
13902
13903var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif";
13904
13905var 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";
13906
13907var 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";
13908
13909var 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}
13909 else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
13910
13911var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif";
13912
13913var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif";
13914
13915var 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";
13916
13917var 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";
13918
13919var 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}";
13920
13921var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif";
13922
13923var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
13924
13925var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;";
13926
13927var 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";
13928
13929var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}
13929\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";
13930
13931var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif";
13932
13933var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
13934
13935var 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";
13936
13937var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
13938
13939var 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
13939( 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";
13940
13941var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;
13941\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_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif";
13942�
vendor: 15,344 bytes, lines 13942-13943
13942
13943var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n    float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n    float x2 = x * x;\n    float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n    return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3(    0, 1,    0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
13943
13944
13945var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.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.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
13946
13947var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif";
13948
13949var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif";
13950
13951var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
13952
13953var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
13954
13955var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif";
13956
13957var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
13958
13959var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif";
13960
13961var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
13962
13963var 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";
13964
13965var 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";
13966
13967var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
13968
13969var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
13970
13971var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\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";
13972
13973var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif";
13974
13975var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif";
13976
13977var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif";
13978
13979var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;";
13980
13981var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );
13981\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
13982
13983var 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";
13984
13985var 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";
13986
13987var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif";
13988
13989var 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";
13990
13991var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif";
13992
13993var 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";
13994
13995var 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";
13996
13997var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif";
13998
13999var 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 );";
14000
14001var 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.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( 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( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}";
14002
14003var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
14004
14005var 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;";
14006
14007var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
14008
14009var 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";
14010
14011var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
14012
14013var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
14014�
vendor: 9,177 bytes, lines 14014-14015
14014
14015var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif";
14015
14016
14017var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat 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 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 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";
14018
14019var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif";
14020
14021var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.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.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.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}";
14022
14023var 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";
14024
14025var 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";
14026
14027var 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";
14028
14029var 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";
14030
14031var 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";
14032
14033var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
14034
14035var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
14036�
vendor: 2,514 bytes, lines 14036-14037
14036
14037var 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 OptimizedCineonToneMapping( 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 
14037= LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\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\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
14038
14039var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.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";
14040
14041var 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 ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\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";
14042
14043var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;
14043\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";
14044
14045var 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";
14046
14047var 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;
14047\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";
14048
14049var 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";
14050
14051const 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}";
14052
14053const 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}";
14054
14055const 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}";
14056
14057const 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 flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, 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}";
14058
14059const 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}";
14060
14061const 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}";
14062
14063const 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#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}";
14064
14065const 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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\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\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}";
14066
14067const 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#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}";
14068
14069const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\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 <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\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 = packDepthToRGBA( dist );\n}";
14070
14071const 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}";
14072
14073const 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}";
14074
14075const 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 <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}";
14076
14077const 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\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14078
14079const 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 <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}";
14080
14081const 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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14082
14083const 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 <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}";
14084
14085const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\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 <envmap_common_pars_fragment>\n#include <envmap_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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14086
14087const 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 <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>
14087\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
14088
14089const 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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14090
14091const 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 <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}";
14092
14093const 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 <packing>\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\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( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}";
14094
14095const 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 <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}";
14096
14097const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\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 <envmap_common_pars_fragment>\n#include <envmap_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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14098
14099const 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 <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}";
14100
14101const 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;
14101\n\tuniform float clearcoatRoughness;\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 <packing>\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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;
14101\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}";
14102
14103const 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 <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}";
14104
14105const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\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\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14106
14107const 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 <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}";
14108
14109const 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\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14110
14111const 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 <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}";
14112
14113const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\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}";
14114
14115const 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 * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
14116
14117const 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\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\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}";
14118
14119const ShaderChunk = {
14120	alphahash_fragment: alphahash_fragment,
14121	alphahash_pars_fragment: alphahash_pars_fragment,
14122	alphamap_fragment: alphamap_fragment,
14123	alphamap_pars_fragment: alphamap_pars_fragment,
14124	alphatest_fragment: alphatest_fragment,
14125	alphatest_pars_fragment: alphatest_pars_fragment,
14126	aomap_fragment: aomap_fragment,
14127	aomap_pars_fragment: aomap_pars_fragment,
14128	batching_pars_vertex: batching_pars_vertex,
14129	batching_vertex: batching_vertex,
14130	begin_vertex: begin_vertex,
14131	beginnormal_vertex: beginnormal_vertex,
14132	bsdfs: bsdfs,
14133	iridescence_fragment: iridescence_fragment,
14134	bumpmap_pars_fragment: bumpmap_pars_fragment,
14135	clipping_planes_fragment: clipping_planes_fragment,
14136	clipping_planes_pars_fragment: clipping_planes_pars_fragment,
14137	clipping_planes_pars_vertex: clipping_planes_pars_vertex,
14138	clipping_planes_vertex: clipping_planes_vertex,
14139	color_fragment: color_fragment,
14140	color_pars_fragment: color_pars_fragment,
14141	color_pars_vertex: color_pars_vertex,
14142	color_vertex: color_vertex,
14143	common: common,
14144	cube_uv_reflection_fragment: cube_uv_reflection_fragment,
14145	defaultnormal_vertex: defaultnormal_vertex,
vendor: 12,224 bytes, lines 14146-14616
14146	displacementmap_pars_vertex: displacementmap_pars_vertex,
14147	displacementmap_vertex: displacementmap_vertex,
14148	emissivemap_fragment: emissivemap_fragment,
14149	emissivemap_pars_fragment: emissivemap_pars_fragment,
14150	colorspace_fragment: colorspace_fragment,
14151	colorspace_pars_fragment: colorspace_pars_fragment,
14152	envmap_fragment: envmap_fragment,
14153	envmap_common_pars_fragment: envmap_common_pars_fragment,
14154	envmap_pars_fragment: envmap_pars_fragment,
14155	envmap_pars_vertex: envmap_pars_vertex,
14156	envmap_physical_pars_fragment: envmap_physical_pars_fragment,
14157	envmap_vertex: envmap_vertex,
14158	fog_vertex: fog_vertex,
14159	fog_pars_vertex: fog_pars_vertex,
14160	fog_fragment: fog_fragment,
14161	fog_pars_fragment: fog_pars_fragment,
14162	gradientmap_pars_fragment: gradientmap_pars_fragment,
14163	lightmap_fragment: lightmap_fragment,
14164	lightmap_pars_fragment: lightmap_pars_fragment,
14165	lights_lambert_fragment: lights_lambert_fragment,
14166	lights_lambert_pars_fragment: lights_lambert_pars_fragment,
14167	lights_pars_begin: lights_pars_begin,
14168	lights_toon_fragment: lights_toon_fragment,
14169	lights_toon_pars_fragment: lights_toon_pars_fragment,
14170	lights_phong_fragment: lights_phong_fragment,
14171	lights_phong_pars_fragment: lights_phong_pars_fragment,
14172	lights_physical_fragment: lights_physical_fragment,
14173	lights_physical_pars_fragment: lights_physical_pars_fragment,
14174	lights_fragment_begin: lights_fragment_begin,
14175	lights_fragment_maps: lights_fragment_maps,
14176	lights_fragment_end: lights_fragment_end,
14177	logdepthbuf_fragment: logdepthbuf_fragment,
14178	logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
14179	logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
14180	logdepthbuf_vertex: logdepthbuf_vertex,
14181	map_fragment: map_fragment,
14182	map_pars_fragment: map_pars_fragment,
14183	map_particle_fragment: map_particle_fragment,
14184	map_particle_pars_fragment: map_particle_pars_fragment,
14185	metalnessmap_fragment: metalnessmap_fragment,
14186	metalnessmap_pars_fragment: metalnessmap_pars_fragment,
14187	morphcolor_vertex: morphcolor_vertex,
14188	morphnormal_vertex: morphnormal_vertex,
14189	morphtarget_pars_vertex: morphtarget_pars_vertex,
14190	morphtarget_vertex: morphtarget_vertex,
14191	normal_fragment_begin: normal_fragment_begin,
14192	normal_fragment_maps: normal_fragment_maps,
14193	normal_pars_fragment: normal_pars_fragment,
14194	normal_pars_vertex: normal_pars_vertex,
14195	normal_vertex: normal_vertex,
14196	normalmap_pars_fragment: normalmap_pars_fragment,
14197	clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
14198	clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
14199	clearcoat_pars_fragment: clearcoat_pars_fragment,
14200	iridescence_pars_fragment: iridescence_pars_fragment,
14201	opaque_fragment: opaque_fragment,
14202	packing: packing,
14203	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
14204	project_vertex: project_vertex,
14205	dithering_fragment: dithering_fragment,
14206	dithering_pars_fragment: dithering_pars_fragment,
14207	roughnessmap_fragment: roughnessmap_fragment,
14208	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
14209	shadowmap_pars_fragment: shadowmap_pars_fragment,
14210	shadowmap_pars_vertex: shadowmap_pars_vertex,
14211	shadowmap_vertex: shadowmap_vertex,
14212	shadowmask_pars_fragment: shadowmask_pars_fragment,
14213	skinbase_vertex: skinbase_vertex,
14214	skinning_pars_vertex: skinning_pars_vertex,
14215	skinning_vertex: skinning_vertex,
14216	skinnormal_vertex: skinnormal_vertex,
14217	specularmap_fragment: specularmap_fragment,
14218	specularmap_pars_fragment: specularmap_pars_fragment,
14219	tonemapping_fragment: tonemapping_fragment,
14220	tonemapping_pars_fragment: tonemapping_pars_fragment,
14221	transmission_fragment: transmission_fragment,
14222	transmission_pars_fragment: transmission_pars_fragment,
14223	uv_pars_fragment: uv_pars_fragment,
14224	uv_pars_vertex: uv_pars_vertex,
14225	uv_vertex: uv_vertex,
14226	worldpos_vertex: worldpos_vertex,
14227
14228	background_vert: vertex$h,
14229	background_frag: fragment$h,
14230	backgroundCube_vert: vertex$g,
14231	backgroundCube_frag: fragment$g,
14232	cube_vert: vertex$f,
14233	cube_frag: fragment$f,
14234	depth_vert: vertex$e,
14235	depth_frag: fragment$e,
14236	distanceRGBA_vert: vertex$d,
14237	distanceRGBA_frag: fragment$d,
14238	equirect_vert: vertex$c,
14239	equirect_frag: fragment$c,
14240	linedashed_vert: vertex$b,
14241	linedashed_frag: fragment$b,
14242	meshbasic_vert: vertex$a,
14243	meshbasic_frag: fragment$a,
14244	meshlambert_vert: vertex$9,
14245	meshlambert_frag: fragment$9,
14246	meshmatcap_vert: vertex$8,
14247	meshmatcap_frag: fragment$8,
14248	meshnormal_vert: vertex$7,
14249	meshnormal_frag: fragment$7,
14250	meshphong_vert: vertex$6,
14251	meshphong_frag: fragment$6,
14252	meshphysical_vert: vertex$5,
14253	meshphysical_frag: fragment$5,
14254	meshtoon_vert: vertex$4,
14255	meshtoon_frag: fragment$4,
14256	points_vert: vertex$3,
14257	points_frag: fragment$3,
14258	shadow_vert: vertex$2,
14259	shadow_frag: fragment$2,
14260	sprite_vert: vertex$1,
14261	sprite_frag: fragment$1
14262};
14263
14264/**
14265 * Uniforms library for shared webgl shaders
14266 */
14267
14268const UniformsLib = {
14269
14270	common: {
14271
14272		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14273		opacity: { value: 1.0 },
14274
14275		map: { value: null },
14276		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14277
14278		alphaMap: { value: null },
14279		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14280
14281		alphaTest: { value: 0 }
14282
14283	},
14284
14285	specularmap: {
14286
14287		specularMap: { value: null },
14288		specularMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14289
14290	},
14291
14292	envmap: {
14293
14294		envMap: { value: null },
14295		flipEnvMap: { value: - 1 },
14296		reflectivity: { value: 1.0 }, // basic, lambert, phong
14297		ior: { value: 1.5 }, // physical
14298		refractionRatio: { value: 0.98 }, // basic, lambert, phong
14299
14300	},
14301
14302	aomap: {
14303
14304		aoMap: { value: null },
14305		aoMapIntensity: { value: 1 },
14306		aoMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14307
14308	},
14309
14310	lightmap: {
14311
14312		lightMap: { value: null },
14313		lightMapIntensity: { value: 1 },
14314		lightMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14315
14316	},
14317
14318	bumpmap: {
14319
14320		bumpMap: { value: null },
14321		bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14322		bumpScale: { value: 1 }
14323
14324	},
14325
14326	normalmap: {
14327
14328		normalMap: { value: null },
14329		normalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14330		normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }
14331
14332	},
14333
14334	displacementmap: {
14335
14336		displacementMap: { value: null },
14337		displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14338		displacementScale: { value: 1 },
14339		displacementBias: { value: 0 }
14340
14341	},
14342
14343	emissivemap: {
14344
14345		emissiveMap: { value: null },
14346		emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14347
14348	},
14349
14350	metalnessmap: {
14351
14352		metalnessMap: { value: null },
14353		metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14354
14355	},
14356
14357	roughnessmap: {
14358
14359		roughnessMap: { value: null },
14360		roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14361
14362	},
14363
14364	gradientmap: {
14365
14366		gradientMap: { value: null }
14367
14368	},
14369
14370	fog: {
14371
14372		fogDensity: { value: 0.00025 },
14373		fogNear: { value: 1 },
14374		fogFar: { value: 2000 },
14375		fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }
14376
14377	},
14378
14379	lights: {
14380
14381		ambientLightColor: { value: [] },
14382
14383		lightProbe: { value: [] },
14384
14385		directionalLights: { value: [], properties: {
14386			direction: {},
14387			color: {}
14388		} },
14389
14390		directionalLightShadows: { value: [], properties: {
14391			shadowBias: {},
14392			shadowNormalBias: {},
14393			shadowRadius: {},
14394			shadowMapSize: {}
14395		} },
14396
14397		directionalShadowMap: { value: [] },
14398		directionalShadowMatrix: { value: [] },
14399
14400		spotLights: { value: [], properties: {
14401			color: {},
14402			position: {},
14403			direction: {},
14404			distance: {},
14405			coneCos: {},
14406			penumbraCos: {},
14407			decay: {}
14408		} },
14409
14410		spotLightShadows: { value: [], properties: {
14411			shadowBias: {},
14412			shadowNormalBias: {},
14413			shadowRadius: {},
14414			shadowMapSize: {}
14415		} },
14416
14417		spotLightMap: { value: [] },
14418		spotShadowMap: { value: [] },
14419		spotLightMatrix: { value: [] },
14420
14421		pointLights: { value: [], properties: {
14422			color: {},
14423			position: {},
14424			decay: {},
14425			distance: {}
14426		} },
14427
14428		pointLightShadows: { value: [], properties: {
14429			shadowBias: {},
14430			shadowNormalBias: {},
14431			shadowRadius: {},
14432			shadowMapSize: {},
14433			shadowCameraNear: {},
14434			shadowCameraFar: {}
14435		} },
14436
14437		pointShadowMap: { value: [] },
14438		pointShadowMatrix: { value: [] },
14439
14440		hemisphereLights: { value: [], properties: {
14441			direction: {},
14442			skyColor: {},
14443			groundColor: {}
14444		} },
14445
14446		// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
14447		rectAreaLights: { value: [], properties: {
14448			color: {},
14449			position: {},
14450			width: {},
14451			height: {}
14452		} },
14453
14454		ltc_1: { value: null },
14455		ltc_2: { value: null }
14456
14457	},
14458
14459	points: {
14460
14461		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14462		opacity: { value: 1.0 },
14463		size: { value: 1.0 },
14464		scale: { value: 1.0 },
14465		map: { value: null },
14466		alphaMap: { value: null },
14467		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14468		alphaTest: { value: 0 },
14469		uvTransform: { value: /*@__PURE__*/ new Matrix3() }
14470
14471	},
14472
14473	sprite: {
14474
14475		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14476		opacity: { value: 1.0 },
14477		center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },
14478		rotation: { value: 0.0 },
14479		map: { value: null },
14480		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14481		alphaMap: { value: null },
14482		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14483		alphaTest: { value: 0 }
14484
14485	}
14486
14487};
14488
14489const ShaderLib = {
14490
14491	basic: {
14492
14493		uniforms: /*@__PURE__*/ mergeUniforms( [
14494			UniformsLib.common,
14495			UniformsLib.specularmap,
14496			UniformsLib.envmap,
14497			UniformsLib.aomap,
14498			UniformsLib.lightmap,
14499			UniformsLib.fog
14500		] ),
14501
14502		vertexShader: ShaderChunk.meshbasic_vert,
14503		fragmentShader: ShaderChunk.meshbasic_frag
14504
14505	},
14506
14507	lambert: {
14508
14509		uniforms: /*@__PURE__*/ mergeUniforms( [
14510			UniformsLib.common,
14511			UniformsLib.specularmap,
14512			UniformsLib.envmap,
14513			UniformsLib.aomap,
14514			UniformsLib.lightmap,
14515			UniformsLib.emissivemap,
14516			UniformsLib.bumpmap,
14517			UniformsLib.normalmap,
14518			UniformsLib.displacementmap,
14519			UniformsLib.fog,
14520			UniformsLib.lights,
14521			{
14522				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14523			}
14524		] ),
14525
14526		vertexShader: ShaderChunk.meshlambert_vert,
14527		fragmentShader: ShaderChunk.meshlambert_frag
14528
14529	},
14530
14531	phong: {
14532
14533		uniforms: /*@__PURE__*/ mergeUniforms( [
14534			UniformsLib.common,
14535			UniformsLib.specularmap,
14536			UniformsLib.envmap,
14537			UniformsLib.aomap,
14538			UniformsLib.lightmap,
14539			UniformsLib.emissivemap,
14540			UniformsLib.bumpmap,
14541			UniformsLib.normalmap,
14542			UniformsLib.displacementmap,
14543			UniformsLib.fog,
14544			UniformsLib.lights,
14545			{
14546				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14547				specular: { value: /*@__PURE__*/ new Color( 0x111111 ) },
14548				shininess: { value: 30 }
14549			}
14550		] ),
14551
14552		vertexShader: ShaderChunk.meshphong_vert,
14553		fragmentShader: ShaderChunk.meshphong_frag
14554
14555	},
14556
14557	standard: {
14558
14559		uniforms: /*@__PURE__*/ mergeUniforms( [
14560			UniformsLib.common,
14561			UniformsLib.envmap,
14562			UniformsLib.aomap,
14563			UniformsLib.lightmap,
14564			UniformsLib.emissivemap,
14565			UniformsLib.bumpmap,
14566			UniformsLib.normalmap,
14567			UniformsLib.displacementmap,
14568			UniformsLib.roughnessmap,
14569			UniformsLib.metalnessmap,
14570			UniformsLib.fog,
14571			UniformsLib.lights,
14572			{
14573				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14574				roughness: { value: 1.0 },
14575				metalness: { value: 0.0 },
14576				envMapIntensity: { value: 1 } // temporary
14577			}
14578		] ),
14579
14580		vertexShader: ShaderChunk.meshphysical_vert,
14581		fragmentShader: ShaderChunk.meshphysical_frag
14582
14583	},
14584
14585	toon: {
14586
14587		uniforms: /*@__PURE__*/ mergeUniforms( [
14588			UniformsLib.common,
14589			UniformsLib.aomap,
14590			UniformsLib.lightmap,
14591			UniformsLib.emissivemap,
14592			UniformsLib.bumpmap,
14593			UniformsLib.normalmap,
14594			UniformsLib.displacementmap,
14595			UniformsLib.gradientmap,
14596			UniformsLib.fog,
14597			UniformsLib.lights,
14598			{
14599				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14600			}
14601		] ),
14602
14603		vertexShader: ShaderChunk.meshtoon_vert,
14604		fragmentShader: ShaderChunk.meshtoon_frag
14605
14606	},
14607
14608	matcap: {
14609
14610		uniforms: /*@__PURE__*/ mergeUniforms( [
14611			UniformsLib.common,
14612			UniformsLib.bumpmap,
14613			UniformsLib.normalmap,
14614			UniformsLib.displacementmap,
14615			UniformsLib.fog,
14616			{
vendor: 5,494 bytes, lines 14617-14839
14617				matcap: { value: null }
14618			}
14619		] ),
14620
14621		vertexShader: ShaderChunk.meshmatcap_vert,
14622		fragmentShader: ShaderChunk.meshmatcap_frag
14623
14624	},
14625
14626	points: {
14627
14628		uniforms: /*@__PURE__*/ mergeUniforms( [
14629			UniformsLib.points,
14630			UniformsLib.fog
14631		] ),
14632
14633		vertexShader: ShaderChunk.points_vert,
14634		fragmentShader: ShaderChunk.points_frag
14635
14636	},
14637
14638	dashed: {
14639
14640		uniforms: /*@__PURE__*/ mergeUniforms( [
14641			UniformsLib.common,
14642			UniformsLib.fog,
14643			{
14644				scale: { value: 1 },
14645				dashSize: { value: 1 },
14646				totalSize: { value: 2 }
14647			}
14648		] ),
14649
14650		vertexShader: ShaderChunk.linedashed_vert,
14651		fragmentShader: ShaderChunk.linedashed_frag
14652
14653	},
14654
14655	depth: {
14656
14657		uniforms: /*@__PURE__*/ mergeUniforms( [
14658			UniformsLib.common,
14659			UniformsLib.displacementmap
14660		] ),
14661
14662		vertexShader: ShaderChunk.depth_vert,
14663		fragmentShader: ShaderChunk.depth_frag
14664
14665	},
14666
14667	normal: {
14668
14669		uniforms: /*@__PURE__*/ mergeUniforms( [
14670			UniformsLib.common,
14671			UniformsLib.bumpmap,
14672			UniformsLib.normalmap,
14673			UniformsLib.displacementmap,
14674			{
14675				opacity: { value: 1.0 }
14676			}
14677		] ),
14678
14679		vertexShader: ShaderChunk.meshnormal_vert,
14680		fragmentShader: ShaderChunk.meshnormal_frag
14681
14682	},
14683
14684	sprite: {
14685
14686		uniforms: /*@__PURE__*/ mergeUniforms( [
14687			UniformsLib.sprite,
14688			UniformsLib.fog
14689		] ),
14690
14691		vertexShader: ShaderChunk.sprite_vert,
14692		fragmentShader: ShaderChunk.sprite_frag
14693
14694	},
14695
14696	background: {
14697
14698		uniforms: {
14699			uvTransform: { value: /*@__PURE__*/ new Matrix3() },
14700			t2D: { value: null },
14701			backgroundIntensity: { value: 1 }
14702		},
14703
14704		vertexShader: ShaderChunk.background_vert,
14705		fragmentShader: ShaderChunk.background_frag
14706
14707	},
14708
14709	backgroundCube: {
14710
14711		uniforms: {
14712			envMap: { value: null },
14713			flipEnvMap: { value: - 1 },
14714			backgroundBlurriness: { value: 0 },
14715			backgroundIntensity: { value: 1 }
14716		},
14717
14718		vertexShader: ShaderChunk.backgroundCube_vert,
14719		fragmentShader: ShaderChunk.backgroundCube_frag
14720
14721	},
14722
14723	cube: {
14724
14725		uniforms: {
14726			tCube: { value: null },
14727			tFlip: { value: - 1 },
14728			opacity: { value: 1.0 }
14729		},
14730
14731		vertexShader: ShaderChunk.cube_vert,
14732		fragmentShader: ShaderChunk.cube_frag
14733
14734	},
14735
14736	equirect: {
14737
14738		uniforms: {
14739			tEquirect: { value: null },
14740		},
14741
14742		vertexShader: ShaderChunk.equirect_vert,
14743		fragmentShader: ShaderChunk.equirect_frag
14744
14745	},
14746
14747	distanceRGBA: {
14748
14749		uniforms: /*@__PURE__*/ mergeUniforms( [
14750			UniformsLib.common,
14751			UniformsLib.displacementmap,
14752			{
14753				referencePosition: { value: /*@__PURE__*/ new Vector3() },
14754				nearDistance: { value: 1 },
14755				farDistance: { value: 1000 }
14756			}
14757		] ),
14758
14759		vertexShader: ShaderChunk.distanceRGBA_vert,
14760		fragmentShader: ShaderChunk.distanceRGBA_frag
14761
14762	},
14763
14764	shadow: {
14765
14766		uniforms: /*@__PURE__*/ mergeUniforms( [
14767			UniformsLib.lights,
14768			UniformsLib.fog,
14769			{
14770				color: { value: /*@__PURE__*/ new Color( 0x00000 ) },
14771				opacity: { value: 1.0 }
14772			},
14773		] ),
14774
14775		vertexShader: ShaderChunk.shadow_vert,
14776		fragmentShader: ShaderChunk.shadow_frag
14777
14778	}
14779
14780};
14781
14782ShaderLib.physical = {
14783
14784	uniforms: /*@__PURE__*/ mergeUniforms( [
14785		ShaderLib.standard.uniforms,
14786		{
14787			clearcoat: { value: 0 },
14788			clearcoatMap: { value: null },
14789			clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14790			clearcoatNormalMap: { value: null },
14791			clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14792			clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },
14793			clearcoatRoughness: { value: 0 },
14794			clearcoatRoughnessMap: { value: null },
14795			clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14796			iridescence: { value: 0 },
14797			iridescenceMap: { value: null },
14798			iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14799			iridescenceIOR: { value: 1.3 },
14800			iridescenceThicknessMinimum: { value: 100 },
14801			iridescenceThicknessMaximum: { value: 400 },
14802			iridescenceThicknessMap: { value: null },
14803			iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14804			sheen: { value: 0 },
14805			sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14806			sheenColorMap: { value: null },
14807			sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14808			sheenRoughness: { value: 1 },
14809			sheenRoughnessMap: { value: null },
14810			sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14811			transmission: { value: 0 },
14812			transmissionMap: { value: null },
14813			transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14814			transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },
14815			transmissionSamplerMap: { value: null },
14816			thickness: { value: 0 },
14817			thicknessMap: { value: null },
14818			thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14819			attenuationDistance: { value: 0 },
14820			attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14821			specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },
14822			specularColorMap: { value: null },
14823			specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14824			specularIntensity: { value: 1 },
14825			specularIntensityMap: { value: null },
14826			specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14827			anisotropyVector: { value: /*@__PURE__*/ new Vector2() },
14828			anisotropyMap: { value: null },
14829			anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14830		}
14831	] ),
14832
14833	vertexShader: ShaderChunk.meshphysical_vert,
14834	fragmentShader: ShaderChunk.meshphysical_frag
14835
14836};
14837
14838const _rgb = { r: 0, b: 0, g: 0 };
14839
vendor: 24,395 bytes, lines 14840-15869
14840function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) {
14841
14842	const clearColor = new Color( 0x000000 );
14843	let clearAlpha = alpha === true ? 0 : 1;
14844
14845	let planeMesh;
14846	let boxMesh;
14847
14848	let currentBackground = null;
14849	let currentBackgroundVersion = 0;
14850	let currentTonemapping = null;
14851
14852	function render( renderList, scene ) {
14853
14854		let forceClear = false;
14855		let background = scene.isScene === true ? scene.background : null;
14856
14857		if ( background && background.isTexture ) {
14858
14859			const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background
14860			background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );
14861
14862		}
14863
14864		if ( background === null ) {
14865
14866			setClear( clearColor, clearAlpha );
14867
14868		} else if ( background && background.isColor ) {
14869
14870			setClear( background, 1 );
14871			forceClear = true;
14872
14873		}
14874
14875		const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();
14876
14877		if ( environmentBlendMode === 'additive' ) {
14878
14879			state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
14880
14881		} else if ( environmentBlendMode === 'alpha-blend' ) {
14882
14883			state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
14884
14885		}
14886
14887		if ( renderer.autoClear || forceClear ) {
14888
14889			renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
14890
14891		}
14892
14893		if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {
14894
14895			if ( boxMesh === undefined ) {
14896
14897				boxMesh = new Mesh(
14898					new BoxGeometry( 1, 1, 1 ),
14899					new ShaderMaterial( {
14900						name: 'BackgroundCubeMaterial',
14901						uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
14902						vertexShader: ShaderLib.backgroundCube.vertexShader,
14903						fragmentShader: ShaderLib.backgroundCube.fragmentShader,
14904						side: BackSide,
14905						depthTest: false,
14906						depthWrite: false,
14907						fog: false
14908					} )
14909				);
14910
14911				boxMesh.geometry.deleteAttribute( 'normal' );
14912				boxMesh.geometry.deleteAttribute( 'uv' );
14913
14914				boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
14915
14916					this.matrixWorld.copyPosition( camera.matrixWorld );
14917
14918				};
14919
14920				// add "envMap" material property so the renderer can evaluate it like for built-in materials
14921				Object.defineProperty( boxMesh.material, 'envMap', {
14922
14923					get: function () {
14924
14925						return this.uniforms.envMap.value;
14926
14927					}
14928
14929				} );
14930
14931				objects.update( boxMesh );
14932
14933			}
14934
14935			boxMesh.material.uniforms.envMap.value = background;
14936			boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;
14937			boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
14938			boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
14939			boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14940
14941			if ( currentBackground !== background ||
14942				currentBackgroundVersion !== background.version ||
14943				currentTonemapping !== renderer.toneMapping ) {
14944
14945				boxMesh.material.needsUpdate = true;
14946
14947				currentBackground = background;
14948				currentBackgroundVersion = background.version;
14949				currentTonemapping = renderer.toneMapping;
14950
14951			}
14952
14953			boxMesh.layers.enableAll();
14954
14955			// push to the pre-sorted opaque render list
14956			renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
14957
14958		} else if ( background && background.isTexture ) {
14959
14960			if ( planeMesh === undefined ) {
14961
14962				planeMesh = new Mesh(
14963					new PlaneGeometry( 2, 2 ),
14964					new ShaderMaterial( {
14965						name: 'BackgroundMaterial',
14966						uniforms: cloneUniforms( ShaderLib.background.uniforms ),
14967						vertexShader: ShaderLib.background.vertexShader,
14968						fragmentShader: ShaderLib.background.fragmentShader,
14969						side: FrontSide,
14970						depthTest: false,
14971						depthWrite: false,
14972						fog: false
14973					} )
14974				);
14975
14976				planeMesh.geometry.deleteAttribute( 'normal' );
14977
14978				// add "map" material property so the renderer can evaluate it like for built-in materials
14979				Object.defineProperty( planeMesh.material, 'map', {
14980
14981					get: function () {
14982
14983						return this.uniforms.t2D.value;
14984
14985					}
14986
14987				} );
14988
14989				objects.update( planeMesh );
14990
14991			}
14992
14993			planeMesh.material.uniforms.t2D.value = background;
14994			planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
14995			planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14996
14997			if ( background.matrixAutoUpdate === true ) {
14998
14999				background.updateMatrix();
15000
15001			}
15002
15003			planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
15004
15005			if ( currentBackground !== background ||
15006				currentBackgroundVersion !== background.version ||
15007				currentTonemapping !== renderer.toneMapping ) {
15008
15009				planeMesh.material.needsUpdate = true;
15010
15011				currentBackground = background;
15012				currentBackgroundVersion = background.version;
15013				currentTonemapping = renderer.toneMapping;
15014
15015			}
15016
15017			planeMesh.layers.enableAll();
15018
15019			// push to the pre-sorted opaque render list
15020			renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
15021
15022		}
15023
15024	}
15025
15026	function setClear( color, alpha ) {
15027
15028		color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );
15029
15030		state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );
15031
15032	}
15033
15034	return {
15035
15036		getClearColor: function () {
15037
15038			return clearColor;
15039
15040		},
15041		setClearColor: function ( color, alpha = 1 ) {
15042
15043			clearColor.set( color );
15044			clearAlpha = alpha;
15045			setClear( clearColor, clearAlpha );
15046
15047		},
15048		getClearAlpha: function () {
15049
15050			return clearAlpha;
15051
15052		},
15053		setClearAlpha: function ( alpha ) {
15054
15055			clearAlpha = alpha;
15056			setClear( clearColor, clearAlpha );
15057
15058		},
15059		render: render
15060
15061	};
15062
15063}
15064
15065function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
15066
15067	const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15068
15069	const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
15070	const vaoAvailable = capabilities.isWebGL2 || extension !== null;
15071
15072	const bindingStates = {};
15073
15074	const defaultState = createBindingState( null );
15075	let currentState = defaultState;
15076	let forceUpdate = false;
15077
15078	function setup( object, material, program, geometry, index ) {
15079
15080		let updateBuffers = false;
15081
15082		if ( vaoAvailable ) {
15083
15084			const state = getBindingState( geometry, program, material );
15085
15086			if ( currentState !== state ) {
15087
15088				currentState = state;
15089				bindVertexArrayObject( currentState.object );
15090
15091			}
15092
15093			updateBuffers = needsUpdate( object, geometry, program, index );
15094
15095			if ( updateBuffers ) saveCache( object, geometry, program, index );
15096
15097		} else {
15098
15099			const wireframe = ( material.wireframe === true );
15100
15101			if ( currentState.geometry !== geometry.id ||
15102				currentState.program !== program.id ||
15103				currentState.wireframe !== wireframe ) {
15104
15105				currentState.geometry = geometry.id;
15106				currentState.program = program.id;
15107				currentState.wireframe = wireframe;
15108
15109				updateBuffers = true;
15110
15111			}
15112
15113		}
15114
15115		if ( index !== null ) {
15116
15117			attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
15118
15119		}
15120
15121		if ( updateBuffers || forceUpdate ) {
15122
15123			forceUpdate = false;
15124
15125			setupVertexAttributes( object, material, program, geometry );
15126
15127			if ( index !== null ) {
15128
15129				gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );
15130
15131			}
15132
15133		}
15134
15135	}
15136
15137	function createVertexArrayObject() {
15138
15139		if ( capabilities.isWebGL2 ) return gl.createVertexArray();
15140
15141		return extension.createVertexArrayOES();
15142
15143	}
15144
15145	function bindVertexArrayObject( vao ) {
15146
15147		if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
15148
15149		return extension.bindVertexArrayOES( vao );
15150
15151	}
15152
15153	function deleteVertexArrayObject( vao ) {
15154
15155		if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
15156
15157		return extension.deleteVertexArrayOES( vao );
15158
15159	}
15160
15161	function getBindingState( geometry, program, material ) {
15162
15163		const wireframe = ( material.wireframe === true );
15164
15165		let programMap = bindingStates[ geometry.id ];
15166
15167		if ( programMap === undefined ) {
15168
15169			programMap = {};
15170			bindingStates[ geometry.id ] = programMap;
15171
15172		}
15173
15174		let stateMap = programMap[ program.id ];
15175
15176		if ( stateMap === undefined ) {
15177
15178			stateMap = {};
15179			programMap[ program.id ] = stateMap;
15180
15181		}
15182
15183		let state = stateMap[ wireframe ];
15184
15185		if ( state === undefined ) {
15186
15187			state = createBindingState( createVertexArrayObject() );
15188			stateMap[ wireframe ] = state;
15189
15190		}
15191
15192		return state;
15193
15194	}
15195
15196	function createBindingState( vao ) {
15197
15198		const newAttributes = [];
15199		const enabledAttributes = [];
15200		const attributeDivisors = [];
15201
15202		for ( let i = 0; i < maxVertexAttributes; i ++ ) {
15203
15204			newAttributes[ i ] = 0;
15205			enabledAttributes[ i ] = 0;
15206			attributeDivisors[ i ] = 0;
15207
15208		}
15209
15210		return {
15211
15212			// for backward compatibility on non-VAO support browser
15213			geometry: null,
15214			program: null,
15215			wireframe: false,
15216
15217			newAttributes: newAttributes,
15218			enabledAttributes: enabledAttributes,
15219			attributeDivisors: attributeDivisors,
15220			object: vao,
15221			attributes: {},
15222			index: null
15223
15224		};
15225
15226	}
15227
15228	function needsUpdate( object, geometry, program, index ) {
15229
15230		const cachedAttributes = currentState.attributes;
15231		const geometryAttributes = geometry.attributes;
15232
15233		let attributesNum = 0;
15234
15235		const programAttributes = program.getAttributes();
15236
15237		for ( const name in programAttributes ) {
15238
15239			const programAttribute = programAttributes[ name ];
15240
15241			if ( programAttribute.location >= 0 ) {
15242
15243				const cachedAttribute = cachedAttributes[ name ];
15244				let geometryAttribute = geometryAttributes[ name ];
15245
15246				if ( geometryAttribute === undefined ) {
15247
15248					if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15249					if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15250
15251				}
15252
15253				if ( cachedAttribute === undefined ) return true;
15254
15255				if ( cachedAttribute.attribute !== geometryAttribute ) return true;
15256
15257				if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;
15258
15259				attributesNum ++;
15260
15261			}
15262
15263		}
15264
15265		if ( currentState.attributesNum !== attributesNum ) return true;
15266
15267		if ( currentState.index !== index ) return true;
15268
15269		return false;
15270
15271	}
15272
15273	function saveCache( object, geometry, program, index ) {
15274
15275		const cache = {};
15276		const attributes = geometry.attributes;
15277		let attributesNum = 0;
15278
15279		const programAttributes = program.getAttributes();
15280
15281		for ( const name in programAttributes ) {
15282
15283			const programAttribute = programAttributes[ name ];
15284
15285			if ( programAttribute.location >= 0 ) {
15286
15287				let attribute = attributes[ name ];
15288
15289				if ( attribute === undefined ) {
15290
15291					if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;
15292					if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;
15293
15294				}
15295
15296				const data = {};
15297				data.attribute = attribute;
15298
15299				if ( attribute && attribute.data ) {
15300
15301					data.data = attribute.data;
15302
15303				}
15304
15305				cache[ name ] = data;
15306
15307				attributesNum ++;
15308
15309			}
15310
15311		}
15312
15313		currentState.attributes = cache;
15314		currentState.attributesNum = attributesNum;
15315
15316		currentState.index = index;
15317
15318	}
15319
15320	function initAttributes() {
15321
15322		const newAttributes = currentState.newAttributes;
15323
15324		for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
15325
15326			newAttributes[ i ] = 0;
15327
15328		}
15329
15330	}
15331
15332	function enableAttribute( attribute ) {
15333
15334		enableAttributeAndDivisor( attribute, 0 );
15335
15336	}
15337
15338	function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
15339
15340		const newAttributes = currentState.newAttributes;
15341		const enabledAttributes = currentState.enabledAttributes;
15342		const attributeDivisors = currentState.attributeDivisors;
15343
15344		newAttributes[ attribute ] = 1;
15345
15346		if ( enabledAttributes[ attribute ] === 0 ) {
15347
15348			gl.enableVertexAttribArray( attribute );
15349			enabledAttributes[ attribute ] = 1;
15350
15351		}
15352
15353		if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
15354
15355			const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
15356
15357			extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
15358			attributeDivisors[ attribute ] = meshPerAttribute;
15359
15360		}
15361
15362	}
15363
15364	function disableUnusedAttributes() {
15365
15366		const newAttributes = currentState.newAttributes;
15367		const enabledAttributes = currentState.enabledAttributes;
15368
15369		for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
15370
15371			if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
15372
15373				gl.disableVertexAttribArray( i );
15374				enabledAttributes[ i ] = 0;
15375
15376			}
15377
15378		}
15379
15380	}
15381
15382	function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {
15383
15384		if ( integer === true ) {
15385
15386			gl.vertexAttribIPointer( index, size, type, stride, offset );
15387
15388		} else {
15389
15390			gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
15391
15392		}
15393
15394	}
15395
15396	function setupVertexAttributes( object, material, program, geometry ) {
15397
15398		if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
15399
15400			if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
15401
15402		}
15403
15404		initAttributes();
15405
15406		const geometryAttributes = geometry.attributes;
15407
15408		const programAttributes = program.getAttributes();
15409
15410		const materialDefaultAttributeValues = material.defaultAttributeValues;
15411
15412		for ( const name in programAttributes ) {
15413
15414			const programAttribute = programAttributes[ name ];
15415
15416			if ( programAttribute.location >= 0 ) {
15417
15418				let geometryAttribute = geometryAttributes[ name ];
15419
15420				if ( geometryAttribute === undefined ) {
15421
15422					if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15423					if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15424
15425				}
15426
15427				if ( geometryAttribute !== undefined ) {
15428
15429					const normalized = geometryAttribute.normalized;
15430					const size = geometryAttribute.itemSize;
15431
15432					const attribute = attributes.get( geometryAttribute );
15433
15434					// TODO Attribute may not be available on context restore
15435
15436					if ( attribute === undefined ) continue;
15437
15438					const buffer = attribute.buffer;
15439					const type = attribute.type;
15440					const bytesPerElement = attribute.bytesPerElement;
15441
15442					// check for integer attributes (WebGL 2 only)
15443
15444					const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) );
15445
15446					if ( geometryAttribute.isInterleavedBufferAttribute ) {
15447
15448						const data = geometryAttribute.data;
15449						const stride = data.stride;
15450						const offset = geometryAttribute.offset;
15451
15452						if ( data.isInstancedInterleavedBuffer ) {
15453
15454							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15455
15456								enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );
15457
15458							}
15459
15460							if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15461
15462								geometry._maxInstanceCount = data.meshPerAttribute * data.count;
15463
15464							}
15465
15466						} else {
15467
15468							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15469
15470								enableAttribute( programAttribute.location + i );
15471
15472							}
15473
15474						}
15475
15476						gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15477
15478						for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15479
15480							vertexAttribPointer(
15481								programAttribute.location + i,
15482								size / programAttribute.locationSize,
15483								type,
15484								normalized,
15485								stride * bytesPerElement,
15486								( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,
15487								integer
15488							);
15489
15490						}
15491
15492					} else {
15493
15494						if ( geometryAttribute.isInstancedBufferAttribute ) {
15495
15496							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15497
15498								enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );
15499
15500							}
15501
15502							if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15503
15504								geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
15505
15506							}
15507
15508						} else {
15509
15510							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15511
15512								enableAttribute( programAttribute.location + i );
15513
15514							}
15515
15516						}
15517
15518						gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15519
15520						for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15521
15522							vertexAttribPointer(
15523								programAttribute.location + i,
15524								size / programAttribute.locationSize,
15525								type,
15526								normalized,
15527								size * bytesPerElement,
15528								( size / programAttribute.locationSize ) * i * bytesPerElement,
15529								integer
15530							);
15531
15532						}
15533
15534					}
15535
15536				} else if ( materialDefaultAttributeValues !== undefined ) {
15537
15538					const value = materialDefaultAttributeValues[ name ];
15539
15540					if ( value !== undefined ) {
15541
15542						switch ( value.length ) {
15543
15544							case 2:
15545								gl.vertexAttrib2fv( programAttribute.location, value );
15546								break;
15547
15548							case 3:
15549								gl.vertexAttrib3fv( programAttribute.location, value );
15550								break;
15551
15552							case 4:
15553								gl.vertexAttrib4fv( programAttribute.location, value );
15554								break;
15555
15556							default:
15557								gl.vertexAttrib1fv( programAttribute.location, value );
15558
15559						}
15560
15561					}
15562
15563				}
15564
15565			}
15566
15567		}
15568
15569		disableUnusedAttributes();
15570
15571	}
15572
15573	function dispose() {
15574
15575		reset();
15576
15577		for ( const geometryId in bindingStates ) {
15578
15579			const programMap = bindingStates[ geometryId ];
15580
15581			for ( const programId in programMap ) {
15582
15583				const stateMap = programMap[ programId ];
15584
15585				for ( const wireframe in stateMap ) {
15586
15587					deleteVertexArrayObject( stateMap[ wireframe ].object );
15588
15589					delete stateMap[ wireframe ];
15590
15591				}
15592
15593				delete programMap[ programId ];
15594
15595			}
15596
15597			delete bindingStates[ geometryId ];
15598
15599		}
15600
15601	}
15602
15603	function releaseStatesOfGeometry( geometry ) {
15604
15605		if ( bindingStates[ geometry.id ] === undefined ) return;
15606
15607		const programMap = bindingStates[ geometry.id ];
15608
15609		for ( const programId in programMap ) {
15610
15611			const stateMap = programMap[ programId ];
15612
15613			for ( const wireframe in stateMap ) {
15614
15615				deleteVertexArrayObject( stateMap[ wireframe ].object );
15616
15617				delete stateMap[ wireframe ];
15618
15619			}
15620
15621			delete programMap[ programId ];
15622
15623		}
15624
15625		delete bindingStates[ geometry.id ];
15626
15627	}
15628
15629	function releaseStatesOfProgram( program ) {
15630
15631		for ( const geometryId in bindingStates ) {
15632
15633			const programMap = bindingStates[ geometryId ];
15634
15635			if ( programMap[ program.id ] === undefined ) continue;
15636
15637			const stateMap = programMap[ program.id ];
15638
15639			for ( const wireframe in stateMap ) {
15640
15641				deleteVertexArrayObject( stateMap[ wireframe ].object );
15642
15643				delete stateMap[ wireframe ];
15644
15645			}
15646
15647			delete programMap[ program.id ];
15648
15649		}
15650
15651	}
15652
15653	function reset() {
15654
15655		resetDefaultState();
15656		forceUpdate = true;
15657
15658		if ( currentState === defaultState ) return;
15659
15660		currentState = defaultState;
15661		bindVertexArrayObject( currentState.object );
15662
15663	}
15664
15665	// for backward-compatibility
15666
15667	function resetDefaultState() {
15668
15669		defaultState.geometry = null;
15670		defaultState.program = null;
15671		defaultState.wireframe = false;
15672
15673	}
15674
15675	return {
15676
15677		setup: setup,
15678		reset: reset,
15679		resetDefaultState: resetDefaultState,
15680		dispose: dispose,
15681		releaseStatesOfGeometry: releaseStatesOfGeometry,
15682		releaseStatesOfProgram: releaseStatesOfProgram,
15683
15684		initAttributes: initAttributes,
15685		enableAttribute: enableAttribute,
15686		disableUnusedAttributes: disableUnusedAttributes
15687
15688	};
15689
15690}
15691
15692function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
15693
15694	const isWebGL2 = capabilities.isWebGL2;
15695
15696	let mode;
15697
15698	function setMode( value ) {
15699
15700		mode = value;
15701
15702	}
15703
15704	function render( start, count ) {
15705
15706		gl.drawArrays( mode, start, count );
15707
15708		info.update( count, mode, 1 );
15709
15710	}
15711
15712	function renderInstances( start, count, primcount ) {
15713
15714		if ( primcount === 0 ) return;
15715
15716		let extension, methodName;
15717
15718		if ( isWebGL2 ) {
15719
15720			extension = gl;
15721			methodName = 'drawArraysInstanced';
15722
15723		} else {
15724
15725			extension = extensions.get( 'ANGLE_instanced_arrays' );
15726			methodName = 'drawArraysInstancedANGLE';
15727
15728			if ( extension === null ) {
15729
15730				console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
15731				return;
15732
15733			}
15734
15735		}
15736
15737		extension[ methodName ]( mode, start, count, primcount );
15738
15739		info.update( count, mode, primcount );
15740
15741	}
15742
15743	function renderMultiDraw( starts, counts, drawCount ) {
15744
15745		if ( drawCount === 0 ) return;
15746
15747		const extension = extensions.get( 'WEBGL_multi_draw' );
15748		if ( extension === null ) {
15749
15750			for ( let i = 0; i < drawCount; i ++ ) {
15751
15752				this.render( starts[ i ], counts[ i ] );
15753
15754			}
15755
15756		} else {
15757
15758			extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );
15759
15760			let elementCount = 0;
15761			for ( let i = 0; i < drawCount; i ++ ) {
15762
15763				elementCount += counts[ i ];
15764
15765			}
15766
15767			info.update( elementCount, mode, 1 );
15768
15769		}
15770
15771	}
15772
15773	//
15774
15775	this.setMode = setMode;
15776	this.render = render;
15777	this.renderInstances = renderInstances;
15778	this.renderMultiDraw = renderMultiDraw;
15779
15780}
15781
15782function WebGLCapabilities( gl, extensions, parameters ) {
15783
15784	let maxAnisotropy;
15785
15786	function getMaxAnisotropy() {
15787
15788		if ( maxAnisotropy !== undefined ) return maxAnisotropy;
15789
15790		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
15791
15792			const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
15793
15794			maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
15795
15796		} else {
15797
15798			maxAnisotropy = 0;
15799
15800		}
15801
15802		return maxAnisotropy;
15803
15804	}
15805
15806	function getMaxPrecision( precision ) {
15807
15808		if ( precision === 'highp' ) {
15809
15810			if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
15811				gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
15812
15813				return 'highp';
15814
15815			}
15816
15817			precision = 'mediump';
15818
15819		}
15820
15821		if ( precision === 'mediump' ) {
15822
15823			if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
15824				gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
15825
15826				return 'mediump';
15827
15828			}
15829
15830		}
15831
15832		return 'lowp';
15833
15834	}
15835
15836	const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext';
15837
15838	let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
15839	const maxPrecision = getMaxPrecision( precision );
15840
15841	if ( maxPrecision !== precision ) {
15842
15843		console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
15844		precision = maxPrecision;
15845
15846	}
15847
15848	const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' );
15849
15850	const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
15851
15852	const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
15853	const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
15854	const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
15855	const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
15856
15857	const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15858	const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
15859	const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
15860	const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
15861
15862	const vertexTextures = maxVertexTextures > 0;
15863	const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' );
15864	const floatVertexTextures = vertexTextures && floatFragmentTextures;
15865
15866	const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0;
15867
15868	return {
15869
vendor: 1,924 bytes, lines 15870-15958
15870		isWebGL2: isWebGL2,
15871
15872		drawBuffers: drawBuffers,
15873
15874		getMaxAnisotropy: getMaxAnisotropy,
15875		getMaxPrecision: getMaxPrecision,
15876
15877		precision: precision,
15878		logarithmicDepthBuffer: logarithmicDepthBuffer,
15879
15880		maxTextures: maxTextures,
15881		maxVertexTextures: maxVertexTextures,
15882		maxTextureSize: maxTextureSize,
15883		maxCubemapSize: maxCubemapSize,
15884
15885		maxAttributes: maxAttributes,
15886		maxVertexUniforms: maxVertexUniforms,
15887		maxVaryings: maxVaryings,
15888		maxFragmentUniforms: maxFragmentUniforms,
15889
15890		vertexTextures: vertexTextures,
15891		floatFragmentTextures: floatFragmentTextures,
15892		floatVertexTextures: floatVertexTextures,
15893
15894		maxSamples: maxSamples
15895
15896	};
15897
15898}
15899
15900function WebGLClipping( properties ) {
15901
15902	const scope = this;
15903
15904	let globalState = null,
15905		numGlobalPlanes = 0,
15906		localClippingEnabled = false,
15907		renderingShadows = false;
15908
15909	const plane = new Plane(),
15910		viewNormalMatrix = new Matrix3(),
15911
15912		uniform = { value: null, needsUpdate: false };
15913
15914	this.uniform = uniform;
15915	this.numPlanes = 0;
15916	this.numIntersection = 0;
15917
15918	this.init = function ( planes, enableLocalClipping ) {
15919
15920		const enabled =
15921			planes.length !== 0 ||
15922			enableLocalClipping ||
15923			// enable state of previous frame - the clipping code has to
15924			// run another frame in order to reset the state:
15925			numGlobalPlanes !== 0 ||
15926			localClippingEnabled;
15927
15928		localClippingEnabled = enableLocalClipping;
15929
15930		numGlobalPlanes = planes.length;
15931
15932		return enabled;
15933
15934	};
15935
15936	this.beginShadows = function () {
15937
15938		renderingShadows = true;
15939		projectPlanes( null );
15940
15941	};
15942
15943	this.endShadows = function () {
15944
15945		renderingShadows = false;
15946
15947	};
15948
15949	this.setGlobalState = function ( planes, camera ) {
15950
15951		globalState = projectPlanes( planes, camera, 0 );
15952
15953	};
15954
15955	this.setState = function ( material, camera, useCache ) {
15956
15957		const planes = material.clippingPlanes,
15958			clipIntersection = material.clipIntersection,
vendor: 24,263 bytes, lines 15959-16936
15959			clipShadows = material.clipShadows;
15960
15961		const materialProperties = properties.get( material );
15962
15963		if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
15964
15965			// there's no local clipping
15966
15967			if ( renderingShadows ) {
15968
15969				// there's no global clipping
15970
15971				projectPlanes( null );
15972
15973			} else {
15974
15975				resetGlobalState();
15976
15977			}
15978
15979		} else {
15980
15981			const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
15982				lGlobal = nGlobal * 4;
15983
15984			let dstArray = materialProperties.clippingState || null;
15985
15986			uniform.value = dstArray; // ensure unique state
15987
15988			dstArray = projectPlanes( planes, camera, lGlobal, useCache );
15989
15990			for ( let i = 0; i !== lGlobal; ++ i ) {
15991
15992				dstArray[ i ] = globalState[ i ];
15993
15994			}
15995
15996			materialProperties.clippingState = dstArray;
15997			this.numIntersection = clipIntersection ? this.numPlanes : 0;
15998			this.numPlanes += nGlobal;
15999
16000		}
16001
16002
16003	};
16004
16005	function resetGlobalState() {
16006
16007		if ( uniform.value !== globalState ) {
16008
16009			uniform.value = globalState;
16010			uniform.needsUpdate = numGlobalPlanes > 0;
16011
16012		}
16013
16014		scope.numPlanes = numGlobalPlanes;
16015		scope.numIntersection = 0;
16016
16017	}
16018
16019	function projectPlanes( planes, camera, dstOffset, skipTransform ) {
16020
16021		const nPlanes = planes !== null ? planes.length : 0;
16022		let dstArray = null;
16023
16024		if ( nPlanes !== 0 ) {
16025
16026			dstArray = uniform.value;
16027
16028			if ( skipTransform !== true || dstArray === null ) {
16029
16030				const flatSize = dstOffset + nPlanes * 4,
16031					viewMatrix = camera.matrixWorldInverse;
16032
16033				viewNormalMatrix.getNormalMatrix( viewMatrix );
16034
16035				if ( dstArray === null || dstArray.length < flatSize ) {
16036
16037					dstArray = new Float32Array( flatSize );
16038
16039				}
16040
16041				for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
16042
16043					plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
16044
16045					plane.normal.toArray( dstArray, i4 );
16046					dstArray[ i4 + 3 ] = plane.constant;
16047
16048				}
16049
16050			}
16051
16052			uniform.value = dstArray;
16053			uniform.needsUpdate = true;
16054
16055		}
16056
16057		scope.numPlanes = nPlanes;
16058		scope.numIntersection = 0;
16059
16060		return dstArray;
16061
16062	}
16063
16064}
16065
16066function WebGLCubeMaps( renderer ) {
16067
16068	let cubemaps = new WeakMap();
16069
16070	function mapTextureMapping( texture, mapping ) {
16071
16072		if ( mapping === EquirectangularReflectionMapping ) {
16073
16074			texture.mapping = CubeReflectionMapping;
16075
16076		} else if ( mapping === EquirectangularRefractionMapping ) {
16077
16078			texture.mapping = CubeRefractionMapping;
16079
16080		}
16081
16082		return texture;
16083
16084	}
16085
16086	function get( texture ) {
16087
16088		if ( texture && texture.isTexture ) {
16089
16090			const mapping = texture.mapping;
16091
16092			if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
16093
16094				if ( cubemaps.has( texture ) ) {
16095
16096					const cubemap = cubemaps.get( texture ).texture;
16097					return mapTextureMapping( cubemap, texture.mapping );
16098
16099				} else {
16100
16101					const image = texture.image;
16102
16103					if ( image && image.height > 0 ) {
16104
16105						const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
16106						renderTarget.fromEquirectangularTexture( renderer, texture );
16107						cubemaps.set( texture, renderTarget );
16108
16109						texture.addEventListener( 'dispose', onTextureDispose );
16110
16111						return mapTextureMapping( renderTarget.texture, texture.mapping );
16112
16113					} else {
16114
16115						// image not yet ready. try the conversion next frame
16116
16117						return null;
16118
16119					}
16120
16121				}
16122
16123			}
16124
16125		}
16126
16127		return texture;
16128
16129	}
16130
16131	function onTextureDispose( event ) {
16132
16133		const texture = event.target;
16134
16135		texture.removeEventListener( 'dispose', onTextureDispose );
16136
16137		const cubemap = cubemaps.get( texture );
16138
16139		if ( cubemap !== undefined ) {
16140
16141			cubemaps.delete( texture );
16142			cubemap.dispose();
16143
16144		}
16145
16146	}
16147
16148	function dispose() {
16149
16150		cubemaps = new WeakMap();
16151
16152	}
16153
16154	return {
16155		get: get,
16156		dispose: dispose
16157	};
16158
16159}
16160
16161class OrthographicCamera extends Camera {
16162
16163	constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
16164
16165		super();
16166
16167		this.isOrthographicCamera = true;
16168
16169		this.type = 'OrthographicCamera';
16170
16171		this.zoom = 1;
16172		this.view = null;
16173
16174		this.left = left;
16175		this.right = right;
16176		this.top = top;
16177		this.bottom = bottom;
16178
16179		this.near = near;
16180		this.far = far;
16181
16182		this.updateProjectionMatrix();
16183
16184	}
16185
16186	copy( source, recursive ) {
16187
16188		super.copy( source, recursive );
16189
16190		this.left = source.left;
16191		this.right = source.right;
16192		this.top = source.top;
16193		this.bottom = source.bottom;
16194		this.near = source.near;
16195		this.far = source.far;
16196
16197		this.zoom = source.zoom;
16198		this.view = source.view === null ? null : Object.assign( {}, source.view );
16199
16200		return this;
16201
16202	}
16203
16204	setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
16205
16206		if ( this.view === null ) {
16207
16208			this.view = {
16209				enabled: true,
16210				fullWidth: 1,
16211				fullHeight: 1,
16212				offsetX: 0,
16213				offsetY: 0,
16214				width: 1,
16215				height: 1
16216			};
16217
16218		}
16219
16220		this.view.enabled = true;
16221		this.view.fullWidth = fullWidth;
16222		this.view.fullHeight = fullHeight;
16223		this.view.offsetX = x;
16224		this.view.offsetY = y;
16225		this.view.width = width;
16226		this.view.height = height;
16227
16228		this.updateProjectionMatrix();
16229
16230	}
16231
16232	clearViewOffset() {
16233
16234		if ( this.view !== null ) {
16235
16236			this.view.enabled = false;
16237
16238		}
16239
16240		this.updateProjectionMatrix();
16241
16242	}
16243
16244	updateProjectionMatrix() {
16245
16246		const dx = ( this.right - this.left ) / ( 2 * this.zoom );
16247		const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
16248		const cx = ( this.right + this.left ) / 2;
16249		const cy = ( this.top + this.bottom ) / 2;
16250
16251		let left = cx - dx;
16252		let right = cx + dx;
16253		let top = cy + dy;
16254		let bottom = cy - dy;
16255
16256		if ( this.view !== null && this.view.enabled ) {
16257
16258			const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
16259			const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
16260
16261			left += scaleW * this.view.offsetX;
16262			right = left + scaleW * this.view.width;
16263			top -= scaleH * this.view.offsetY;
16264			bottom = top - scaleH * this.view.height;
16265
16266		}
16267
16268		this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem );
16269
16270		this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
16271
16272	}
16273
16274	toJSON( meta ) {
16275
16276		const data = super.toJSON( meta );
16277
16278		data.object.zoom = this.zoom;
16279		data.object.left = this.left;
16280		data.object.right = this.right;
16281		data.object.top = this.top;
16282		data.object.bottom = this.bottom;
16283		data.object.near = this.near;
16284		data.object.far = this.far;
16285
16286		if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
16287
16288		return data;
16289
16290	}
16291
16292}
16293
16294const LOD_MIN = 4;
16295
16296// The standard deviations (radians) associated with the extra mips. These are
16297// chosen to approximate a Trowbridge-Reitz distribution function times the
16298// geometric shadowing function. These sigma values squared must match the
16299// variance #defines in cube_uv_reflection_fragment.glsl.js.
16300const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
16301
16302// The maximum length of the blur for loop. Smaller sigmas will use fewer
16303// samples and exit early, but not recompile the shader.
16304const MAX_SAMPLES = 20;
16305
16306const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
16307const _clearColor = /*@__PURE__*/ new Color();
16308let _oldTarget = null;
16309let _oldActiveCubeFace = 0;
16310let _oldActiveMipmapLevel = 0;
16311
16312// Golden Ratio
16313const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
16314const INV_PHI = 1 / PHI;
16315
16316// Vertices of a dodecahedron (except the opposites, which represent the
16317// same axis), used as axis directions evenly spread on a sphere.
16318const _axisDirections = [
16319	/*@__PURE__*/ new Vector3( 1, 1, 1 ),
16320	/*@__PURE__*/ new Vector3( - 1, 1, 1 ),
16321	/*@__PURE__*/ new Vector3( 1, 1, - 1 ),
16322	/*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
16323	/*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
16324	/*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
16325	/*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
16326	/*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
16327	/*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
16328	/*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
16329
16330/**
16331 * This class generates a Prefiltered, Mipmapped Radiance Environment Map
16332 * (PMREM) from a cubeMap environment texture. This allows different levels of
16333 * blur to be quickly accessed based on material roughness. It is packed into a
16334 * special CubeUV format that allows us to perform custom interpolation so that
16335 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
16336 * chain, it only goes down to the LOD_MIN level (above), and then creates extra
16337 * even more filtered 'mips' at the same LOD_MIN resolution, associated with
16338 * higher roughness levels. In this way we maintain resolution to smoothly
16339 * interpolate diffuse lighting while limiting sampling computation.
16340 *
16341 * Paper: Fast, Accurate Image-Based Lighting
16342 * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view
16343*/
16344
16345class PMREMGenerator {
16346
16347	constructor( renderer ) {
16348
16349		this._renderer = renderer;
16350		this._pingPongRenderTarget = null;
16351
16352		this._lodMax = 0;
16353		this._cubeSize = 0;
16354		this._lodPlanes = [];
16355		this._sizeLods = [];
16356		this._sigmas = [];
16357
16358		this._blurMaterial = null;
16359		this._cubemapMaterial = null;
16360		this._equirectMaterial = null;
16361
16362		this._compileMaterial( this._blurMaterial );
16363
16364	}
16365
16366	/**
16367	 * Generates a PMREM from a supplied Scene, which can be faster than using an
16368	 * image if networking bandwidth is low. Optional sigma specifies a blur radius
16369	 * in radians to be applied to the scene before PMREM generation. Optional near
16370	 * and far planes ensure the scene is rendered in its entirety (the cubeCamera
16371	 * is placed at the origin).
16372	 */
16373	fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
16374
16375		_oldTarget = this._renderer.getRenderTarget();
16376		_oldActiveCubeFace = this._renderer.getActiveCubeFace();
16377		_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16378
16379		this._setSize( 256 );
16380
16381		const cubeUVRenderTarget = this._allocateTargets();
16382		cubeUVRenderTarget.depthBuffer = true;
16383
16384		this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
16385
16386		if ( sigma > 0 ) {
16387
16388			this._blur( cubeUVRenderTarget, 0, 0, sigma );
16389
16390		}
16391
16392		this._applyPMREM( cubeUVRenderTarget );
16393		this._cleanup( cubeUVRenderTarget );
16394
16395		return cubeUVRenderTarget;
16396
16397	}
16398
16399	/**
16400	 * Generates a PMREM from an equirectangular texture, which can be either LDR
16401	 * or HDR. The ideal input image size is 1k (1024 x 512),
16402	 * as this matches best with the 256 x 256 cubemap output.
16403	 */
16404	fromEquirectangular( equirectangular, renderTarget = null ) {
16405
16406		return this._fromTexture( equirectangular, renderTarget );
16407
16408	}
16409
16410	/**
16411	 * Generates a PMREM from an cubemap texture, which can be either LDR
16412	 * or HDR. The ideal input cube size is 256 x 256,
16413	 * as this matches best with the 256 x 256 cubemap output.
16414	 */
16415	fromCubemap( cubemap, renderTarget = null ) {
16416
16417		return this._fromTexture( cubemap, renderTarget );
16418
16419	}
16420
16421	/**
16422	 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
16423	 * your texture's network fetch for increased concurrency.
16424	 */
16425	compileCubemapShader() {
16426
16427		if ( this._cubemapMaterial === null ) {
16428
16429			this._cubemapMaterial = _getCubemapMaterial();
16430			this._compileMaterial( this._cubemapMaterial );
16431
16432		}
16433
16434	}
16435
16436	/**
16437	 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
16438	 * your texture's network fetch for increased concurrency.
16439	 */
16440	compileEquirectangularShader() {
16441
16442		if ( this._equirectMaterial === null ) {
16443
16444			this._equirectMaterial = _getEquirectMaterial();
16445			this._compileMaterial( this._equirectMaterial );
16446
16447		}
16448
16449	}
16450
16451	/**
16452	 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
16453	 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
16454	 * one of them will cause any others to also become unusable.
16455	 */
16456	dispose() {
16457
16458		this._dispose();
16459
16460		if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
16461		if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
16462
16463	}
16464
16465	// private interface
16466
16467	_setSize( cubeSize ) {
16468
16469		this._lodMax = Math.floor( Math.log2( cubeSize ) );
16470		this._cubeSize = Math.pow( 2, this._lodMax );
16471
16472	}
16473
16474	_dispose() {
16475
16476		if ( this._blurMaterial !== null ) this._blurMaterial.dispose();
16477
16478		if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();
16479
16480		for ( let i = 0; i < this._lodPlanes.length; i ++ ) {
16481
16482			this._lodPlanes[ i ].dispose();
16483
16484		}
16485
16486	}
16487
16488	_cleanup( outputTarget ) {
16489
16490		this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
16491		outputTarget.scissorTest = false;
16492		_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
16493
16494	}
16495
16496	_fromTexture( texture, renderTarget ) {
16497
16498		if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
16499
16500			this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
16501
16502		} else { // Equirectangular
16503
16504			this._setSize( texture.image.width / 4 );
16505
16506		}
16507
16508		_oldTarget = this._renderer.getRenderTarget();
16509		_oldActiveCubeFace = this._renderer.getActiveCubeFace();
16510		_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16511
16512		const cubeUVRenderTarget = renderTarget || this._allocateTargets();
16513		this._textureToCubeUV( texture, cubeUVRenderTarget );
16514		this._applyPMREM( cubeUVRenderTarget );
16515		this._cleanup( cubeUVRenderTarget );
16516
16517		return cubeUVRenderTarget;
16518
16519	}
16520
16521	_allocateTargets() {
16522
16523		const width = 3 * Math.max( this._cubeSize, 16 * 7 );
16524		const height = 4 * this._cubeSize;
16525
16526		const params = {
16527			magFilter: LinearFilter,
16528			minFilter: LinearFilter,
16529			generateMipmaps: false,
16530			type: HalfFloatType,
16531			format: RGBAFormat,
16532			colorSpace: LinearSRGBColorSpace,
16533			depthBuffer: false
16534		};
16535
16536		const cubeUVRenderTarget = _createRenderTarget( width, height, params );
16537
16538		if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {
16539
16540			if ( this._pingPongRenderTarget !== null ) {
16541
16542				this._dispose();
16543
16544			}
16545
16546			this._pingPongRenderTarget = _createRenderTarget( width, height, params );
16547
16548			const { _lodMax } = this;
16549			( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );
16550
16551			this._blurMaterial = _getBlurShader( _lodMax, width, height );
16552
16553		}
16554
16555		return cubeUVRenderTarget;
16556
16557	}
16558
16559	_compileMaterial( material ) {
16560
16561		const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
16562		this._renderer.compile( tmpMesh, _flatCamera );
16563
16564	}
16565
16566	_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
16567
16568		const fov = 90;
16569		const aspect = 1;
16570		const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
16571		const upSign = [ 1, - 1, 1, 1, 1, 1 ];
16572		const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
16573		const renderer = this._renderer;
16574
16575		const originalAutoClear = renderer.autoClear;
16576		const toneMapping = renderer.toneMapping;
16577		renderer.getClearColor( _clearColor );
16578
16579		renderer.toneMapping = NoToneMapping;
16580		renderer.autoClear = false;
16581
16582		const backgroundMaterial = new MeshBasicMaterial( {
16583			name: 'PMREM.Background',
16584			side: BackSide,
16585			depthWrite: false,
16586			depthTest: false,
16587		} );
16588
16589		const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
16590
16591		let useSolidColor = false;
16592		const background = scene.background;
16593
16594		if ( background ) {
16595
16596			if ( background.isColor ) {
16597
16598				backgroundMaterial.color.copy( background );
16599				scene.background = null;
16600				useSolidColor = true;
16601
16602			}
16603
16604		} else {
16605
16606			backgroundMaterial.color.copy( _clearColor );
16607			useSolidColor = true;
16608
16609		}
16610
16611		for ( let i = 0; i < 6; i ++ ) {
16612
16613			const col = i % 3;
16614
16615			if ( col === 0 ) {
16616
16617				cubeCamera.up.set( 0, upSign[ i ], 0 );
16618				cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
16619
16620			} else if ( col === 1 ) {
16621
16622				cubeCamera.up.set( 0, 0, upSign[ i ] );
16623				cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
16624
16625			} else {
16626
16627				cubeCamera.up.set( 0, upSign[ i ], 0 );
16628				cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
16629
16630			}
16631
16632			const size = this._cubeSize;
16633
16634			_setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );
16635
16636			renderer.setRenderTarget( cubeUVRenderTarget );
16637
16638			if ( useSolidColor ) {
16639
16640				renderer.render( backgroundBox, cubeCamera );
16641
16642			}
16643
16644			renderer.render( scene, cubeCamera );
16645
16646		}
16647
16648		backgroundBox.geometry.dispose();
16649		backgroundBox.material.dispose();
16650
16651		renderer.toneMapping = toneMapping;
16652		renderer.autoClear = originalAutoClear;
16653		scene.background = background;
16654
16655	}
16656
16657	_textureToCubeUV( texture, cubeUVRenderTarget ) {
16658
16659		const renderer = this._renderer;
16660
16661		const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
16662
16663		if ( isCubeTexture ) {
16664
16665			if ( this._cubemapMaterial === null ) {
16666
16667				this._cubemapMaterial = _getCubemapMaterial();
16668
16669			}
16670
16671			this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
16672
16673		} else {
16674
16675			if ( this._equirectMaterial === null ) {
16676
16677				this._equirectMaterial = _getEquirectMaterial();
16678
16679			}
16680
16681		}
16682
16683		const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
16684		const mesh = new Mesh( this._lodPlanes[ 0 ], material );
16685
16686		const uniforms = material.uniforms;
16687
16688		uniforms[ 'envMap' ].value = texture;
16689
16690		const size = this._cubeSize;
16691
16692		_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
16693
16694		renderer.setRenderTarget( cubeUVRenderTarget );
16695		renderer.render( mesh, _flatCamera );
16696
16697	}
16698
16699	_applyPMREM( cubeUVRenderTarget ) {
16700
16701		const renderer = this._renderer;
16702		const autoClear = renderer.autoClear;
16703		renderer.autoClear = false;
16704
16705		for ( let i = 1; i < this._lodPlanes.length; i ++ ) {
16706
16707			const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );
16708
16709			const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
16710
16711			this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
16712
16713		}
16714
16715		renderer.autoClear = autoClear;
16716
16717	}
16718
16719	/**
16720	 * This is a two-pass Gaussian blur for a cubemap. Normally this is done
16721	 * vertically and horizontally, but this breaks down on a cube. Here we apply
16722	 * the blur latitudinally (around the poles), and then longitudinally (towards
16723	 * the poles) to approximate the orthogonally-separable blur. It is least
16724	 * accurate at the poles, but still does a decent job.
16725	 */
16726	_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
16727
16728		const pingPongRenderTarget = this._pingPongRenderTarget;
16729
16730		this._halfBlur(
16731			cubeUVRenderTarget,
16732			pingPongRenderTarget,
16733			lodIn,
16734			lodOut,
16735			sigma,
16736			'latitudinal',
16737			poleAxis );
16738
16739		this._halfBlur(
16740			pingPongRenderTarget,
16741			cubeUVRenderTarget,
16742			lodOut,
16743			lodOut,
16744			sigma,
16745			'longitudinal',
16746			poleAxis );
16747
16748	}
16749
16750	_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
16751
16752		const renderer = this._renderer;
16753		const blurMaterial = this._blurMaterial;
16754
16755		if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
16756
16757			console.error(
16758				'blur direction must be either latitudinal or longitudinal!' );
16759
16760		}
16761
16762		// Number of standard deviations at which to cut off the discrete approximation.
16763		const STANDARD_DEVIATIONS = 3;
16764
16765		const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
16766		const blurUniforms = blurMaterial.uniforms;
16767
16768		const pixels = this._sizeLods[ lodIn ] - 1;
16769		const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
16770		const sigmaPixels = sigmaRadians / radiansPerPixel;
16771		const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
16772
16773		if ( samples > MAX_SAMPLES ) {
16774
16775			console.warn( `sigmaRadians, ${
16776				sigmaRadians}, is too large and will clip, as it requested ${
16777				samples} samples when the maximum is set to ${MAX_SAMPLES}` );
16778
16779		}
16780
16781		const weights = [];
16782		let sum = 0;
16783
16784		for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
16785
16786			const x = i / sigmaPixels;
16787			const weight = Math.exp( - x * x / 2 );
16788			weights.push( weight );
16789
16790			if ( i === 0 ) {
16791
16792				sum += weight;
16793
16794			} else if ( i < samples ) {
16795
16796				sum += 2 * weight;
16797
16798			}
16799
16800		}
16801
16802		for ( let i = 0; i < weights.length; i ++ ) {
16803
16804			weights[ i ] = weights[ i ] / sum;
16805
16806		}
16807
16808		blurUniforms[ 'envMap' ].value = targetIn.texture;
16809		blurUniforms[ 'samples' ].value = samples;
16810		blurUniforms[ 'weights' ].value = weights;
16811		blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
16812
16813		if ( poleAxis ) {
16814
16815			blurUniforms[ 'poleAxis' ].value = poleAxis;
16816
16817		}
16818
16819		const { _lodMax } = this;
16820		blurUniforms[ 'dTheta' ].value = radiansPerPixel;
16821		blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;
16822
16823		const outputSize = this._sizeLods[ lodOut ];
16824		const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
16825		const y = 4 * ( this._cubeSize - outputSize );
16826
16827		_setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
16828		renderer.setRenderTarget( targetOut );
16829		renderer.render( blurMesh, _flatCamera );
16830
16831	}
16832
16833}
16834
16835
16836
16837function _createPlanes( lodMax ) {
16838
16839	const lodPlanes = [];
16840	const sizeLods = [];
16841	const sigmas = [];
16842
16843	let lod = lodMax;
16844
16845	const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
16846
16847	for ( let i = 0; i < totalLods; i ++ ) {
16848
16849		const sizeLod = Math.pow( 2, lod );
16850		sizeLods.push( sizeLod );
16851		let sigma = 1.0 / sizeLod;
16852
16853		if ( i > lodMax - LOD_MIN ) {
16854
16855			sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];
16856
16857		} else if ( i === 0 ) {
16858
16859			sigma = 0;
16860
16861		}
16862
16863		sigmas.push( sigma );
16864
16865		const texelSize = 1.0 / ( sizeLod - 2 );
16866		const min = - texelSize;
16867		const max = 1 + texelSize;
16868		const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
16869
16870		const cubeFaces = 6;
16871		const vertices = 6;
16872		const positionSize = 3;
16873		const uvSize = 2;
16874		const faceIndexSize = 1;
16875
16876		const position = new Float32Array( positionSize * vertices * cubeFaces );
16877		const uv = new Float32Array( uvSize * vertices * cubeFaces );
16878		const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
16879
16880		for ( let face = 0; face < cubeFaces; face ++ ) {
16881
16882			const x = ( face % 3 ) * 2 / 3 - 1;
16883			const y = face > 2 ? 0 : - 1;
16884			const coordinates = [
16885				x, y, 0,
16886				x + 2 / 3, y, 0,
16887				x + 2 / 3, y + 1, 0,
16888				x, y, 0,
16889				x + 2 / 3, y + 1, 0,
16890				x, y + 1, 0
16891			];
16892			position.set( coordinates, positionSize * vertices * face );
16893			uv.set( uv1, uvSize * vertices * face );
16894			const fill = [ face, face, face, face, face, face ];
16895			faceIndex.set( fill, faceIndexSize * vertices * face );
16896
16897		}
16898
16899		const planes = new BufferGeometry();
16900		planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
16901		planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
16902		planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
16903		lodPlanes.push( planes );
16904
16905		if ( lod > LOD_MIN ) {
16906
16907			lod --;
16908
16909		}
16910
16911	}
16912
16913	return { lodPlanes, sizeLods, sigmas };
16914
16915}
16916
16917function _createRenderTarget( width, height, params ) {
16918
16919	const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );
16920	cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
16921	cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
16922	cubeUVRenderTarget.scissorTest = true;
16923	return cubeUVRenderTarget;
16924
16925}
16926
16927function _setViewport( target, x, y, width, height ) {
16928
16929	target.viewport.set( x, y, width, height );
16930	target.scissor.set( x, y, width, height );
16931
16932}
16933
16934function _getBlurShader( lodMax, width, height ) {
16935
16936	const weights = new Float32Array( MAX_SAMPLES );
vendor: 3,252 bytes, lines 16937-17096
16937	const poleAxis = new Vector3( 0, 1, 0 );
16938	const shaderMaterial = new ShaderMaterial( {
16939
16940		name: 'SphericalGaussianBlur',
16941
16942		defines: {
16943			'n': MAX_SAMPLES,
16944			'CUBEUV_TEXEL_WIDTH': 1.0 / width,
16945			'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
16946			'CUBEUV_MAX_MIP': `${lodMax}.0`,
16947		},
16948
16949		uniforms: {
16950			'envMap': { value: null },
16951			'samples': { value: 1 },
16952			'weights': { value: weights },
16953			'latitudinal': { value: false },
16954			'dTheta': { value: 0 },
16955			'mipInt': { value: 0 },
16956			'poleAxis': { value: poleAxis }
16957		},
16958
16959		vertexShader: _getCommonVertexShader(),
16960
16961		fragmentShader: /* glsl */`
16962
16963			precision mediump float;
16964			precision mediump int;
16965
16966			varying vec3 vOutputDirection;
16967
16968			uniform sampler2D envMap;
16969			uniform int samples;
16970			uniform float weights[ n ];
16971			uniform bool latitudinal;
16972			uniform float dTheta;
16973			uniform float mipInt;
16974			uniform vec3 poleAxis;
16975
16976			#define ENVMAP_TYPE_CUBE_UV
16977			#include <cube_uv_reflection_fragment>
16978
16979			vec3 getSample( float theta, vec3 axis ) {
16980
16981				float cosTheta = cos( theta );
16982				// Rodrigues' axis-angle rotation
16983				vec3 sampleDirection = vOutputDirection * cosTheta
16984					+ cross( axis, vOutputDirection ) * sin( theta )
16985					+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
16986
16987				return bilinearCubeUV( envMap, sampleDirection, mipInt );
16988
16989			}
16990
16991			void main() {
16992
16993				vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
16994
16995				if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
16996
16997					axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
16998
16999				}
17000
17001				axis = normalize( axis );
17002
17003				gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
17004				gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
17005
17006				for ( int i = 1; i < n; i++ ) {
17007
17008					if ( i >= samples ) {
17009
17010						break;
17011
17012					}
17013
17014					float theta = dTheta * float( i );
17015					gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
17016					gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
17017
17018				}
17019
17020			}
17021		`,
17022
17023		blending: NoBlending,
17024		depthTest: false,
17025		depthWrite: false
17026
17027	} );
17028
17029	return shaderMaterial;
17030
17031}
17032
17033function _getEquirectMaterial() {
17034
17035	return new ShaderMaterial( {
17036
17037		name: 'EquirectangularToCubeUV',
17038
17039		uniforms: {
17040			'envMap': { value: null }
17041		},
17042
17043		vertexShader: _getCommonVertexShader(),
17044
17045		fragmentShader: /* glsl */`
17046
17047			precision mediump float;
17048			precision mediump int;
17049
17050			varying vec3 vOutputDirection;
17051
17052			uniform sampler2D envMap;
17053
17054			#include <common>
17055
17056			void main() {
17057
17058				vec3 outputDirection = normalize( vOutputDirection );
17059				vec2 uv = equirectUv( outputDirection );
17060
17061				gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );
17062
17063			}
17064		`,
17065
17066		blending: NoBlending,
17067		depthTest: false,
17068		depthWrite: false
17069
17070	} );
17071
17072}
17073
17074function _getCubemapMaterial() {
17075
17076	return new ShaderMaterial( {
17077
17078		name: 'CubemapToCubeUV',
17079
17080		uniforms: {
17081			'envMap': { value: null },
17082			'flipEnvMap': { value: - 1 }
17083		},
17084
17085		vertexShader: _getCommonVertexShader(),
17086
17087		fragmentShader: /* glsl */`
17088
17089			precision mediump float;
17090			precision mediump int;
17091
17092			uniform float flipEnvMap;
17093
17094			varying vec3 vOutputDirection;
17095
17096			uniform samplerCube envMap;
17097
17098			void main() {
17099
17100				gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );
17101
17102			}
17103		`,
17104
17105		blending: NoBlending,
17106		depthTest: false,
17107		depthWrite: false
17108
17109	} );
17110
17111}
17112
17113function _getCommonVertexShader() {
17114
17115	return /* glsl */`
17116
17117		precision mediump float;
17118		precision mediump int;
17119
17120		attribute float faceIndex;
17121
17122		varying vec3 vOutputDirection;
17123
17124		// RH coordinate system; PMREM face-indexing convention
17125		vec3 getDirection( vec2 uv, float face ) {
17126
17127			uv = 2.0 * uv - 1.0;
17128
17129			vec3 direction = vec3( uv, 1.0 );
17130
17131			if ( face == 0.0 ) {
17132
17133				direction = direction.zyx; // ( 1, v, u ) pos x
17134
17135			} else if ( face == 1.0 ) {
17136
17137				direction = direction.xzy;
17138				direction.xz *= -1.0; // ( -u, 1, -v ) pos y
17139
17140			} else if ( face == 2.0 ) {
17141
17142				direction.x *= -1.0; // ( -u, v, 1 ) pos z
17143
17144			} else if ( face == 3.0 ) {
17145
17146				direction = direction.zyx;
17147				direction.xz *= -1.0; // ( -1, v, -u ) neg x
17148
17149			} else if ( face == 4.0 ) {
17150
17151				direction = direction.xzy;
17152				direction.xy *= -1.0; // ( -u, -1, v ) neg y
17153
17154			} else if ( face == 5.0 ) {
17155
17156				direction.z *= -1.0; // ( u, v, -1 ) neg z
17157
17158			}
17159
17160			return direction;
17161
17162		}
17163
17164		void main() {
17165
17166			vOutputDirection = getDirection( uv, faceIndex );
17167			gl_Position = vec4( position, 1.0 );
17168
17169		}
17170	`;
17171
17172}
17173
17174function WebGLCubeUVMaps( renderer ) {
17175
17176	let cubeUVmaps = new WeakMap();
17177
17178	let pmremGenerator = null;
17179
17180	function get( texture ) {
17181
17182		if ( texture && texture.isTexture ) {
17183
17184			const mapping = texture.mapping;
17185
17186			const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );
17187			const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
17188
17189			// equirect/cube map to cubeUV conversion
17190
17191			if ( isEquirectMap || isCubeMap ) {
17192
17193				if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) {
17194
17195					texture.needsPMREMUpdate = false;
17196
17197					let renderTarget = cubeUVmaps.get( texture );
17198
17199					if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17200
17201					renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );
17202					cubeUVmaps.set( texture, renderTarget );
17203
17204					return renderTarget.texture;
17205
17206				} else {
17207
17208					if ( cubeUVmaps.has( texture ) ) {
17209
17210						return cubeUVmaps.get( texture ).texture;
17211
17212					} else {
17213
17214						const image = texture.image;
17215
17216						if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {
17217
17218							if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17219
17220							const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
17221							cubeUVmaps.set( texture, renderTarget );
17222
17223							texture.addEventListener( 'dispose', onTextureDispose );
17224
17225							return renderTarget.texture;
17226
17227						} else {
17228
17229							// image not yet ready. try the conversion next frame
17230
17231							return null;
17232
17233						}
17234
17235					}
17236
17237				}
17238
17239			}
17240
17241		}
17242
17243		return texture;
17244
17245	}
17246
17247	function isCubeTextureComplete( image ) {
17248
17249		let count = 0;
17250		const length = 6;
17251
17252		for ( let i = 0; i < length; i ++ ) {
17253
17254			if ( image[ i ] !== undefined ) count ++;
17255
17256		}
17257
17258		return count === length;
17259
17260
17261	}
17262
17263	function onTextureDispose( event ) {
17264
17265		const texture = event.target;
17266
17267		texture.removeEventListener( 'dispose', onTextureDispose );
17268
17269		const cubemapUV = cubeUVmaps.get( texture );
17270
17271		if ( cubemapUV !== undefined ) {
17272
17273			cubeUVmaps.delete( texture );
17274			cubemapUV.dispose();
17275
17276		}
17277
17278	}
17279
17280	function dispose() {
17281
17282		cubeUVmaps = new WeakMap();
17283
17284		if ( pmremGenerator !== null ) {
17285
17286			pmremGenerator.dispose();
17287			pmremGenerator = null;
17288
17289		}
17290
17291	}
17292
17293	return {
17294		get: get,
17295		dispose: dispose
17296	};
17297
17298}
17299
17300function WebGLExtensions( gl ) {
17301
17302	const extensions = {};
17303
17304	function getExtension( name ) {
17305
17306		if ( extensions[ name ] !== undefined ) {
17307
17308			return extensions[ name ];
17309
17310		}
17311
17312		let extension;
17313
17314		switch ( name ) {
17315
17316			case 'WEBGL_depth_texture':
17317				extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
17318				break;
17319
17320			case 'EXT_texture_filter_anisotropic':
17321				extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
17322				break;
17323
17324			case 'WEBGL_compressed_texture_s3tc':
17325				extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
17326				break;
17327
17328			case 'WEBGL_compressed_texture_pvrtc':
17329				extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
17330				break;
17331
17332			default:
17333				extension = gl.getExtension( name );
17334
17335		}
17336
17337		extensions[ name ] = extension;
17338
17339		return extension;
17340
17341	}
17342
17343	return {
17344
17345		has: function ( name ) {
17346
17347			return getExtension( name ) !== null;
17348
17349		},
17350
17351		init: function ( capabilities ) {
17352
17353			if ( capabilities.isWebGL2 ) {
17354
17355				getExtension( 'EXT_color_buffer_float' );
17356				getExtension( 'WEBGL_clip_cull_distance' );
17357
17358			} else {
17359
17360				getExtension( 'WEBGL_depth_texture' );
17361				getExtension( 'OES_texture_float' );
17362				getExtension( 'OES_texture_half_float' );
17363				getExtension( 'OES_texture_half_float_linear' );
17364				getExtension( 'OES_standard_derivatives' );
17365				getExtension( 'OES_element_index_uint' );
17366				getExtension( 'OES_vertex_array_object' );
vendor: 27,956 bytes, lines 17367-18772
17367				getExtension( 'ANGLE_instanced_arrays' );
17368
17369			}
17370
17371			getExtension( 'OES_texture_float_linear' );
17372			getExtension( 'EXT_color_buffer_half_float' );
17373			getExtension( 'WEBGL_multisampled_render_to_texture' );
17374
17375		},
17376
17377		get: function ( name ) {
17378
17379			const extension = getExtension( name );
17380
17381			if ( extension === null ) {
17382
17383				console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
17384
17385			}
17386
17387			return extension;
17388
17389		}
17390
17391	};
17392
17393}
17394
17395function WebGLGeometries( gl, attributes, info, bindingStates ) {
17396
17397	const geometries = {};
17398	const wireframeAttributes = new WeakMap();
17399
17400	function onGeometryDispose( event ) {
17401
17402		const geometry = event.target;
17403
17404		if ( geometry.index !== null ) {
17405
17406			attributes.remove( geometry.index );
17407
17408		}
17409
17410		for ( const name in geometry.attributes ) {
17411
17412			attributes.remove( geometry.attributes[ name ] );
17413
17414		}
17415
17416		for ( const name in geometry.morphAttributes ) {
17417
17418			const array = geometry.morphAttributes[ name ];
17419
17420			for ( let i = 0, l = array.length; i < l; i ++ ) {
17421
17422				attributes.remove( array[ i ] );
17423
17424			}
17425
17426		}
17427
17428		geometry.removeEventListener( 'dispose', onGeometryDispose );
17429
17430		delete geometries[ geometry.id ];
17431
17432		const attribute = wireframeAttributes.get( geometry );
17433
17434		if ( attribute ) {
17435
17436			attributes.remove( attribute );
17437			wireframeAttributes.delete( geometry );
17438
17439		}
17440
17441		bindingStates.releaseStatesOfGeometry( geometry );
17442
17443		if ( geometry.isInstancedBufferGeometry === true ) {
17444
17445			delete geometry._maxInstanceCount;
17446
17447		}
17448
17449		//
17450
17451		info.memory.geometries --;
17452
17453	}
17454
17455	function get( object, geometry ) {
17456
17457		if ( geometries[ geometry.id ] === true ) return geometry;
17458
17459		geometry.addEventListener( 'dispose', onGeometryDispose );
17460
17461		geometries[ geometry.id ] = true;
17462
17463		info.memory.geometries ++;
17464
17465		return geometry;
17466
17467	}
17468
17469	function update( geometry ) {
17470
17471		const geometryAttributes = geometry.attributes;
17472
17473		// Updating index buffer in VAO now. See WebGLBindingStates.
17474
17475		for ( const name in geometryAttributes ) {
17476
17477			attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
17478
17479		}
17480
17481		// morph targets
17482
17483		const morphAttributes = geometry.morphAttributes;
17484
17485		for ( const name in morphAttributes ) {
17486
17487			const array = morphAttributes[ name ];
17488
17489			for ( let i = 0, l = array.length; i < l; i ++ ) {
17490
17491				attributes.update( array[ i ], gl.ARRAY_BUFFER );
17492
17493			}
17494
17495		}
17496
17497	}
17498
17499	function updateWireframeAttribute( geometry ) {
17500
17501		const indices = [];
17502
17503		const geometryIndex = geometry.index;
17504		const geometryPosition = geometry.attributes.position;
17505		let version = 0;
17506
17507		if ( geometryIndex !== null ) {
17508
17509			const array = geometryIndex.array;
17510			version = geometryIndex.version;
17511
17512			for ( let i = 0, l = array.length; i < l; i += 3 ) {
17513
17514				const a = array[ i + 0 ];
17515				const b = array[ i + 1 ];
17516				const c = array[ i + 2 ];
17517
17518				indices.push( a, b, b, c, c, a );
17519
17520			}
17521
17522		} else if ( geometryPosition !== undefined ) {
17523
17524			const array = geometryPosition.array;
17525			version = geometryPosition.version;
17526
17527			for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
17528
17529				const a = i + 0;
17530				const b = i + 1;
17531				const c = i + 2;
17532
17533				indices.push( a, b, b, c, c, a );
17534
17535			}
17536
17537		} else {
17538
17539			return;
17540
17541		}
17542
17543		const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
17544		attribute.version = version;
17545
17546		// Updating index buffer in VAO now. See WebGLBindingStates
17547
17548		//
17549
17550		const previousAttribute = wireframeAttributes.get( geometry );
17551
17552		if ( previousAttribute ) attributes.remove( previousAttribute );
17553
17554		//
17555
17556		wireframeAttributes.set( geometry, attribute );
17557
17558	}
17559
17560	function getWireframeAttribute( geometry ) {
17561
17562		const currentAttribute = wireframeAttributes.get( geometry );
17563
17564		if ( currentAttribute ) {
17565
17566			const geometryIndex = geometry.index;
17567
17568			if ( geometryIndex !== null ) {
17569
17570				// if the attribute is obsolete, create a new one
17571
17572				if ( currentAttribute.version < geometryIndex.version ) {
17573
17574					updateWireframeAttribute( geometry );
17575
17576				}
17577
17578			}
17579
17580		} else {
17581
17582			updateWireframeAttribute( geometry );
17583
17584		}
17585
17586		return wireframeAttributes.get( geometry );
17587
17588	}
17589
17590	return {
17591
17592		get: get,
17593		update: update,
17594
17595		getWireframeAttribute: getWireframeAttribute
17596
17597	};
17598
17599}
17600
17601function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
17602
17603	const isWebGL2 = capabilities.isWebGL2;
17604
17605	let mode;
17606
17607	function setMode( value ) {
17608
17609		mode = value;
17610
17611	}
17612
17613	let type, bytesPerElement;
17614
17615	function setIndex( value ) {
17616
17617		type = value.type;
17618		bytesPerElement = value.bytesPerElement;
17619
17620	}
17621
17622	function render( start, count ) {
17623
17624		gl.drawElements( mode, count, type, start * bytesPerElement );
17625
17626		info.update( count, mode, 1 );
17627
17628	}
17629
17630	function renderInstances( start, count, primcount ) {
17631
17632		if ( primcount === 0 ) return;
17633
17634		let extension, methodName;
17635
17636		if ( isWebGL2 ) {
17637
17638			extension = gl;
17639			methodName = 'drawElementsInstanced';
17640
17641		} else {
17642
17643			extension = extensions.get( 'ANGLE_instanced_arrays' );
17644			methodName = 'drawElementsInstancedANGLE';
17645
17646			if ( extension === null ) {
17647
17648				console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
17649				return;
17650
17651			}
17652
17653		}
17654
17655		extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
17656
17657		info.update( count, mode, primcount );
17658
17659	}
17660
17661	function renderMultiDraw( starts, counts, drawCount ) {
17662
17663		if ( drawCount === 0 ) return;
17664
17665		const extension = extensions.get( 'WEBGL_multi_draw' );
17666		if ( extension === null ) {
17667
17668			for ( let i = 0; i < drawCount; i ++ ) {
17669
17670				this.render( starts[ i ] / bytesPerElement, counts[ i ] );
17671
17672			}
17673
17674		} else {
17675
17676			extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );
17677
17678			let elementCount = 0;
17679			for ( let i = 0; i < drawCount; i ++ ) {
17680
17681				elementCount += counts[ i ];
17682
17683			}
17684
17685			info.update( elementCount, mode, 1 );
17686
17687		}
17688
17689	}
17690
17691	//
17692
17693	this.setMode = setMode;
17694	this.setIndex = setIndex;
17695	this.render = render;
17696	this.renderInstances = renderInstances;
17697	this.renderMultiDraw = renderMultiDraw;
17698
17699}
17700
17701function WebGLInfo( gl ) {
17702
17703	const memory = {
17704		geometries: 0,
17705		textures: 0
17706	};
17707
17708	const render = {
17709		frame: 0,
17710		calls: 0,
17711		triangles: 0,
17712		points: 0,
17713		lines: 0
17714	};
17715
17716	function update( count, mode, instanceCount ) {
17717
17718		render.calls ++;
17719
17720		switch ( mode ) {
17721
17722			case gl.TRIANGLES:
17723				render.triangles += instanceCount * ( count / 3 );
17724				break;
17725
17726			case gl.LINES:
17727				render.lines += instanceCount * ( count / 2 );
17728				break;
17729
17730			case gl.LINE_STRIP:
17731				render.lines += instanceCount * ( count - 1 );
17732				break;
17733
17734			case gl.LINE_LOOP:
17735				render.lines += instanceCount * count;
17736				break;
17737
17738			case gl.POINTS:
17739				render.points += instanceCount * count;
17740				break;
17741
17742			default:
17743				console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
17744				break;
17745
17746		}
17747
17748	}
17749
17750	function reset() {
17751
17752		render.calls = 0;
17753		render.triangles = 0;
17754		render.points = 0;
17755		render.lines = 0;
17756
17757	}
17758
17759	return {
17760		memory: memory,
17761		render: render,
17762		programs: null,
17763		autoReset: true,
17764		reset: reset,
17765		update: update
17766	};
17767
17768}
17769
17770function numericalSort( a, b ) {
17771
17772	return a[ 0 ] - b[ 0 ];
17773
17774}
17775
17776function absNumericalSort( a, b ) {
17777
17778	return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
17779
17780}
17781
17782function WebGLMorphtargets( gl, capabilities, textures ) {
17783
17784	const influencesList = {};
17785	const morphInfluences = new Float32Array( 8 );
17786	const morphTextures = new WeakMap();
17787	const morph = new Vector4();
17788
17789	const workInfluences = [];
17790
17791	for ( let i = 0; i < 8; i ++ ) {
17792
17793		workInfluences[ i ] = [ i, 0 ];
17794
17795	}
17796
17797	function update( object, geometry, program ) {
17798
17799		const objectInfluences = object.morphTargetInfluences;
17800
17801		if ( capabilities.isWebGL2 === true ) {
17802
17803			// instead of using attributes, the WebGL 2 code path encodes morph targets
17804			// into an array of data textures. Each layer represents a single morph target.
17805
17806			const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
17807			const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
17808
17809			let entry = morphTextures.get( geometry );
17810
17811			if ( entry === undefined || entry.count !== morphTargetsCount ) {
17812
17813				if ( entry !== undefined ) entry.texture.dispose();
17814
17815				const hasMorphPosition = geometry.morphAttributes.position !== undefined;
17816				const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
17817				const hasMorphColors = geometry.morphAttributes.color !== undefined;
17818
17819				const morphTargets = geometry.morphAttributes.position || [];
17820				const morphNormals = geometry.morphAttributes.normal || [];
17821				const morphColors = geometry.morphAttributes.color || [];
17822
17823				let vertexDataCount = 0;
17824
17825				if ( hasMorphPosition === true ) vertexDataCount = 1;
17826				if ( hasMorphNormals === true ) vertexDataCount = 2;
17827				if ( hasMorphColors === true ) vertexDataCount = 3;
17828
17829				let width = geometry.attributes.position.count * vertexDataCount;
17830				let height = 1;
17831
17832				if ( width > capabilities.maxTextureSize ) {
17833
17834					height = Math.ceil( width / capabilities.maxTextureSize );
17835					width = capabilities.maxTextureSize;
17836
17837				}
17838
17839				const buffer = new Float32Array( width * height * 4 * morphTargetsCount );
17840
17841				const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
17842				texture.type = FloatType;
17843				texture.needsUpdate = true;
17844
17845				// fill buffer
17846
17847				const vertexDataStride = vertexDataCount * 4;
17848
17849				for ( let i = 0; i < morphTargetsCount; i ++ ) {
17850
17851					const morphTarget = morphTargets[ i ];
17852					const morphNormal = morphNormals[ i ];
17853					const morphColor = morphColors[ i ];
17854
17855					const offset = width * height * 4 * i;
17856
17857					for ( let j = 0; j < morphTarget.count; j ++ ) {
17858
17859						const stride = j * vertexDataStride;
17860
17861						if ( hasMorphPosition === true ) {
17862
17863							morph.fromBufferAttribute( morphTarget, j );
17864
17865							buffer[ offset + stride + 0 ] = morph.x;
17866							buffer[ offset + stride + 1 ] = morph.y;
17867							buffer[ offset + stride + 2 ] = morph.z;
17868							buffer[ offset + stride + 3 ] = 0;
17869
17870						}
17871
17872						if ( hasMorphNormals === true ) {
17873
17874							morph.fromBufferAttribute( morphNormal, j );
17875
17876							buffer[ offset + stride + 4 ] = morph.x;
17877							buffer[ offset + stride + 5 ] = morph.y;
17878							buffer[ offset + stride + 6 ] = morph.z;
17879							buffer[ offset + stride + 7 ] = 0;
17880
17881						}
17882
17883						if ( hasMorphColors === true ) {
17884
17885							morph.fromBufferAttribute( morphColor, j );
17886
17887							buffer[ offset + stride + 8 ] = morph.x;
17888							buffer[ offset + stride + 9 ] = morph.y;
17889							buffer[ offset + stride + 10 ] = morph.z;
17890							buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;
17891
17892						}
17893
17894					}
17895
17896				}
17897
17898				entry = {
17899					count: morphTargetsCount,
17900					texture: texture,
17901					size: new Vector2( width, height )
17902				};
17903
17904				morphTextures.set( geometry, entry );
17905
17906				function disposeTexture() {
17907
17908					texture.dispose();
17909
17910					morphTextures.delete( geometry );
17911
17912					geometry.removeEventListener( 'dispose', disposeTexture );
17913
17914				}
17915
17916				geometry.addEventListener( 'dispose', disposeTexture );
17917
17918			}
17919
17920			//
17921
17922			let morphInfluencesSum = 0;
17923
17924			for ( let i = 0; i < objectInfluences.length; i ++ ) {
17925
17926				morphInfluencesSum += objectInfluences[ i ];
17927
17928			}
17929
17930			const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
17931
17932			program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
17933			program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );
17934
17935			program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
17936			program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );
17937
17938
17939		} else {
17940
17941			// When object doesn't have morph target influences defined, we treat it as a 0-length array
17942			// This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
17943
17944			const length = objectInfluences === undefined ? 0 : objectInfluences.length;
17945
17946			let influences = influencesList[ geometry.id ];
17947
17948			if ( influences === undefined || influences.length !== length ) {
17949
17950				// initialise list
17951
17952				influences = [];
17953
17954				for ( let i = 0; i < length; i ++ ) {
17955
17956					influences[ i ] = [ i, 0 ];
17957
17958				}
17959
17960				influencesList[ geometry.id ] = influences;
17961
17962			}
17963
17964			// Collect influences
17965
17966			for ( let i = 0; i < length; i ++ ) {
17967
17968				const influence = influences[ i ];
17969
17970				influence[ 0 ] = i;
17971				influence[ 1 ] = objectInfluences[ i ];
17972
17973			}
17974
17975			influences.sort( absNumericalSort );
17976
17977			for ( let i = 0; i < 8; i ++ ) {
17978
17979				if ( i < length && influences[ i ][ 1 ] ) {
17980
17981					workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
17982					workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
17983
17984				} else {
17985
17986					workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
17987					workInfluences[ i ][ 1 ] = 0;
17988
17989				}
17990
17991			}
17992
17993			workInfluences.sort( numericalSort );
17994
17995			const morphTargets = geometry.morphAttributes.position;
17996			const morphNormals = geometry.morphAttributes.normal;
17997
17998			let morphInfluencesSum = 0;
17999
18000			for ( let i = 0; i < 8; i ++ ) {
18001
18002				const influence = workInfluences[ i ];
18003				const index = influence[ 0 ];
18004				const value = influence[ 1 ];
18005
18006				if ( index !== Number.MAX_SAFE_INTEGER && value ) {
18007
18008					if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
18009
18010						geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
18011
18012					}
18013
18014					if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
18015
18016						geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
18017
18018					}
18019
18020					morphInfluences[ i ] = value;
18021					morphInfluencesSum += value;
18022
18023				} else {
18024
18025					if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
18026
18027						geometry.deleteAttribute( 'morphTarget' + i );
18028
18029					}
18030
18031					if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
18032
18033						geometry.deleteAttribute( 'morphNormal' + i );
18034
18035					}
18036
18037					morphInfluences[ i ] = 0;
18038
18039				}
18040
18041			}
18042
18043			// GLSL shader uses formula baseinfluence * base + sum(target * influence)
18044			// This allows us to switch between absolute morphs and relative morphs without changing shader code
18045			// When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
18046			const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
18047
18048			program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
18049			program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
18050
18051		}
18052
18053	}
18054
18055	return {
18056
18057		update: update
18058
18059	};
18060
18061}
18062
18063function WebGLObjects( gl, geometries, attributes, info ) {
18064
18065	let updateMap = new WeakMap();
18066
18067	function update( object ) {
18068
18069		const frame = info.render.frame;
18070
18071		const geometry = object.geometry;
18072		const buffergeometry = geometries.get( object, geometry );
18073
18074		// Update once per frame
18075
18076		if ( updateMap.get( buffergeometry ) !== frame ) {
18077
18078			geometries.update( buffergeometry );
18079
18080			updateMap.set( buffergeometry, frame );
18081
18082		}
18083
18084		if ( object.isInstancedMesh ) {
18085
18086			if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
18087
18088				object.addEventListener( 'dispose', onInstancedMeshDispose );
18089
18090			}
18091
18092			if ( updateMap.get( object ) !== frame ) {
18093
18094				attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );
18095
18096				if ( object.instanceColor !== null ) {
18097
18098					attributes.update( object.instanceColor, gl.ARRAY_BUFFER );
18099
18100				}
18101
18102				updateMap.set( object, frame );
18103
18104			}
18105
18106		}
18107
18108		if ( object.isSkinnedMesh ) {
18109
18110			const skeleton = object.skeleton;
18111
18112			if ( updateMap.get( skeleton ) !== frame ) {
18113
18114				skeleton.update();
18115
18116				updateMap.set( skeleton, frame );
18117
18118			}
18119
18120		}
18121
18122		return buffergeometry;
18123
18124	}
18125
18126	function dispose() {
18127
18128		updateMap = new WeakMap();
18129
18130	}
18131
18132	function onInstancedMeshDispose( event ) {
18133
18134		const instancedMesh = event.target;
18135
18136		instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
18137
18138		attributes.remove( instancedMesh.instanceMatrix );
18139
18140		if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
18141
18142	}
18143
18144	return {
18145
18146		update: update,
18147		dispose: dispose
18148
18149	};
18150
18151}
18152
18153class DepthTexture extends Texture {
18154
18155	constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
18156
18157		format = format !== undefined ? format : DepthFormat;
18158
18159		if ( format !== DepthFormat && format !== DepthStencilFormat ) {
18160
18161			throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
18162
18163		}
18164
18165		if ( type === undefined && format === DepthFormat ) type = UnsignedIntType;
18166		if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
18167
18168		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
18169
18170		this.isDepthTexture = true;
18171
18172		this.image = { width: width, height: height };
18173
18174		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
18175		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
18176
18177		this.flipY = false;
18178		this.generateMipmaps = false;
18179
18180		this.compareFunction = null;
18181
18182	}
18183
18184
18185	copy( source ) {
18186
18187		super.copy( source );
18188
18189		this.compareFunction = source.compareFunction;
18190
18191		return this;
18192
18193	}
18194
18195	toJSON( meta ) {
18196
18197		const data = super.toJSON( meta );
18198
18199		if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction;
18200
18201		return data;
18202
18203	}
18204
18205}
18206
18207/**
18208 * Uniforms of a program.
18209 * Those form a tree structure with a special top-level container for the root,
18210 * which you get by calling 'new WebGLUniforms( gl, program )'.
18211 *
18212 *
18213 * Properties of inner nodes including the top-level container:
18214 *
18215 * .seq - array of nested uniforms
18216 * .map - nested uniforms by name
18217 *
18218 *
18219 * Methods of all nodes except the top-level container:
18220 *
18221 * .setValue( gl, value, [textures] )
18222 *
18223 * 		uploads a uniform value(s)
18224 *  	the 'textures' parameter is needed for sampler uniforms
18225 *
18226 *
18227 * Static methods of the top-level container (textures factorizations):
18228 *
18229 * .upload( gl, seq, values, textures )
18230 *
18231 * 		sets uniforms in 'seq' to 'values[id].value'
18232 *
18233 * .seqWithValue( seq, values ) : filteredSeq
18234 *
18235 * 		filters 'seq' entries with corresponding entry in values
18236 *
18237 *
18238 * Methods of the top-level container (textures factorizations):
18239 *
18240 * .setValue( gl, name, value, textures )
18241 *
18242 * 		sets uniform with  name 'name' to 'value'
18243 *
18244 * .setOptional( gl, obj, prop )
18245 *
18246 * 		like .set for an optional property of the object
18247 *
18248 */
18249
18250
18251const emptyTexture = /*@__PURE__*/ new Texture();
18252
18253const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );
18254emptyShadowTexture.compareFunction = LessEqualCompare;
18255
18256const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
18257const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
18258const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
18259
18260// --- Utilities ---
18261
18262// Array Caches (provide typed arrays for temporary by size)
18263
18264const arrayCacheF32 = [];
18265const arrayCacheI32 = [];
18266
18267// Float32Array caches used for uploading Matrix uniforms
18268
18269const mat4array = new Float32Array( 16 );
18270const mat3array = new Float32Array( 9 );
18271const mat2array = new Float32Array( 4 );
18272
18273// Flattening for arrays of vectors and matrices
18274
18275function flatten( array, nBlocks, blockSize ) {
18276
18277	const firstElem = array[ 0 ];
18278
18279	if ( firstElem <= 0 || firstElem > 0 ) return array;
18280	// unoptimized: ! isNaN( firstElem )
18281	// see http://jacksondunstan.com/articles/983
18282
18283	const n = nBlocks * blockSize;
18284	let r = arrayCacheF32[ n ];
18285
18286	if ( r === undefined ) {
18287
18288		r = new Float32Array( n );
18289		arrayCacheF32[ n ] = r;
18290
18291	}
18292
18293	if ( nBlocks !== 0 ) {
18294
18295		firstElem.toArray( r, 0 );
18296
18297		for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
18298
18299			offset += blockSize;
18300			array[ i ].toArray( r, offset );
18301
18302		}
18303
18304	}
18305
18306	return r;
18307
18308}
18309
18310function arraysEqual( a, b ) {
18311
18312	if ( a.length !== b.length ) return false;
18313
18314	for ( let i = 0, l = a.length; i < l; i ++ ) {
18315
18316		if ( a[ i ] !== b[ i ] ) return false;
18317
18318	}
18319
18320	return true;
18321
18322}
18323
18324function copyArray( a, b ) {
18325
18326	for ( let i = 0, l = b.length; i < l; i ++ ) {
18327
18328		a[ i ] = b[ i ];
18329
18330	}
18331
18332}
18333
18334// Texture unit allocation
18335
18336function allocTexUnits( textures, n ) {
18337
18338	let r = arrayCacheI32[ n ];
18339
18340	if ( r === undefined ) {
18341
18342		r = new Int32Array( n );
18343		arrayCacheI32[ n ] = r;
18344
18345	}
18346
18347	for ( let i = 0; i !== n; ++ i ) {
18348
18349		r[ i ] = textures.allocateTextureUnit();
18350
18351	}
18352
18353	return r;
18354
18355}
18356
18357// --- Setters ---
18358
18359// Note: Defining these methods externally, because they come in a bunch
18360// and this way their names minify.
18361
18362// Single scalar
18363
18364function setValueV1f( gl, v ) {
18365
18366	const cache = this.cache;
18367
18368	if ( cache[ 0 ] === v ) return;
18369
18370	gl.uniform1f( this.addr, v );
18371
18372	cache[ 0 ] = v;
18373
18374}
18375
18376// Single float vector (from flat array or THREE.VectorN)
18377
18378function setValueV2f( gl, v ) {
18379
18380	const cache = this.cache;
18381
18382	if ( v.x !== undefined ) {
18383
18384		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18385
18386			gl.uniform2f( this.addr, v.x, v.y );
18387
18388			cache[ 0 ] = v.x;
18389			cache[ 1 ] = v.y;
18390
18391		}
18392
18393	} else {
18394
18395		if ( arraysEqual( cache, v ) ) return;
18396
18397		gl.uniform2fv( this.addr, v );
18398
18399		copyArray( cache, v );
18400
18401	}
18402
18403}
18404
18405function setValueV3f( gl, v ) {
18406
18407	const cache = this.cache;
18408
18409	if ( v.x !== undefined ) {
18410
18411		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18412
18413			gl.uniform3f( this.addr, v.x, v.y, v.z );
18414
18415			cache[ 0 ] = v.x;
18416			cache[ 1 ] = v.y;
18417			cache[ 2 ] = v.z;
18418
18419		}
18420
18421	} else if ( v.r !== undefined ) {
18422
18423		if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
18424
18425			gl.uniform3f( this.addr, v.r, v.g, v.b );
18426
18427			cache[ 0 ] = v.r;
18428			cache[ 1 ] = v.g;
18429			cache[ 2 ] = v.b;
18430
18431		}
18432
18433	} else {
18434
18435		if ( arraysEqual( cache, v ) ) return;
18436
18437		gl.uniform3fv( this.addr, v );
18438
18439		copyArray( cache, v );
18440
18441	}
18442
18443}
18444
18445function setValueV4f( gl, v ) {
18446
18447	const cache = this.cache;
18448
18449	if ( v.x !== undefined ) {
18450
18451		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18452
18453			gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
18454
18455			cache[ 0 ] = v.x;
18456			cache[ 1 ] = v.y;
18457			cache[ 2 ] = v.z;
18458			cache[ 3 ] = v.w;
18459
18460		}
18461
18462	} else {
18463
18464		if ( arraysEqual( cache, v ) ) return;
18465
18466		gl.uniform4fv( this.addr, v );
18467
18468		copyArray( cache, v );
18469
18470	}
18471
18472}
18473
18474// Single matrix (from flat array or THREE.MatrixN)
18475
18476function setValueM2( gl, v ) {
18477
18478	const cache = this.cache;
18479	const elements = v.elements;
18480
18481	if ( elements === undefined ) {
18482
18483		if ( arraysEqual( cache, v ) ) return;
18484
18485		gl.uniformMatrix2fv( this.addr, false, v );
18486
18487		copyArray( cache, v );
18488
18489	} else {
18490
18491		if ( arraysEqual( cache, elements ) ) return;
18492
18493		mat2array.set( elements );
18494
18495		gl.uniformMatrix2fv( this.addr, false, mat2array );
18496
18497		copyArray( cache, elements );
18498
18499	}
18500
18501}
18502
18503function setValueM3( gl, v ) {
18504
18505	const cache = this.cache;
18506	const elements = v.elements;
18507
18508	if ( elements === undefined ) {
18509
18510		if ( arraysEqual( cache, v ) ) return;
18511
18512		gl.uniformMatrix3fv( this.addr, false, v );
18513
18514		copyArray( cache, v );
18515
18516	} else {
18517
18518		if ( arraysEqual( cache, elements ) ) return;
18519
18520		mat3array.set( elements );
18521
18522		gl.uniformMatrix3fv( this.addr, false, mat3array );
18523
18524		copyArray( cache, elements );
18525
18526	}
18527
18528}
18529
18530function setValueM4( gl, v ) {
18531
18532	const cache = this.cache;
18533	const elements = v.elements;
18534
18535	if ( elements === undefined ) {
18536
18537		if ( arraysEqual( cache, v ) ) return;
18538
18539		gl.uniformMatrix4fv( this.addr, false, v );
18540
18541		copyArray( cache, v );
18542
18543	} else {
18544
18545		if ( arraysEqual( cache, elements ) ) return;
18546
18547		mat4array.set( elements );
18548
18549		gl.uniformMatrix4fv( this.addr, false, mat4array );
18550
18551		copyArray( cache, elements );
18552
18553	}
18554
18555}
18556
18557// Single integer / boolean
18558
18559function setValueV1i( gl, v ) {
18560
18561	const cache = this.cache;
18562
18563	if ( cache[ 0 ] === v ) return;
18564
18565	gl.uniform1i( this.addr, v );
18566
18567	cache[ 0 ] = v;
18568
18569}
18570
18571// Single integer / boolean vector (from flat array or THREE.VectorN)
18572
18573function setValueV2i( gl, v ) {
18574
18575	const cache = this.cache;
18576
18577	if ( v.x !== undefined ) {
18578
18579		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18580
18581			gl.uniform2i( this.addr, v.x, v.y );
18582
18583			cache[ 0 ] = v.x;
18584			cache[ 1 ] = v.y;
18585
18586		}
18587
18588	} else {
18589
18590		if ( arraysEqual( cache, v ) ) return;
18591
18592		gl.uniform2iv( this.addr, v );
18593
18594		copyArray( cache, v );
18595
18596	}
18597
18598}
18599
18600function setValueV3i( gl, v ) {
18601
18602	const cache = this.cache;
18603
18604	if ( v.x !== undefined ) {
18605
18606		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18607
18608			gl.uniform3i( this.addr, v.x, v.y, v.z );
18609
18610			cache[ 0 ] = v.x;
18611			cache[ 1 ] = v.y;
18612			cache[ 2 ] = v.z;
18613
18614		}
18615
18616	} else {
18617
18618		if ( arraysEqual( cache, v ) ) return;
18619
18620		gl.uniform3iv( this.addr, v );
18621
18622		copyArray( cache, v );
18623
18624	}
18625
18626}
18627
18628function setValueV4i( gl, v ) {
18629
18630	const cache = this.cache;
18631
18632	if ( v.x !== undefined ) {
18633
18634		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18635
18636			gl.uniform4i( this.addr, v.x, v.y, v.z, v.w );
18637
18638			cache[ 0 ] = v.x;
18639			cache[ 1 ] = v.y;
18640			cache[ 2 ] = v.z;
18641			cache[ 3 ] = v.w;
18642
18643		}
18644
18645	} else {
18646
18647		if ( arraysEqual( cache, v ) ) return;
18648
18649		gl.uniform4iv( this.addr, v );
18650
18651		copyArray( cache, v );
18652
18653	}
18654
18655}
18656
18657// Single unsigned integer
18658
18659function setValueV1ui( gl, v ) {
18660
18661	const cache = this.cache;
18662
18663	if ( cache[ 0 ] === v ) return;
18664
18665	gl.uniform1ui( this.addr, v );
18666
18667	cache[ 0 ] = v;
18668
18669}
18670
18671// Single unsigned integer vector (from flat array or THREE.VectorN)
18672
18673function setValueV2ui( gl, v ) {
18674
18675	const cache = this.cache;
18676
18677	if ( v.x !== undefined ) {
18678
18679		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18680
18681			gl.uniform2ui( this.addr, v.x, v.y );
18682
18683			cache[ 0 ] = v.x;
18684			cache[ 1 ] = v.y;
18685
18686		}
18687
18688	} else {
18689
18690		if ( arraysEqual( cache, v ) ) return;
18691
18692		gl.uniform2uiv( this.addr, v );
18693
18694		copyArray( cache, v );
18695
18696	}
18697
18698}
18699
18700function setValueV3ui( gl, v ) {
18701
18702	const cache = this.cache;
18703
18704	if ( v.x !== undefined ) {
18705
18706		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18707
18708			gl.uniform3ui( this.addr, v.x, v.y, v.z );
18709
18710			cache[ 0 ] = v.x;
18711			cache[ 1 ] = v.y;
18712			cache[ 2 ] = v.z;
18713
18714		}
18715
18716	} else {
18717
18718		if ( arraysEqual( cache, v ) ) return;
18719
18720		gl.uniform3uiv( this.addr, v );
18721
18722		copyArray( cache, v );
18723
18724	}
18725
18726}
18727
18728function setValueV4ui( gl, v ) {
18729
18730	const cache = this.cache;
18731
18732	if ( v.x !== undefined ) {
18733
18734		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18735
18736			gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );
18737
18738			cache[ 0 ] = v.x;
18739			cache[ 1 ] = v.y;
18740			cache[ 2 ] = v.z;
18741			cache[ 3 ] = v.w;
18742
18743		}
18744
18745	} else {
18746
18747		if ( arraysEqual( cache, v ) ) return;
18748
18749		gl.uniform4uiv( this.addr, v );
18750
18751		copyArray( cache, v );
18752
18753	}
18754
18755}
18756
18757
18758// Single texture (2D / Cube)
18759
18760function setValueT1( gl, v, textures ) {
18761
18762	const cache = this.cache;
18763	const unit = textures.allocateTextureUnit();
18764
18765	if ( cache[ 0 ] !== unit ) {
18766
18767		gl.uniform1i( this.addr, unit );
18768		cache[ 0 ] = unit;
18769
18770	}
18771
18772	const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptySh
vendor: 7,467 bytes, lines 18772-19135
18772adowTexture : emptyTexture;
18773
18774	textures.setTexture2D( v || emptyTexture2D, unit );
18775
18776}
18777
18778function setValueT3D1( gl, v, textures ) {
18779
18780	const cache = this.cache;
18781	const unit = textures.allocateTextureUnit();
18782
18783	if ( cache[ 0 ] !== unit ) {
18784
18785		gl.uniform1i( this.addr, unit );
18786		cache[ 0 ] = unit;
18787
18788	}
18789
18790	textures.setTexture3D( v || empty3dTexture, unit );
18791
18792}
18793
18794function setValueT6( gl, v, textures ) {
18795
18796	const cache = this.cache;
18797	const unit = textures.allocateTextureUnit();
18798
18799	if ( cache[ 0 ] !== unit ) {
18800
18801		gl.uniform1i( this.addr, unit );
18802		cache[ 0 ] = unit;
18803
18804	}
18805
18806	textures.setTextureCube( v || emptyCubeTexture, unit );
18807
18808}
18809
18810function setValueT2DArray1( gl, v, textures ) {
18811
18812	const cache = this.cache;
18813	const unit = textures.allocateTextureUnit();
18814
18815	if ( cache[ 0 ] !== unit ) {
18816
18817		gl.uniform1i( this.addr, unit );
18818		cache[ 0 ] = unit;
18819
18820	}
18821
18822	textures.setTexture2DArray( v || emptyArrayTexture, unit );
18823
18824}
18825
18826// Helper to pick the right setter for the singular case
18827
18828function getSingularSetter( type ) {
18829
18830	switch ( type ) {
18831
18832		case 0x1406: return setValueV1f; // FLOAT
18833		case 0x8b50: return setValueV2f; // _VEC2
18834		case 0x8b51: return setValueV3f; // _VEC3
18835		case 0x8b52: return setValueV4f; // _VEC4
18836
18837		case 0x8b5a: return setValueM2; // _MAT2
18838		case 0x8b5b: return setValueM3; // _MAT3
18839		case 0x8b5c: return setValueM4; // _MAT4
18840
18841		case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
18842		case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
18843		case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
18844		case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
18845
18846		case 0x1405: return setValueV1ui; // UINT
18847		case 0x8dc6: return setValueV2ui; // _VEC2
18848		case 0x8dc7: return setValueV3ui; // _VEC3
18849		case 0x8dc8: return setValueV4ui; // _VEC4
18850
18851		case 0x8b5e: // SAMPLER_2D
18852		case 0x8d66: // SAMPLER_EXTERNAL_OES
18853		case 0x8dca: // INT_SAMPLER_2D
18854		case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
18855		case 0x8b62: // SAMPLER_2D_SHADOW
18856			return setValueT1;
18857
18858		case 0x8b5f: // SAMPLER_3D
18859		case 0x8dcb: // INT_SAMPLER_3D
18860		case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
18861			return setValueT3D1;
18862
18863		case 0x8b60: // SAMPLER_CUBE
18864		case 0x8dcc: // INT_SAMPLER_CUBE
18865		case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
18866		case 0x8dc5: // SAMPLER_CUBE_SHADOW
18867			return setValueT6;
18868
18869		case 0x8dc1: // SAMPLER_2D_ARRAY
18870		case 0x8dcf: // INT_SAMPLER_2D_ARRAY
18871		case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
18872		case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
18873			return setValueT2DArray1;
18874
18875	}
18876
18877}
18878
18879
18880// Array of scalars
18881
18882function setValueV1fArray( gl, v ) {
18883
18884	gl.uniform1fv( this.addr, v );
18885
18886}
18887
18888// Array of vectors (from flat array or array of THREE.VectorN)
18889
18890function setValueV2fArray( gl, v ) {
18891
18892	const data = flatten( v, this.size, 2 );
18893
18894	gl.uniform2fv( this.addr, data );
18895
18896}
18897
18898function setValueV3fArray( gl, v ) {
18899
18900	const data = flatten( v, this.size, 3 );
18901
18902	gl.uniform3fv( this.addr, data );
18903
18904}
18905
18906function setValueV4fArray( gl, v ) {
18907
18908	const data = flatten( v, this.size, 4 );
18909
18910	gl.uniform4fv( this.addr, data );
18911
18912}
18913
18914// Array of matrices (from flat array or array of THREE.MatrixN)
18915
18916function setValueM2Array( gl, v ) {
18917
18918	const data = flatten( v, this.size, 4 );
18919
18920	gl.uniformMatrix2fv( this.addr, false, data );
18921
18922}
18923
18924function setValueM3Array( gl, v ) {
18925
18926	const data = flatten( v, this.size, 9 );
18927
18928	gl.uniformMatrix3fv( this.addr, false, data );
18929
18930}
18931
18932function setValueM4Array( gl, v ) {
18933
18934	const data = flatten( v, this.size, 16 );
18935
18936	gl.uniformMatrix4fv( this.addr, false, data );
18937
18938}
18939
18940// Array of integer / boolean
18941
18942function setValueV1iArray( gl, v ) {
18943
18944	gl.uniform1iv( this.addr, v );
18945
18946}
18947
18948// Array of integer / boolean vectors (from flat array)
18949
18950function setValueV2iArray( gl, v ) {
18951
18952	gl.uniform2iv( this.addr, v );
18953
18954}
18955
18956function setValueV3iArray( gl, v ) {
18957
18958	gl.uniform3iv( this.addr, v );
18959
18960}
18961
18962function setValueV4iArray( gl, v ) {
18963
18964	gl.uniform4iv( this.addr, v );
18965
18966}
18967
18968// Array of unsigned integer
18969
18970function setValueV1uiArray( gl, v ) {
18971
18972	gl.uniform1uiv( this.addr, v );
18973
18974}
18975
18976// Array of unsigned integer vectors (from flat array)
18977
18978function setValueV2uiArray( gl, v ) {
18979
18980	gl.uniform2uiv( this.addr, v );
18981
18982}
18983
18984function setValueV3uiArray( gl, v ) {
18985
18986	gl.uniform3uiv( this.addr, v );
18987
18988}
18989
18990function setValueV4uiArray( gl, v ) {
18991
18992	gl.uniform4uiv( this.addr, v );
18993
18994}
18995
18996
18997// Array of textures (2D / 3D / Cube / 2DArray)
18998
18999function setValueT1Array( gl, v, textures ) {
19000
19001	const cache = this.cache;
19002
19003	const n = v.length;
19004
19005	const units = allocTexUnits( textures, n );
19006
19007	if ( ! arraysEqual( cache, units ) ) {
19008
19009		gl.uniform1iv( this.addr, units );
19010
19011		copyArray( cache, units );
19012
19013	}
19014
19015	for ( let i = 0; i !== n; ++ i ) {
19016
19017		textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
19018
19019	}
19020
19021}
19022
19023function setValueT3DArray( gl, v, textures ) {
19024
19025	const cache = this.cache;
19026
19027	const n = v.length;
19028
19029	const units = allocTexUnits( textures, n );
19030
19031	if ( ! arraysEqual( cache, units ) ) {
19032
19033		gl.uniform1iv( this.addr, units );
19034
19035		copyArray( cache, units );
19036
19037	}
19038
19039	for ( let i = 0; i !== n; ++ i ) {
19040
19041		textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );
19042
19043	}
19044
19045}
19046
19047function setValueT6Array( gl, v, textures ) {
19048
19049	const cache = this.cache;
19050
19051	const n = v.length;
19052
19053	const units = allocTexUnits( textures, n );
19054
19055	if ( ! arraysEqual( cache, units ) ) {
19056
19057		gl.uniform1iv( this.addr, units );
19058
19059		copyArray( cache, units );
19060
19061	}
19062
19063	for ( let i = 0; i !== n; ++ i ) {
19064
19065		textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
19066
19067	}
19068
19069}
19070
19071function setValueT2DArrayArray( gl, v, textures ) {
19072
19073	const cache = this.cache;
19074
19075	const n = v.length;
19076
19077	const units = allocTexUnits( textures, n );
19078
19079	if ( ! arraysEqual( cache, units ) ) {
19080
19081		gl.uniform1iv( this.addr, units );
19082
19083		copyArray( cache, units );
19084
19085	}
19086
19087	for ( let i = 0; i !== n; ++ i ) {
19088
19089		textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );
19090
19091	}
19092
19093}
19094
19095
19096// Helper to pick the right setter for a pure (bottom-level) array
19097
19098function getPureArraySetter( type ) {
19099
19100	switch ( type ) {
19101
19102		case 0x1406: return setValueV1fArray; // FLOAT
19103		case 0x8b50: return setValueV2fArray; // _VEC2
19104		case 0x8b51: return setValueV3fArray; // _VEC3
19105		case 0x8b52: return setValueV4fArray; // _VEC4
19106
19107		case 0x8b5a: return setValueM2Array; // _MAT2
19108		case 0x8b5b: return setValueM3Array; // _MAT3
19109		case 0x8b5c: return setValueM4Array; // _MAT4
19110
19111		case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
19112		case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
19113		case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
19114		case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
19115
19116		case 0x1405: return setValueV1uiArray; // UINT
19117		case 0x8dc6: return setValueV2uiArray; // _VEC2
19118		case 0x8dc7: return setValueV3uiArray; // _VEC3
19119		case 0x8dc8: return setValueV4uiArray; // _VEC4
19120
19121		case 0x8b5e: // SAMPLER_2D
19122		case 0x8d66: // SAMPLER_EXTERNAL_OES
19123		case 0x8dca: // INT_SAMPLER_2D
19124		case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
19125		case 0x8b62: // SAMPLER_2D_SHADOW
19126			return setValueT1Array;
19127
19128		case 0x8b5f: // SAMPLER_3D
19129		case 0x8dcb: // INT_SAMPLER_3D
19130		case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
19131			return setValueT3DArray;
19132
19133		case 0x8b60: // SAMPLER_CUBE
19134		case 0x8dcc: // INT_SAMPLER_CUBE
19135		case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
vendor: 216,434 bytes, lines 19136-27437
19136		case 0x8dc5: // SAMPLER_CUBE_SHADOW
19137			return setValueT6Array;
19138
19139		case 0x8dc1: // SAMPLER_2D_ARRAY
19140		case 0x8dcf: // INT_SAMPLER_2D_ARRAY
19141		case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
19142		case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
19143			return setValueT2DArrayArray;
19144
19145	}
19146
19147}
19148
19149// --- Uniform Classes ---
19150
19151class SingleUniform {
19152
19153	constructor( id, activeInfo, addr ) {
19154
19155		this.id = id;
19156		this.addr = addr;
19157		this.cache = [];
19158		this.type = activeInfo.type;
19159		this.setValue = getSingularSetter( activeInfo.type );
19160
19161		// this.path = activeInfo.name; // DEBUG
19162
19163	}
19164
19165}
19166
19167class PureArrayUniform {
19168
19169	constructor( id, activeInfo, addr ) {
19170
19171		this.id = id;
19172		this.addr = addr;
19173		this.cache = [];
19174		this.type = activeInfo.type;
19175		this.size = activeInfo.size;
19176		this.setValue = getPureArraySetter( activeInfo.type );
19177
19178		// this.path = activeInfo.name; // DEBUG
19179
19180	}
19181
19182}
19183
19184class StructuredUniform {
19185
19186	constructor( id ) {
19187
19188		this.id = id;
19189
19190		this.seq = [];
19191		this.map = {};
19192
19193	}
19194
19195	setValue( gl, value, textures ) {
19196
19197		const seq = this.seq;
19198
19199		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19200
19201			const u = seq[ i ];
19202			u.setValue( gl, value[ u.id ], textures );
19203
19204		}
19205
19206	}
19207
19208}
19209
19210// --- Top-level ---
19211
19212// Parser - builds up the property tree from the path strings
19213
19214const RePathPart = /(\w+)(\])?(\[|\.)?/g;
19215
19216// extracts
19217// 	- the identifier (member name or array index)
19218//  - followed by an optional right bracket (found when array index)
19219//  - followed by an optional left bracket or dot (type of subscript)
19220//
19221// Note: These portions can be read in a non-overlapping fashion and
19222// allow straightforward parsing of the hierarchy that WebGL encodes
19223// in the uniform names.
19224
19225function addUniform( container, uniformObject ) {
19226
19227	container.seq.push( uniformObject );
19228	container.map[ uniformObject.id ] = uniformObject;
19229
19230}
19231
19232function parseUniform( activeInfo, addr, container ) {
19233
19234	const path = activeInfo.name,
19235		pathLength = path.length;
19236
19237	// reset RegExp object, because of the early exit of a previous run
19238	RePathPart.lastIndex = 0;
19239
19240	while ( true ) {
19241
19242		const match = RePathPart.exec( path ),
19243			matchEnd = RePathPart.lastIndex;
19244
19245		let id = match[ 1 ];
19246		const idIsIndex = match[ 2 ] === ']',
19247			subscript = match[ 3 ];
19248
19249		if ( idIsIndex ) id = id | 0; // convert to integer
19250
19251		if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
19252
19253			// bare name or "pure" bottom-level array "[0]" suffix
19254
19255			addUniform( container, subscript === undefined ?
19256				new SingleUniform( id, activeInfo, addr ) :
19257				new PureArrayUniform( id, activeInfo, addr ) );
19258
19259			break;
19260
19261		} else {
19262
19263			// step into inner node / create it in case it doesn't exist
19264
19265			const map = container.map;
19266			let next = map[ id ];
19267
19268			if ( next === undefined ) {
19269
19270				next = new StructuredUniform( id );
19271				addUniform( container, next );
19272
19273			}
19274
19275			container = next;
19276
19277		}
19278
19279	}
19280
19281}
19282
19283// Root Container
19284
19285class WebGLUniforms {
19286
19287	constructor( gl, program ) {
19288
19289		this.seq = [];
19290		this.map = {};
19291
19292		const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
19293
19294		for ( let i = 0; i < n; ++ i ) {
19295
19296			const info = gl.getActiveUniform( program, i ),
19297				addr = gl.getUniformLocation( program, info.name );
19298
19299			parseUniform( info, addr, this );
19300
19301		}
19302
19303	}
19304
19305	setValue( gl, name, value, textures ) {
19306
19307		const u = this.map[ name ];
19308
19309		if ( u !== undefined ) u.setValue( gl, value, textures );
19310
19311	}
19312
19313	setOptional( gl, object, name ) {
19314
19315		const v = object[ name ];
19316
19317		if ( v !== undefined ) this.setValue( gl, name, v );
19318
19319	}
19320
19321	static upload( gl, seq, values, textures ) {
19322
19323		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19324
19325			const u = seq[ i ],
19326
19327				v = values[ u.id ];
19328
19329			if ( v.needsUpdate !== false ) {
19330
19331				// note: always updating when .needsUpdate is undefined
19332				u.setValue( gl, v.value, textures );
19333
19334			}
19335
19336		}
19337
19338	}
19339
19340	static seqWithValue( seq, values ) {
19341
19342		const r = [];
19343
19344		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19345
19346			const u = seq[ i ];
19347			if ( u.id in values ) r.push( u );
19348
19349		}
19350
19351		return r;
19352
19353	}
19354
19355}
19356
19357function WebGLShader( gl, type, string ) {
19358
19359	const shader = gl.createShader( type );
19360
19361	gl.shaderSource( shader, string );
19362	gl.compileShader( shader );
19363
19364	return shader;
19365
19366}
19367
19368// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
19369const COMPLETION_STATUS_KHR = 0x91B1;
19370
19371let programIdCount = 0;
19372
19373function handleSource( string, errorLine ) {
19374
19375	const lines = string.split( '\n' );
19376	const lines2 = [];
19377
19378	const from = Math.max( errorLine - 6, 0 );
19379	const to = Math.min( errorLine + 6, lines.length );
19380
19381	for ( let i = from; i < to; i ++ ) {
19382
19383		const line = i + 1;
19384		lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );
19385
19386	}
19387
19388	return lines2.join( '\n' );
19389
19390}
19391
19392function getEncodingComponents( colorSpace ) {
19393
19394	const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
19395	const encodingPrimaries = ColorManagement.getPrimaries( colorSpace );
19396
19397	let gamutMapping;
19398
19399	if ( workingPrimaries === encodingPrimaries ) {
19400
19401		gamutMapping = '';
19402
19403	} else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) {
19404
19405		gamutMapping = 'LinearDisplayP3ToLinearSRGB';
19406
19407	} else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) {
19408
19409		gamutMapping = 'LinearSRGBToLinearDisplayP3';
19410
19411	}
19412
19413	switch ( colorSpace ) {
19414
19415		case LinearSRGBColorSpace:
19416		case LinearDisplayP3ColorSpace:
19417			return [ gamutMapping, 'LinearTransferOETF' ];
19418
19419		case SRGBColorSpace:
19420		case DisplayP3ColorSpace:
19421			return [ gamutMapping, 'sRGBTransferOETF' ];
19422
19423		default:
19424			console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );
19425			return [ gamutMapping, 'LinearTransferOETF' ];
19426
19427	}
19428
19429}
19430
19431function getShaderErrors( gl, shader, type ) {
19432
19433	const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );
19434	const errors = gl.getShaderInfoLog( shader ).trim();
19435
19436	if ( status && errors === '' ) return '';
19437
19438	const errorMatches = /ERROR: 0:(\d+)/.exec( errors );
19439	if ( errorMatches ) {
19440
19441		// --enable-privileged-webgl-extension
19442		// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
19443
19444		const errorLine = parseInt( errorMatches[ 1 ] );
19445		return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine );
19446
19447	} else {
19448
19449		return errors;
19450
19451	}
19452
19453}
19454
19455function getTexelEncodingFunction( functionName, colorSpace ) {
19456
19457	const components = getEncodingComponents( colorSpace );
19458	return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;
19459
19460}
19461
19462function getToneMappingFunction( functionName, toneMapping ) {
19463
19464	let toneMappingName;
19465
19466	switch ( toneMapping ) {
19467
19468		case LinearToneMapping:
19469			toneMappingName = 'Linear';
19470			break;
19471
19472		case ReinhardToneMapping:
19473			toneMappingName = 'Reinhard';
19474			break;
19475
19476		case CineonToneMapping:
19477			toneMappingName = 'OptimizedCineon';
19478			break;
19479
19480		case ACESFilmicToneMapping:
19481			toneMappingName = 'ACESFilmic';
19482			break;
19483
19484		case AgXToneMapping:
19485			toneMappingName = 'AgX';
19486			break;
19487
19488		case CustomToneMapping:
19489			toneMappingName = 'Custom';
19490			break;
19491
19492		default:
19493			console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
19494			toneMappingName = 'Linear';
19495
19496	}
19497
19498	return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
19499
19500}
19501
19502function generateExtensions( parameters ) {
19503
19504	const chunks = [
19505		( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
19506		( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
19507		( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
19508		( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
19509	];
19510
19511	return chunks.filter( filterEmptyLine ).join( '\n' );
19512
19513}
19514
19515function generateVertexExtensions( parameters ) {
19516
19517	const chunks = [
19518		parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : ''
19519	];
19520
19521	return chunks.filter( filterEmptyLine ).join( '\n' );
19522
19523}
19524
19525function generateDefines( defines ) {
19526
19527	const chunks = [];
19528
19529	for ( const name in defines ) {
19530
19531		const value = defines[ name ];
19532
19533		if ( value === false ) continue;
19534
19535		chunks.push( '#define ' + name + ' ' + value );
19536
19537	}
19538
19539	return chunks.join( '\n' );
19540
19541}
19542
19543function fetchAttributeLocations( gl, program ) {
19544
19545	const attributes = {};
19546
19547	const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
19548
19549	for ( let i = 0; i < n; i ++ ) {
19550
19551		const info = gl.getActiveAttrib( program, i );
19552		const name = info.name;
19553
19554		let locationSize = 1;
19555		if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
19556		if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
19557		if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;
19558
19559		// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
19560
19561		attributes[ name ] = {
19562			type: info.type,
19563			location: gl.getAttribLocation( program, name ),
19564			locationSize: locationSize
19565		};
19566
19567	}
19568
19569	return attributes;
19570
19571}
19572
19573function filterEmptyLine( string ) {
19574
19575	return string !== '';
19576
19577}
19578
19579function replaceLightNums( string, parameters ) {
19580
19581	const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;
19582
19583	return string
19584		.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
19585		.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
19586		.replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
19587		.replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )
19588		.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
19589		.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
19590		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
19591		.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
19592		.replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )
19593		.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
19594		.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
19595
19596}
19597
19598function replaceClippingPlaneNums( string, parameters ) {
19599
19600	return string
19601		.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
19602		.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
19603
19604}
19605
19606// Resolve Includes
19607
19608const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
19609
19610function resolveIncludes( string ) {
19611
19612	return string.replace( includePattern, includeReplacer );
19613
19614}
19615
19616const shaderChunkMap = new Map( [
19617	[ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154
19618	[ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154
19619	[ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154
19620] );
19621
19622function includeReplacer( match, include ) {
19623
19624	let string = ShaderChunk[ include ];
19625
19626	if ( string === undefined ) {
19627
19628		const newInclude = shaderChunkMap.get( include );
19629
19630		if ( newInclude !== undefined ) {
19631
19632			string = ShaderChunk[ newInclude ];
19633			console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude );
19634
19635		} else {
19636
19637			throw new Error( 'Can not resolve #include <' + include + '>' );
19638
19639		}
19640
19641	}
19642
19643	return resolveIncludes( string );
19644
19645}
19646
19647// Unroll Loops
19648
19649const 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;
19650
19651function unrollLoops( string ) {
19652
19653	return string.replace( unrollLoopPattern, loopReplacer );
19654
19655}
19656
19657function loopReplacer( match, start, end, snippet ) {
19658
19659	let string = '';
19660
19661	for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
19662
19663		string += snippet
19664			.replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
19665			.replace( /UNROLLED_LOOP_INDEX/g, i );
19666
19667	}
19668
19669	return string;
19670
19671}
19672
19673//
19674
19675function generatePrecision( parameters ) {
19676
19677	let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
19678
19679	if ( parameters.precision === 'highp' ) {
19680
19681		precisionstring += '\n#define HIGH_PRECISION';
19682
19683	} else if ( parameters.precision === 'mediump' ) {
19684
19685		precisionstring += '\n#define MEDIUM_PRECISION';
19686
19687	} else if ( parameters.precision === 'lowp' ) {
19688
19689		precisionstring += '\n#define LOW_PRECISION';
19690
19691	}
19692
19693	return precisionstring;
19694
19695}
19696
19697function generateShadowMapTypeDefine( parameters ) {
19698
19699	let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
19700
19701	if ( parameters.shadowMapType === PCFShadowMap ) {
19702
19703		shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
19704
19705	} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
19706
19707		shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
19708
19709	} else if ( parameters.shadowMapType === VSMShadowMap ) {
19710
19711		shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
19712
19713	}
19714
19715	return shadowMapTypeDefine;
19716
19717}
19718
19719function generateEnvMapTypeDefine( parameters ) {
19720
19721	let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19722
19723	if ( parameters.envMap ) {
19724
19725		switch ( parameters.envMapMode ) {
19726
19727			case CubeReflectionMapping:
19728			case CubeRefractionMapping:
19729				envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19730				break;
19731
19732			case CubeUVReflectionMapping:
19733				envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
19734				break;
19735
19736		}
19737
19738	}
19739
19740	return envMapTypeDefine;
19741
19742}
19743
19744function generateEnvMapModeDefine( parameters ) {
19745
19746	let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
19747
19748	if ( parameters.envMap ) {
19749
19750		switch ( parameters.envMapMode ) {
19751
19752			case CubeRefractionMapping:
19753
19754				envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
19755				break;
19756
19757		}
19758
19759	}
19760
19761	return envMapModeDefine;
19762
19763}
19764
19765function generateEnvMapBlendingDefine( parameters ) {
19766
19767	let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
19768
19769	if ( parameters.envMap ) {
19770
19771		switch ( parameters.combine ) {
19772
19773			case MultiplyOperation:
19774				envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
19775				break;
19776
19777			case MixOperation:
19778				envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
19779				break;
19780
19781			case AddOperation:
19782				envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
19783				break;
19784
19785		}
19786
19787	}
19788
19789	return envMapBlendingDefine;
19790
19791}
19792
19793function generateCubeUVSize( parameters ) {
19794
19795	const imageHeight = parameters.envMapCubeUVHeight;
19796
19797	if ( imageHeight === null ) return null;
19798
19799	const maxMip = Math.log2( imageHeight ) - 2;
19800
19801	const texelHeight = 1.0 / imageHeight;
19802
19803	const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
19804
19805	return { texelWidth, texelHeight, maxMip };
19806
19807}
19808
19809function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
19810
19811	// TODO Send this event to Three.js DevTools
19812	// console.log( 'WebGLProgram', cacheKey );
19813
19814	const gl = renderer.getContext();
19815
19816	const defines = parameters.defines;
19817
19818	let vertexShader = parameters.vertexShader;
19819	let fragmentShader = parameters.fragmentShader;
19820
19821	const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
19822	const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
19823	const envMapModeDefine = generateEnvMapModeDefine( parameters );
19824	const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
19825	const envMapCubeUVSize = generateCubeUVSize( parameters );
19826
19827	const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
19828
19829	const customVertexExtensions = generateVertexExtensions( parameters );
19830
19831	const customDefines = generateDefines( defines );
19832
19833	const program = gl.createProgram();
19834
19835	let prefixVertex, prefixFragment;
19836	let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
19837
19838	if ( parameters.isRawShaderMaterial ) {
19839
19840		prefixVertex = [
19841
19842			'#define SHADER_TYPE ' + parameters.shaderType,
19843			'#define SHADER_NAME ' + parameters.shaderName,
19844
19845			customDefines
19846
19847		].filter( filterEmptyLine ).join( '\n' );
19848
19849		if ( prefixVertex.length > 0 ) {
19850
19851			prefixVertex += '\n';
19852
19853		}
19854
19855		prefixFragment = [
19856
19857			customExtensions,
19858
19859			'#define SHADER_TYPE ' + parameters.shaderType,
19860			'#define SHADER_NAME ' + parameters.shaderName,
19861
19862			customDefines
19863
19864		].filter( filterEmptyLine ).join( '\n' );
19865
19866		if ( prefixFragment.length > 0 ) {
19867
19868			prefixFragment += '\n';
19869
19870		}
19871
19872	} else {
19873
19874		prefixVertex = [
19875
19876			generatePrecision( parameters ),
19877
19878			'#define SHADER_TYPE ' + parameters.shaderType,
19879			'#define SHADER_NAME ' + parameters.shaderName,
19880
19881			customDefines,
19882
19883			parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
19884			parameters.batching ? '#define USE_BATCHING' : '',
19885			parameters.instancing ? '#define USE_INSTANCING' : '',
19886			parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
19887
19888			parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
19889			parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
19890
19891			parameters.map ? '#define USE_MAP' : '',
19892			parameters.envMap ? '#define USE_ENVMAP' : '',
19893			parameters.envMap ? '#define ' + envMapModeDefine : '',
19894			parameters.lightMap ? '#define USE_LIGHTMAP' : '',
19895			parameters.aoMap ? '#define USE_AOMAP' : '',
19896			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
19897			parameters.normalMap ? '#define USE_NORMALMAP' : '',
19898			parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
19899			parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
19900			parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',
19901			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
19902
19903			parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
19904			parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
19905
19906			parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
19907			parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
19908			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
19909
19910			parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
19911			parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
19912
19913			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
19914			parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
19915			parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
19916
19917			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
19918			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
19919			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
19920			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
19921
19922			parameters.transmission ? '#define USE_TRANSMISSION' : '',
19923			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
19924			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
19925
19926			parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
19927			parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
19928
19929			//
19930
19931			parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',
19932			parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',
19933			parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',
19934			parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',
19935			parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',
19936			parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',
19937			parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',
19938			parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',
19939
19940			parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',
19941			parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',
19942
19943			parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',
19944
19945			parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',
19946			parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',
19947			parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',
19948
19949			parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',
19950			parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',
19951
19952			parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',
19953			parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',
19954
19955			parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',
19956			parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',
19957			parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',
19958
19959			parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',
19960			parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',
19961
19962			//
19963
19964			parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
19965			parameters.vertexColors ? '#define USE_COLOR' : '',
19966			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
19967			parameters.vertexUv1s ? '#define USE_UV1' : '',
19968			parameters.vertexUv2s ? '#define USE_UV2' : '',
19969			parameters.vertexUv3s ? '#define USE_UV3' : '',
19970
19971			parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
19972
19973			parameters.flatShading ? '#define FLAT_SHADED' : '',
19974
19975			parameters.skinning ? '#define USE_SKINNING' : '',
19976
19977			parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
19978			parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
19979			( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '',
19980			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
19981			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
19982			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
19983			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
19984			parameters.flipSided ? '#define FLIP_SIDED' : '',
19985
19986			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
19987			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
19988
19989			parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
19990
19991			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
19992
19993			parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
19994
19995			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
19996			( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
19997
19998			'uniform mat4 modelMatrix;',
19999			'uniform mat4 modelViewMatrix;',
20000			'uniform mat4 projectionMatrix;',
20001			'uniform mat4 viewMatrix;',
20002			'uniform mat3 normalMatrix;',
20003			'uniform vec3 cameraPosition;',
20004			'uniform bool isOrthographic;',
20005
20006			'#ifdef USE_INSTANCING',
20007
20008			'	attribute mat4 instanceMatrix;',
20009
20010			'#endif',
20011
20012			'#ifdef USE_INSTANCING_COLOR',
20013
20014			'	attribute vec3 instanceColor;',
20015
20016			'#endif',
20017
20018			'attribute vec3 position;',
20019			'attribute vec3 normal;',
20020			'attribute vec2 uv;',
20021
20022			'#ifdef USE_UV1',
20023
20024			'	attribute vec2 uv1;',
20025
20026			'#endif',
20027
20028			'#ifdef USE_UV2',
20029
20030			'	attribute vec2 uv2;',
20031
20032			'#endif',
20033
20034			'#ifdef USE_UV3',
20035
20036			'	attribute vec2 uv3;',
20037
20038			'#endif',
20039
20040			'#ifdef USE_TANGENT',
20041
20042			'	attribute vec4 tangent;',
20043
20044			'#endif',
20045
20046			'#if defined( USE_COLOR_ALPHA )',
20047
20048			'	attribute vec4 color;',
20049
20050			'#elif defined( USE_COLOR )',
20051
20052			'	attribute vec3 color;',
20053
20054			'#endif',
20055
20056			'#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
20057
20058			'	attribute vec3 morphTarget0;',
20059			'	attribute vec3 morphTarget1;',
20060			'	attribute vec3 morphTarget2;',
20061			'	attribute vec3 morphTarget3;',
20062
20063			'	#ifdef USE_MORPHNORMALS',
20064
20065			'		attribute vec3 morphNormal0;',
20066			'		attribute vec3 morphNormal1;',
20067			'		attribute vec3 morphNormal2;',
20068			'		attribute vec3 morphNormal3;',
20069
20070			'	#else',
20071
20072			'		attribute vec3 morphTarget4;',
20073			'		attribute vec3 morphTarget5;',
20074			'		attribute vec3 morphTarget6;',
20075			'		attribute vec3 morphTarget7;',
20076
20077			'	#endif',
20078
20079			'#endif',
20080
20081			'#ifdef USE_SKINNING',
20082
20083			'	attribute vec4 skinIndex;',
20084			'	attribute vec4 skinWeight;',
20085
20086			'#endif',
20087
20088			'\n'
20089
20090		].filter( filterEmptyLine ).join( '\n' );
20091
20092		prefixFragment = [
20093
20094			customExtensions,
20095
20096			generatePrecision( parameters ),
20097
20098			'#define SHADER_TYPE ' + parameters.shaderType,
20099			'#define SHADER_NAME ' + parameters.shaderName,
20100
20101			customDefines,
20102
20103			parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
20104			parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
20105
20106			parameters.map ? '#define USE_MAP' : '',
20107			parameters.matcap ? '#define USE_MATCAP' : '',
20108			parameters.envMap ? '#define USE_ENVMAP' : '',
20109			parameters.envMap ? '#define ' + envMapTypeDefine : '',
20110			parameters.envMap ? '#define ' + envMapModeDefine : '',
20111			parameters.envMap ? '#define ' + envMapBlendingDefine : '',
20112			envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
20113			envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
20114			envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
20115			parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20116			parameters.aoMap ? '#define USE_AOMAP' : '',
20117			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20118			parameters.normalMap ? '#define USE_NORMALMAP' : '',
20119			parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
20120			parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
20121			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20122
20123			parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
20124			parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
20125
20126			parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
20127			parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
20128			parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
20129			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
20130
20131			parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
20132			parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
20133			parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
20134
20135			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20136			parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
20137			parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
20138
20139			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20140			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20141
20142			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20143			parameters.alphaTest ? '#define USE_ALPHATEST' : '',
20144			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
20145
20146			parameters.sheen ? '#define USE_SHEEN' : '',
20147			parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
20148			parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
20149
20150			parameters.transmission ? '#define USE_TRANSMISSION' : '',
20151			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
20152			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
20153
20154			parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
20155			parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
20156			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
20157			parameters.vertexUv1s ? '#define USE_UV1' : '',
20158			parameters.vertexUv2s ? '#define USE_UV2' : '',
20159			parameters.vertexUv3s ? '#define USE_UV3' : '',
20160
20161			parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
20162
20163			parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
20164
20165			parameters.flatShading ? '#define FLAT_SHADED' : '',
20166
20167			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20168			parameters.flipSided ? '#define FLIP_SIDED' : '',
20169
20170			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20171			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20172
20173			parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
20174
20175			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
20176
20177			parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
20178
20179			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
20180
20181			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20182			( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20183
20184			'uniform mat4 viewMatrix;',
20185			'uniform vec3 cameraPosition;',
20186			'uniform bool isOrthographic;',
20187
20188			( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
20189			( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
20190			( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
20191
20192			parameters.dithering ? '#define DITHERING' : '',
20193			parameters.opaque ? '#define OPAQUE' : '',
20194
20195			ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
20196			getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),
20197
20198			parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
20199
20200			'\n'
20201
20202		].filter( filterEmptyLine ).join( '\n' );
20203
20204	}
20205
20206	vertexShader = resolveIncludes( vertexShader );
20207	vertexShader = replaceLightNums( vertexShader, parameters );
20208	vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
20209
20210	fragmentShader = resolveIncludes( fragmentShader );
20211	fragmentShader = replaceLightNums( fragmentShader, parameters );
20212	fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
20213
20214	vertexShader = unrollLoops( vertexShader );
20215	fragmentShader = unrollLoops( fragmentShader );
20216
20217	if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
20218
20219		// GLSL 3.0 conversion for built-in materials and ShaderMaterial
20220
20221		versionString = '#version 300 es\n';
20222
20223		prefixVertex = [
20224			customVertexExtensions,
20225			'precision mediump sampler2DArray;',
20226			'#define attribute in',
20227			'#define varying out',
20228			'#define texture2D texture'
20229		].join( '\n' ) + '\n' + prefixVertex;
20230
20231		prefixFragment = [
20232			'precision mediump sampler2DArray;',
20233			'#define varying in',
20234			( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
20235			( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
20236			'#define gl_FragDepthEXT gl_FragDepth',
20237			'#define texture2D texture',
20238			'#define textureCube texture',
20239			'#define texture2DProj textureProj',
20240			'#define texture2DLodEXT textureLod',
20241			'#define texture2DProjLodEXT textureProjLod',
20242			'#define textureCubeLodEXT textureLod',
20243			'#define texture2DGradEXT textureGrad',
20244			'#define texture2DProjGradEXT textureProjGrad',
20245			'#define textureCubeGradEXT textureGrad'
20246		].join( '\n' ) + '\n' + prefixFragment;
20247
20248	}
20249
20250	const vertexGlsl = versionString + prefixVertex + vertexShader;
20251	const fragmentGlsl = versionString + prefixFragment + fragmentShader;
20252
20253	// console.log( '*VERTEX*', vertexGlsl );
20254	// console.log( '*FRAGMENT*', fragmentGlsl );
20255
20256	const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
20257	const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
20258
20259	gl.attachShader( program, glVertexShader );
20260	gl.attachShader( program, glFragmentShader );
20261
20262	// Force a particular attribute to index 0.
20263
20264	if ( parameters.index0AttributeName !== undefined ) {
20265
20266		gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
20267
20268	} else if ( parameters.morphTargets === true ) {
20269
20270		// programs with morphTargets displace position out of attribute 0
20271		gl.bindAttribLocation( program, 0, 'position' );
20272
20273	}
20274
20275	gl.linkProgram( program );
20276
20277	function onFirstUse( self ) {
20278
20279		// check for link errors
20280		if ( renderer.debug.checkShaderErrors ) {
20281
20282			const programLog = gl.getProgramInfoLog( program ).trim();
20283			const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
20284			const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
20285
20286			let runnable = true;
20287			let haveDiagnostics = true;
20288
20289			if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
20290
20291				runnable = false;
20292
20293				if ( typeof renderer.debug.onShaderError === 'function' ) {
20294
20295					renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );
20296
20297				} else {
20298
20299					// default error reporting
20300
20301					const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
20302					const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
20303
20304					console.error(
20305						'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
20306						'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
20307						'Program Info Log: ' + programLog + '\n' +
20308						vertexErrors + '\n' +
20309						fragmentErrors
20310					);
20311
20312				}
20313
20314			} else if ( programLog !== '' ) {
20315
20316				console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );
20317
20318			} else if ( vertexLog === '' || fragmentLog === '' ) {
20319
20320				haveDiagnostics = false;
20321
20322			}
20323
20324			if ( haveDiagnostics ) {
20325
20326				self.diagnostics = {
20327
20328					runnable: runnable,
20329
20330					programLog: programLog,
20331
20332					vertexShader: {
20333
20334						log: vertexLog,
20335						prefix: prefixVertex
20336
20337					},
20338
20339					fragmentShader: {
20340
20341						log: fragmentLog,
20342						prefix: prefixFragment
20343
20344					}
20345
20346				};
20347
20348			}
20349
20350		}
20351
20352		// Clean up
20353
20354		// Crashes in iOS9 and iOS10. #18402
20355		// gl.detachShader( program, glVertexShader );
20356		// gl.detachShader( program, glFragmentShader );
20357
20358		gl.deleteShader( glVertexShader );
20359		gl.deleteShader( glFragmentShader );
20360
20361		cachedUniforms = new WebGLUniforms( gl, program );
20362		cachedAttributes = fetchAttributeLocations( gl, program );
20363
20364	}
20365
20366	// set up caching for uniform locations
20367
20368	let cachedUniforms;
20369
20370	this.getUniforms = function () {
20371
20372		if ( cachedUniforms === undefined ) {
20373
20374			// Populates cachedUniforms and cachedAttributes
20375			onFirstUse( this );
20376
20377		}
20378
20379		return cachedUniforms;
20380
20381	};
20382
20383	// set up caching for attribute locations
20384
20385	let cachedAttributes;
20386
20387	this.getAttributes = function () {
20388
20389		if ( cachedAttributes === undefined ) {
20390
20391			// Populates cachedAttributes and cachedUniforms
20392			onFirstUse( this );
20393
20394		}
20395
20396		return cachedAttributes;
20397
20398	};
20399
20400	// indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,
20401	// flag the program as ready immediately. It may cause a stall when it's first used.
20402
20403	let programReady = ( parameters.rendererExtensionParallelShaderCompile === false );
20404
20405	this.isReady = function () {
20406
20407		if ( programReady === false ) {
20408
20409			programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );
20410
20411		}
20412
20413		return programReady;
20414
20415	};
20416
20417	// free resource
20418
20419	this.destroy = function () {
20420
20421		bindingStates.releaseStatesOfProgram( this );
20422
20423		gl.deleteProgram( program );
20424		this.program = undefined;
20425
20426	};
20427
20428	//
20429
20430	this.type = parameters.shaderType;
20431	this.name = parameters.shaderName;
20432	this.id = programIdCount ++;
20433	this.cacheKey = cacheKey;
20434	this.usedTimes = 1;
20435	this.program = program;
20436	this.vertexShader = glVertexShader;
20437	this.fragmentShader = glFragmentShader;
20438
20439	return this;
20440
20441}
20442
20443let _id$1 = 0;
20444
20445class WebGLShaderCache {
20446
20447	constructor() {
20448
20449		this.shaderCache = new Map();
20450		this.materialCache = new Map();
20451
20452	}
20453
20454	update( material ) {
20455
20456		const vertexShader = material.vertexShader;
20457		const fragmentShader = material.fragmentShader;
20458
20459		const vertexShaderStage = this._getShaderStage( vertexShader );
20460		const fragmentShaderStage = this._getShaderStage( fragmentShader );
20461
20462		const materialShaders = this._getShaderCacheForMaterial( material );
20463
20464		if ( materialShaders.has( vertexShaderStage ) === false ) {
20465
20466			materialShaders.add( vertexShaderStage );
20467			vertexShaderStage.usedTimes ++;
20468
20469		}
20470
20471		if ( materialShaders.has( fragmentShaderStage ) === false ) {
20472
20473			materialShaders.add( fragmentShaderStage );
20474			fragmentShaderStage.usedTimes ++;
20475
20476		}
20477
20478		return this;
20479
20480	}
20481
20482	remove( material ) {
20483
20484		const materialShaders = this.materialCache.get( material );
20485
20486		for ( const shaderStage of materialShaders ) {
20487
20488			shaderStage.usedTimes --;
20489
20490			if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );
20491
20492		}
20493
20494		this.materialCache.delete( material );
20495
20496		return this;
20497
20498	}
20499
20500	getVertexShaderID( material ) {
20501
20502		return this._getShaderStage( material.vertexShader ).id;
20503
20504	}
20505
20506	getFragmentShaderID( material ) {
20507
20508		return this._getShaderStage( material.fragmentShader ).id;
20509
20510	}
20511
20512	dispose() {
20513
20514		this.shaderCache.clear();
20515		this.materialCache.clear();
20516
20517	}
20518
20519	_getShaderCacheForMaterial( material ) {
20520
20521		const cache = this.materialCache;
20522		let set = cache.get( material );
20523
20524		if ( set === undefined ) {
20525
20526			set = new Set();
20527			cache.set( material, set );
20528
20529		}
20530
20531		return set;
20532
20533	}
20534
20535	_getShaderStage( code ) {
20536
20537		const cache = this.shaderCache;
20538		let stage = cache.get( code );
20539
20540		if ( stage === undefined ) {
20541
20542			stage = new WebGLShaderStage( code );
20543			cache.set( code, stage );
20544
20545		}
20546
20547		return stage;
20548
20549	}
20550
20551}
20552
20553class WebGLShaderStage {
20554
20555	constructor( code ) {
20556
20557		this.id = _id$1 ++;
20558
20559		this.code = code;
20560		this.usedTimes = 0;
20561
20562	}
20563
20564}
20565
20566function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
20567
20568	const _programLayers = new Layers();
20569	const _customShaders = new WebGLShaderCache();
20570	const programs = [];
20571
20572	const IS_WEBGL2 = capabilities.isWebGL2;
20573	const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
20574	const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;
20575
20576	let precision = capabilities.precision;
20577
20578	const shaderIDs = {
20579		MeshDepthMaterial: 'depth',
20580		MeshDistanceMaterial: 'distanceRGBA',
20581		MeshNormalMaterial: 'normal',
20582		MeshBasicMaterial: 'basic',
20583		MeshLambertMaterial: 'lambert',
20584		MeshPhongMaterial: 'phong',
20585		MeshToonMaterial: 'toon',
20586		MeshStandardMaterial: 'physical',
20587		MeshPhysicalMaterial: 'physical',
20588		MeshMatcapMaterial: 'matcap',
20589		LineBasicMaterial: 'basic',
20590		LineDashedMaterial: 'dashed',
20591		PointsMaterial: 'points',
20592		ShadowMaterial: 'shadow',
20593		SpriteMaterial: 'sprite'
20594	};
20595
20596	function getChannel( value ) {
20597
20598		if ( value === 0 ) return 'uv';
20599
20600		return `uv${ value }`;
20601
20602	}
20603
20604	function getParameters( material, lights, shadows, scene, object ) {
20605
20606		const fog = scene.fog;
20607		const geometry = object.geometry;
20608		const environment = material.isMeshStandardMaterial ? scene.environment : null;
20609
20610		const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
20611		const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;
20612
20613		const shaderID = shaderIDs[ material.type ];
20614
20615		// heuristics to create shader parameters according to lights in the scene
20616		// (not to blow over maxLights budget)
20617
20618		if ( material.precision !== null ) {
20619
20620			precision = capabilities.getMaxPrecision( material.precision );
20621
20622			if ( precision !== material.precision ) {
20623
20624				console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
20625
20626			}
20627
20628		}
20629
20630		//
20631
20632		const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
20633		const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
20634
20635		let morphTextureStride = 0;
20636
20637		if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
20638		if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
20639		if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;
20640
20641		//
20642
20643		let vertexShader, fragmentShader;
20644		let customVertexShaderID, customFragmentShaderID;
20645
20646		if ( shaderID ) {
20647
20648			const shader = ShaderLib[ shaderID ];
20649
20650			vertexShader = shader.vertexShader;
20651			fragmentShader = shader.fragmentShader;
20652
20653		} else {
20654
20655			vertexShader = material.vertexShader;
20656			fragmentShader = material.fragmentShader;
20657
20658			_customShaders.update( material );
20659
20660			customVertexShaderID = _customShaders.getVertexShaderID( material );
20661			customFragmentShaderID = _customShaders.getFragmentShaderID( material );
20662
20663		}
20664
20665		const currentRenderTarget = renderer.getRenderTarget();
20666
20667		const IS_INSTANCEDMESH = object.isInstancedMesh === true;
20668		const IS_BATCHEDMESH = object.isBatchedMesh === true;
20669
20670		const HAS_MAP = !! material.map;
20671		const HAS_MATCAP = !! material.matcap;
20672		const HAS_ENVMAP = !! envMap;
20673		const HAS_AOMAP = !! material.aoMap;
20674		const HAS_LIGHTMAP = !! material.lightMap;
20675		const HAS_BUMPMAP = !! material.bumpMap;
20676		const HAS_NORMALMAP = !! material.normalMap;
20677		const HAS_DISPLACEMENTMAP = !! material.displacementMap;
20678		const HAS_EMISSIVEMAP = !! material.emissiveMap;
20679
20680		const HAS_METALNESSMAP = !! material.metalnessMap;
20681		const HAS_ROUGHNESSMAP = !! material.roughnessMap;
20682
20683		const HAS_ANISOTROPY = material.anisotropy > 0;
20684		const HAS_CLEARCOAT = material.clearcoat > 0;
20685		const HAS_IRIDESCENCE = material.iridescence > 0;
20686		const HAS_SHEEN = material.sheen > 0;
20687		const HAS_TRANSMISSION = material.transmission > 0;
20688
20689		const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap;
20690
20691		const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap;
20692		const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap;
20693		const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap;
20694
20695		const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap;
20696		const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap;
20697
20698		const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap;
20699		const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap;
20700
20701		const HAS_SPECULARMAP = !! material.specularMap;
20702		const HAS_SPECULAR_COLORMAP = !! material.specularColorMap;
20703		const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap;
20704
20705		const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap;
20706		const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap;
20707
20708		const HAS_GRADIENTMAP = !! material.gradientMap;
20709
20710		const HAS_ALPHAMAP = !! material.alphaMap;
20711
20712		const HAS_ALPHATEST = material.alphaTest > 0;
20713
20714		const HAS_ALPHAHASH = !! material.alphaHash;
20715
20716		const HAS_EXTENSIONS = !! material.extensions;
20717
20718		const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1;
20719		const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2;
20720		const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3;
20721
20722		let toneMapping = NoToneMapping;
20723
20724		if ( material.toneMapped ) {
20725
20726			if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {
20727
20728				toneMapping = renderer.toneMapping;
20729
20730			}
20731
20732		}
20733
20734		const parameters = {
20735
20736			isWebGL2: IS_WEBGL2,
20737
20738			shaderID: shaderID,
20739			shaderType: material.type,
20740			shaderName: material.name,
20741
20742			vertexShader: vertexShader,
20743			fragmentShader: fragmentShader,
20744			defines: material.defines,
20745
20746			customVertexShaderID: customVertexShaderID,
20747			customFragmentShaderID: customFragmentShaderID,
20748
20749			isRawShaderMaterial: material.isRawShaderMaterial === true,
20750			glslVersion: material.glslVersion,
20751
20752			precision: precision,
20753
20754			batching: IS_BATCHEDMESH,
20755			instancing: IS_INSTANCEDMESH,
20756			instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
20757
20758			supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,
20759			outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
20760
20761			map: HAS_MAP,
20762			matcap: HAS_MATCAP,
20763			envMap: HAS_ENVMAP,
20764			envMapMode: HAS_ENVMAP && envMap.mapping,
20765			envMapCubeUVHeight: envMapCubeUVHeight,
20766			aoMap: HAS_AOMAP,
20767			lightMap: HAS_LIGHTMAP,
20768			bumpMap: HAS_BUMPMAP,
20769			normalMap: HAS_NORMALMAP,
20770			displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,
20771			emissiveMap: HAS_EMISSIVEMAP,
20772
20773			normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap,
20774			normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap,
20775
20776			metalnessMap: HAS_METALNESSMAP,
20777			roughnessMap: HAS_ROUGHNESSMAP,
20778
20779			anisotropy: HAS_ANISOTROPY,
20780			anisotropyMap: HAS_ANISOTROPYMAP,
20781
20782			clearcoat: HAS_CLEARCOAT,
20783			clearcoatMap: HAS_CLEARCOATMAP,
20784			clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP,
20785			clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP,
20786
20787			iridescence: HAS_IRIDESCENCE,
20788			iridescenceMap: HAS_IRIDESCENCEMAP,
20789			iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,
20790
20791			sheen: HAS_SHEEN,
20792			sheenColorMap: HAS_SHEEN_COLORMAP,
20793			sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,
20794
20795			specularMap: HAS_SPECULARMAP,
20796			specularColorMap: HAS_SPECULAR_COLORMAP,
20797			specularIntensityMap: HAS_SPECULAR_INTENSITYMAP,
20798
20799			transmission: HAS_TRANSMISSION,
20800			transmissionMap: HAS_TRANSMISSIONMAP,
20801			thicknessMap: HAS_THICKNESSMAP,
20802
20803			gradientMap: HAS_GRADIENTMAP,
20804
20805			opaque: material.transparent === false && material.blending === NormalBlending,
20806
20807			alphaMap: HAS_ALPHAMAP,
20808			alphaTest: HAS_ALPHATEST,
20809			alphaHash: HAS_ALPHAHASH,
20810
20811			combine: material.combine,
20812
20813			//
20814
20815			mapUv: HAS_MAP && getChannel( material.map.channel ),
20816			aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ),
20817			lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ),
20818			bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ),
20819			normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ),
20820			displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ),
20821			emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ),
20822
20823			metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ),
20824			roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ),
20825
20826			anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ),
20827
20828			clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ),
20829			clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ),
20830			clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ),
20831
20832			iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ),
20833			iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ),
20834
20835			sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ),
20836			sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ),
20837
20838			specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ),
20839			specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ),
20840			specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ),
20841
20842			transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ),
20843			thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ),
20844
20845			alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ),
20846
20847			//
20848
20849			vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ),
20850			vertexColors: material.vertexColors,
20851			vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,
20852			vertexUv1s: HAS_ATTRIBUTE_UV1,
20853			vertexUv2s: HAS_ATTRIBUTE_UV2,
20854			vertexUv3s: HAS_ATTRIBUTE_UV3,
20855
20856			pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),
20857
20858			fog: !! fog,
20859			useFog: material.fog === true,
20860			fogExp2: ( fog && fog.isFogExp2 ),
20861
20862			flatShading: material.flatShading === true,
20863
20864			sizeAttenuation: material.sizeAttenuation === true,
20865			logarithmicDepthBuffer: logarithmicDepthBuffer,
20866
20867			skinning: object.isSkinnedMesh === true,
20868
20869			morphTargets: geometry.morphAttributes.position !== undefined,
20870			morphNormals: geometry.morphAttributes.normal !== undefined,
20871			morphColors: geometry.morphAttributes.color !== undefined,
20872			morphTargetsCount: morphTargetsCount,
20873			morphTextureStride: morphTextureStride,
20874
20875			numDirLights: lights.directional.length,
20876			numPointLights: lights.point.length,
20877			numSpotLights: lights.spot.length,
20878			numSpotLightMaps: lights.spotLightMap.length,
20879			numRectAreaLights: lights.rectArea.length,
20880			numHemiLights: lights.hemi.length,
20881
20882			numDirLightShadows: lights.directionalShadowMap.length,
20883			numPointLightShadows: lights.pointShadowMap.length,
20884			numSpotLightShadows: lights.spotShadowMap.length,
20885			numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,
20886
20887			numLightProbes: lights.numLightProbes,
20888
20889			numClippingPlanes: clipping.numPlanes,
20890			numClipIntersection: clipping.numIntersection,
20891
20892			dithering: material.dithering,
20893
20894			shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
20895			shadowMapType: renderer.shadowMap.type,
20896
20897			toneMapping: toneMapping,
20898			useLegacyLights: renderer._useLegacyLights,
20899
20900			decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),
20901
20902			premultipliedAlpha: material.premultipliedAlpha,
20903
20904			doubleSided: material.side === DoubleSide,
20905			flipSided: material.side === BackSide,
20906
20907			useDepthPacking: material.depthPacking >= 0,
20908			depthPacking: material.depthPacking || 0,
20909
20910			index0AttributeName: material.index0AttributeName,
20911
20912			extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true,
20913			extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true,
20914			extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true,
20915			extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true,
20916			extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ),
20917
20918			rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ),
20919			rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ),
20920			rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ),
20921			rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),
20922
20923			customProgramCacheKey: material.customProgramCacheKey()
20924
20925		};
20926
20927		return parameters;
20928
20929	}
20930
20931	function getProgramCacheKey( parameters ) {
20932
20933		const array = [];
20934
20935		if ( parameters.shaderID ) {
20936
20937			array.push( parameters.shaderID );
20938
20939		} else {
20940
20941			array.push( parameters.customVertexShaderID );
20942			array.push( parameters.customFragmentShaderID );
20943
20944		}
20945
20946		if ( parameters.defines !== undefined ) {
20947
20948			for ( const name in parameters.defines ) {
20949
20950				array.push( name );
20951				array.push( parameters.defines[ name ] );
20952
20953			}
20954
20955		}
20956
20957		if ( parameters.isRawShaderMaterial === false ) {
20958
20959			getProgramCacheKeyParameters( array, parameters );
20960			getProgramCacheKeyBooleans( array, parameters );
20961			array.push( renderer.outputColorSpace );
20962
20963		}
20964
20965		array.push( parameters.customProgramCacheKey );
20966
20967		return array.join();
20968
20969	}
20970
20971	function getProgramCacheKeyParameters( array, parameters ) {
20972
20973		array.push( parameters.precision );
20974		array.push( parameters.outputColorSpace );
20975		array.push( parameters.envMapMode );
20976		array.push( parameters.envMapCubeUVHeight );
20977		array.push( parameters.mapUv );
20978		array.push( parameters.alphaMapUv );
20979		array.push( parameters.lightMapUv );
20980		array.push( parameters.aoMapUv );
20981		array.push( parameters.bumpMapUv );
20982		array.push( parameters.normalMapUv );
20983		array.push( parameters.displacementMapUv );
20984		array.push( parameters.emissiveMapUv );
20985		array.push( parameters.metalnessMapUv );
20986		array.push( parameters.roughnessMapUv );
20987		array.push( parameters.anisotropyMapUv );
20988		array.push( parameters.clearcoatMapUv );
20989		array.push( parameters.clearcoatNormalMapUv );
20990		array.push( parameters.clearcoatRoughnessMapUv );
20991		array.push( parameters.iridescenceMapUv );
20992		array.push( parameters.iridescenceThicknessMapUv );
20993		array.push( parameters.sheenColorMapUv );
20994		array.push( parameters.sheenRoughnessMapUv );
20995		array.push( parameters.specularMapUv );
20996		array.push( parameters.specularColorMapUv );
20997		array.push( parameters.specularIntensityMapUv );
20998		array.push( parameters.transmissionMapUv );
20999		array.push( parameters.thicknessMapUv );
21000		array.push( parameters.combine );
21001		array.push( parameters.fogExp2 );
21002		array.push( parameters.sizeAttenuation );
21003		array.push( parameters.morphTargetsCount );
21004		array.push( parameters.morphAttributeCount );
21005		array.push( parameters.numDirLights );
21006		array.push( parameters.numPointLights );
21007		array.push( parameters.numSpotLights );
21008		array.push( parameters.numSpotLightMaps );
21009		array.push( parameters.numHemiLights );
21010		array.push( parameters.numRectAreaLights );
21011		array.push( parameters.numDirLightShadows );
21012		array.push( parameters.numPointLightShadows );
21013		array.push( parameters.numSpotLightShadows );
21014		array.push( parameters.numSpotLightShadowsWithMaps );
21015		array.push( parameters.numLightProbes );
21016		array.push( parameters.shadowMapType );
21017		array.push( parameters.toneMapping );
21018		array.push( parameters.numClippingPlanes );
21019		array.push( parameters.numClipIntersection );
21020		array.push( parameters.depthPacking );
21021
21022	}
21023
21024	function getProgramCacheKeyBooleans( array, parameters ) {
21025
21026		_programLayers.disableAll();
21027
21028		if ( parameters.isWebGL2 )
21029			_programLayers.enable( 0 );
21030		if ( parameters.supportsVertexTextures )
21031			_programLayers.enable( 1 );
21032		if ( parameters.instancing )
21033			_programLayers.enable( 2 );
21034		if ( parameters.instancingColor )
21035			_programLayers.enable( 3 );
21036		if ( parameters.matcap )
21037			_programLayers.enable( 4 );
21038		if ( parameters.envMap )
21039			_programLayers.enable( 5 );
21040		if ( parameters.normalMapObjectSpace )
21041			_programLayers.enable( 6 );
21042		if ( parameters.normalMapTangentSpace )
21043			_programLayers.enable( 7 );
21044		if ( parameters.clearcoat )
21045			_programLayers.enable( 8 );
21046		if ( parameters.iridescence )
21047			_programLayers.enable( 9 );
21048		if ( parameters.alphaTest )
21049			_programLayers.enable( 10 );
21050		if ( parameters.vertexColors )
21051			_programLayers.enable( 11 );
21052		if ( parameters.vertexAlphas )
21053			_programLayers.enable( 12 );
21054		if ( parameters.vertexUv1s )
21055			_programLayers.enable( 13 );
21056		if ( parameters.vertexUv2s )
21057			_programLayers.enable( 14 );
21058		if ( parameters.vertexUv3s )
21059			_programLayers.enable( 15 );
21060		if ( parameters.vertexTangents )
21061			_programLayers.enable( 16 );
21062		if ( parameters.anisotropy )
21063			_programLayers.enable( 17 );
21064		if ( parameters.alphaHash )
21065			_programLayers.enable( 18 );
21066		if ( parameters.batching )
21067			_programLayers.enable( 19 );
21068
21069		array.push( _programLayers.mask );
21070		_programLayers.disableAll();
21071
21072		if ( parameters.fog )
21073			_programLayers.enable( 0 );
21074		if ( parameters.useFog )
21075			_programLayers.enable( 1 );
21076		if ( parameters.flatShading )
21077			_programLayers.enable( 2 );
21078		if ( parameters.logarithmicDepthBuffer )
21079			_programLayers.enable( 3 );
21080		if ( parameters.skinning )
21081			_programLayers.enable( 4 );
21082		if ( parameters.morphTargets )
21083			_programLayers.enable( 5 );
21084		if ( parameters.morphNormals )
21085			_programLayers.enable( 6 );
21086		if ( parameters.morphColors )
21087			_programLayers.enable( 7 );
21088		if ( parameters.premultipliedAlpha )
21089			_programLayers.enable( 8 );
21090		if ( parameters.shadowMapEnabled )
21091			_programLayers.enable( 9 );
21092		if ( parameters.useLegacyLights )
21093			_programLayers.enable( 10 );
21094		if ( parameters.doubleSided )
21095			_programLayers.enable( 11 );
21096		if ( parameters.flipSided )
21097			_programLayers.enable( 12 );
21098		if ( parameters.useDepthPacking )
21099			_programLayers.enable( 13 );
21100		if ( parameters.dithering )
21101			_programLayers.enable( 14 );
21102		if ( parameters.transmission )
21103			_programLayers.enable( 15 );
21104		if ( parameters.sheen )
21105			_programLayers.enable( 16 );
21106		if ( parameters.opaque )
21107			_programLayers.enable( 17 );
21108		if ( parameters.pointsUvs )
21109			_programLayers.enable( 18 );
21110		if ( parameters.decodeVideoTexture )
21111			_programLayers.enable( 19 );
21112
21113		array.push( _programLayers.mask );
21114
21115	}
21116
21117	function getUniforms( material ) {
21118
21119		const shaderID = shaderIDs[ material.type ];
21120		let uniforms;
21121
21122		if ( shaderID ) {
21123
21124			const shader = ShaderLib[ shaderID ];
21125			uniforms = UniformsUtils.clone( shader.uniforms );
21126
21127		} else {
21128
21129			uniforms = material.uniforms;
21130
21131		}
21132
21133		return uniforms;
21134
21135	}
21136
21137	function acquireProgram( parameters, cacheKey ) {
21138
21139		let program;
21140
21141		// Check if code has been already compiled
21142		for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
21143
21144			const preexistingProgram = programs[ p ];
21145
21146			if ( preexistingProgram.cacheKey === cacheKey ) {
21147
21148				program = preexistingProgram;
21149				++ program.usedTimes;
21150
21151				break;
21152
21153			}
21154
21155		}
21156
21157		if ( program === undefined ) {
21158
21159			program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
21160			programs.push( program );
21161
21162		}
21163
21164		return program;
21165
21166	}
21167
21168	function releaseProgram( program ) {
21169
21170		if ( -- program.usedTimes === 0 ) {
21171
21172			// Remove from unordered set
21173			const i = programs.indexOf( program );
21174			programs[ i ] = programs[ programs.length - 1 ];
21175			programs.pop();
21176
21177			// Free WebGL resources
21178			program.destroy();
21179
21180		}
21181
21182	}
21183
21184	function releaseShaderCache( material ) {
21185
21186		_customShaders.remove( material );
21187
21188	}
21189
21190	function dispose() {
21191
21192		_customShaders.dispose();
21193
21194	}
21195
21196	return {
21197		getParameters: getParameters,
21198		getProgramCacheKey: getProgramCacheKey,
21199		getUniforms: getUniforms,
21200		acquireProgram: acquireProgram,
21201		releaseProgram: releaseProgram,
21202		releaseShaderCache: releaseShaderCache,
21203		// Exposed for resource monitoring & error feedback via renderer.info:
21204		programs: programs,
21205		dispose: dispose
21206	};
21207
21208}
21209
21210function WebGLProperties() {
21211
21212	let properties = new WeakMap();
21213
21214	function get( object ) {
21215
21216		let map = properties.get( object );
21217
21218		if ( map === undefined ) {
21219
21220			map = {};
21221			properties.set( object, map );
21222
21223		}
21224
21225		return map;
21226
21227	}
21228
21229	function remove( object ) {
21230
21231		properties.delete( object );
21232
21233	}
21234
21235	function update( object, key, value ) {
21236
21237		properties.get( object )[ key ] = value;
21238
21239	}
21240
21241	function dispose() {
21242
21243		properties = new WeakMap();
21244
21245	}
21246
21247	return {
21248		get: get,
21249		remove: remove,
21250		update: update,
21251		dispose: dispose
21252	};
21253
21254}
21255
21256function painterSortStable( a, b ) {
21257
21258	if ( a.groupOrder !== b.groupOrder ) {
21259
21260		return a.groupOrder - b.groupOrder;
21261
21262	} else if ( a.renderOrder !== b.renderOrder ) {
21263
21264		return a.renderOrder - b.renderOrder;
21265
21266	} else if ( a.material.id !== b.material.id ) {
21267
21268		return a.material.id - b.material.id;
21269
21270	} else if ( a.z !== b.z ) {
21271
21272		return a.z - b.z;
21273
21274	} else {
21275
21276		return a.id - b.id;
21277
21278	}
21279
21280}
21281
21282function reversePainterSortStable( a, b ) {
21283
21284	if ( a.groupOrder !== b.groupOrder ) {
21285
21286		return a.groupOrder - b.groupOrder;
21287
21288	} else if ( a.renderOrder !== b.renderOrder ) {
21289
21290		return a.renderOrder - b.renderOrder;
21291
21292	} else if ( a.z !== b.z ) {
21293
21294		return b.z - a.z;
21295
21296	} else {
21297
21298		return a.id - b.id;
21299
21300	}
21301
21302}
21303
21304
21305function WebGLRenderList() {
21306
21307	const renderItems = [];
21308	let renderItemsIndex = 0;
21309
21310	const opaque = [];
21311	const transmissive = [];
21312	const transparent = [];
21313
21314	function init() {
21315
21316		renderItemsIndex = 0;
21317
21318		opaque.length = 0;
21319		transmissive.length = 0;
21320		transparent.length = 0;
21321
21322	}
21323
21324	function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
21325
21326		let renderItem = renderItems[ renderItemsIndex ];
21327
21328		if ( renderItem === undefined ) {
21329
21330			renderItem = {
21331				id: object.id,
21332				object: object,
21333				geometry: geometry,
21334				material: material,
21335				groupOrder: groupOrder,
21336				renderOrder: object.renderOrder,
21337				z: z,
21338				group: group
21339			};
21340
21341			renderItems[ renderItemsIndex ] = renderItem;
21342
21343		} else {
21344
21345			renderItem.id = object.id;
21346			renderItem.object = object;
21347			renderItem.geometry = geometry;
21348			renderItem.material = material;
21349			renderItem.groupOrder = groupOrder;
21350			renderItem.renderOrder = object.renderOrder;
21351			renderItem.z = z;
21352			renderItem.group = group;
21353
21354		}
21355
21356		renderItemsIndex ++;
21357
21358		return renderItem;
21359
21360	}
21361
21362	function push( object, geometry, material, groupOrder, z, group ) {
21363
21364		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21365
21366		if ( material.transmission > 0.0 ) {
21367
21368			transmissive.push( renderItem );
21369
21370		} else if ( material.transparent === true ) {
21371
21372			transparent.push( renderItem );
21373
21374		} else {
21375
21376			opaque.push( renderItem );
21377
21378		}
21379
21380	}
21381
21382	function unshift( object, geometry, material, groupOrder, z, group ) {
21383
21384		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21385
21386		if ( material.transmission > 0.0 ) {
21387
21388			transmissive.unshift( renderItem );
21389
21390		} else if ( material.transparent === true ) {
21391
21392			transparent.unshift( renderItem );
21393
21394		} else {
21395
21396			opaque.unshift( renderItem );
21397
21398		}
21399
21400	}
21401
21402	function sort( customOpaqueSort, customTransparentSort ) {
21403
21404		if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
21405		if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
21406		if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
21407
21408	}
21409
21410	function finish() {
21411
21412		// Clear references from inactive renderItems in the list
21413
21414		for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
21415
21416			const renderItem = renderItems[ i ];
21417
21418			if ( renderItem.id === null ) break;
21419
21420			renderItem.id = null;
21421			renderItem.object = null;
21422			renderItem.geometry = null;
21423			renderItem.material = null;
21424			renderItem.group = null;
21425
21426		}
21427
21428	}
21429
21430	return {
21431
21432		opaque: opaque,
21433		transmissive: transmissive,
21434		transparent: transparent,
21435
21436		init: init,
21437		push: push,
21438		unshift: unshift,
21439		finish: finish,
21440
21441		sort: sort
21442	};
21443
21444}
21445
21446function WebGLRenderLists() {
21447
21448	let lists = new WeakMap();
21449
21450	function get( scene, renderCallDepth ) {
21451
21452		const listArray = lists.get( scene );
21453		let list;
21454
21455		if ( listArray === undefined ) {
21456
21457			list = new WebGLRenderList();
21458			lists.set( scene, [ list ] );
21459
21460		} else {
21461
21462			if ( renderCallDepth >= listArray.length ) {
21463
21464				list = new WebGLRenderList();
21465				listArray.push( list );
21466
21467			} else {
21468
21469				list = listArray[ renderCallDepth ];
21470
21471			}
21472
21473		}
21474
21475		return list;
21476
21477	}
21478
21479	function dispose() {
21480
21481		lists = new WeakMap();
21482
21483	}
21484
21485	return {
21486		get: get,
21487		dispose: dispose
21488	};
21489
21490}
21491
21492function UniformsCache() {
21493
21494	const lights = {};
21495
21496	return {
21497
21498		get: function ( light ) {
21499
21500			if ( lights[ light.id ] !== undefined ) {
21501
21502				return lights[ light.id ];
21503
21504			}
21505
21506			let uniforms;
21507
21508			switch ( light.type ) {
21509
21510				case 'DirectionalLight':
21511					uniforms = {
21512						direction: new Vector3(),
21513						color: new Color()
21514					};
21515					break;
21516
21517				case 'SpotLight':
21518					uniforms = {
21519						position: new Vector3(),
21520						direction: new Vector3(),
21521						color: new Color(),
21522						distance: 0,
21523						coneCos: 0,
21524						penumbraCos: 0,
21525						decay: 0
21526					};
21527					break;
21528
21529				case 'PointLight':
21530					uniforms = {
21531						position: new Vector3(),
21532						color: new Color(),
21533						distance: 0,
21534						decay: 0
21535					};
21536					break;
21537
21538				case 'HemisphereLight':
21539					uniforms = {
21540						direction: new Vector3(),
21541						skyColor: new Color(),
21542						groundColor: new Color()
21543					};
21544					break;
21545
21546				case 'RectAreaLight':
21547					uniforms = {
21548						color: new Color(),
21549						position: new Vector3(),
21550						halfWidth: new Vector3(),
21551						halfHeight: new Vector3()
21552					};
21553					break;
21554
21555			}
21556
21557			lights[ light.id ] = uniforms;
21558
21559			return uniforms;
21560
21561		}
21562
21563	};
21564
21565}
21566
21567function ShadowUniformsCache() {
21568
21569	const lights = {};
21570
21571	return {
21572
21573		get: function ( light ) {
21574
21575			if ( lights[ light.id ] !== undefined ) {
21576
21577				return lights[ light.id ];
21578
21579			}
21580
21581			let uniforms;
21582
21583			switch ( light.type ) {
21584
21585				case 'DirectionalLight':
21586					uniforms = {
21587						shadowBias: 0,
21588						shadowNormalBias: 0,
21589						shadowRadius: 1,
21590						shadowMapSize: new Vector2()
21591					};
21592					break;
21593
21594				case 'SpotLight':
21595					uniforms = {
21596						shadowBias: 0,
21597						shadowNormalBias: 0,
21598						shadowRadius: 1,
21599						shadowMapSize: new Vector2()
21600					};
21601					break;
21602
21603				case 'PointLight':
21604					uniforms = {
21605						shadowBias: 0,
21606						shadowNormalBias: 0,
21607						shadowRadius: 1,
21608						shadowMapSize: new Vector2(),
21609						shadowCameraNear: 1,
21610						shadowCameraFar: 1000
21611					};
21612					break;
21613
21614				// TODO (abelnation): set RectAreaLight shadow uniforms
21615
21616			}
21617
21618			lights[ light.id ] = uniforms;
21619
21620			return uniforms;
21621
21622		}
21623
21624	};
21625
21626}
21627
21628
21629
21630let nextVersion = 0;
21631
21632function shadowCastingAndTexturingLightsFirst( lightA, lightB ) {
21633
21634	return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );
21635
21636}
21637
21638function WebGLLights( extensions, capabilities ) {
21639
21640	const cache = new UniformsCache();
21641
21642	const shadowCache = ShadowUniformsCache();
21643
21644	const state = {
21645
21646		version: 0,
21647
21648		hash: {
21649			directionalLength: - 1,
21650			pointLength: - 1,
21651			spotLength: - 1,
21652			rectAreaLength: - 1,
21653			hemiLength: - 1,
21654
21655			numDirectionalShadows: - 1,
21656			numPointShadows: - 1,
21657			numSpotShadows: - 1,
21658			numSpotMaps: - 1,
21659
21660			numLightProbes: - 1
21661		},
21662
21663		ambient: [ 0, 0, 0 ],
21664		probe: [],
21665		directional: [],
21666		directionalShadow: [],
21667		directionalShadowMap: [],
21668		directionalShadowMatrix: [],
21669		spot: [],
21670		spotLightMap: [],
21671		spotShadow: [],
21672		spotShadowMap: [],
21673		spotLightMatrix: [],
21674		rectArea: [],
21675		rectAreaLTC1: null,
21676		rectAreaLTC2: null,
21677		point: [],
21678		pointShadow: [],
21679		pointShadowMap: [],
21680		pointShadowMatrix: [],
21681		hemi: [],
21682		numSpotLightShadowsWithMaps: 0,
21683		numLightProbes: 0
21684
21685	};
21686
21687	for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
21688
21689	const vector3 = new Vector3();
21690	const matrix4 = new Matrix4();
21691	const matrix42 = new Matrix4();
21692
21693	function setup( lights, useLegacyLights ) {
21694
21695		let r = 0, g = 0, b = 0;
21696
21697		for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
21698
21699		let directionalLength = 0;
21700		let pointLength = 0;
21701		let spotLength = 0;
21702		let rectAreaLength = 0;
21703		let hemiLength = 0;
21704
21705		let numDirectionalShadows = 0;
21706		let numPointShadows = 0;
21707		let numSpotShadows = 0;
21708		let numSpotMaps = 0;
21709		let numSpotShadowsWithMaps = 0;
21710
21711		let numLightProbes = 0;
21712
21713		// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
21714		lights.sort( shadowCastingAndTexturingLightsFirst );
21715
21716		// artist-friendly light intensity scaling factor
21717		const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1;
21718
21719		for ( let i = 0, l = lights.length; i < l; i ++ ) {
21720
21721			const light = lights[ i ];
21722
21723			const color = light.color;
21724			const intensity = light.intensity;
21725			const distance = light.distance;
21726
21727			const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
21728
21729			if ( light.isAmbientLight ) {
21730
21731				r += color.r * intensity * scaleFactor;
21732				g += color.g * intensity * scaleFactor;
21733				b += color.b * intensity * scaleFactor;
21734
21735			} else if ( light.isLightProbe ) {
21736
21737				for ( let j = 0; j < 9; j ++ ) {
21738
21739					state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
21740
21741				}
21742
21743				numLightProbes ++;
21744
21745			} else if ( light.isDirectionalLight ) {
21746
21747				const uniforms = cache.get( light );
21748
21749				uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21750
21751				if ( light.castShadow ) {
21752
21753					const shadow = light.shadow;
21754
21755					const shadowUniforms = shadowCache.get( light );
21756
21757					shadowUniforms.shadowBias = shadow.bias;
21758					shadowUniforms.shadowNormalBias = shadow.normalBias;
21759					shadowUniforms.shadowRadius = shadow.radius;
21760					shadowUniforms.shadowMapSize = shadow.mapSize;
21761
21762					state.directionalShadow[ directionalLength ] = shadowUniforms;
21763					state.directionalShadowMap[ directionalLength ] = shadowMap;
21764					state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
21765
21766					numDirectionalShadows ++;
21767
21768				}
21769
21770				state.directional[ directionalLength ] = uniforms;
21771
21772				directionalLength ++;
21773
21774			} else if ( light.isSpotLight ) {
21775
21776				const uniforms = cache.get( light );
21777
21778				uniforms.position.setFromMatrixPosition( light.matrixWorld );
21779
21780				uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor );
21781				uniforms.distance = distance;
21782
21783				uniforms.coneCos = Math.cos( light.angle );
21784				uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
21785				uniforms.decay = light.decay;
21786
21787				state.spot[ spotLength ] = uniforms;
21788
21789				const shadow = light.shadow;
21790
21791				if ( light.map ) {
21792
21793					state.spotLightMap[ numSpotMaps ] = light.map;
21794					numSpotMaps ++;
21795
21796					// make sure the lightMatrix is up to date
21797					// TODO : do it if required only
21798					shadow.updateMatrices( light );
21799
21800					if ( light.castShadow ) numSpotShadowsWithMaps ++;
21801
21802				}
21803
21804				state.spotLightMatrix[ spotLength ] = shadow.matrix;
21805
21806				if ( light.castShadow ) {
21807
21808					const shadowUniforms = shadowCache.get( light );
21809
21810					shadowUniforms.shadowBias = shadow.bias;
21811					shadowUniforms.shadowNormalBias = shadow.normalBias;
21812					shadowUniforms.shadowRadius = shadow.radius;
21813					shadowUniforms.shadowMapSize = shadow.mapSize;
21814
21815					state.spotShadow[ spotLength ] = shadowUniforms;
21816					state.spotShadowMap[ spotLength ] = shadowMap;
21817
21818					numSpotShadows ++;
21819
21820				}
21821
21822				spotLength ++;
21823
21824			} else if ( light.isRectAreaLight ) {
21825
21826				const uniforms = cache.get( light );
21827
21828				uniforms.color.copy( color ).multiplyScalar( intensity );
21829
21830				uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
21831				uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
21832
21833				state.rectArea[ rectAreaLength ] = uniforms;
21834
21835				rectAreaLength ++;
21836
21837			} else if ( light.isPointLight ) {
21838
21839				const uniforms = cache.get( light );
21840
21841				uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21842				uniforms.distance = light.distance;
21843				uniforms.decay = light.decay;
21844
21845				if ( light.castShadow ) {
21846
21847					const shadow = light.shadow;
21848
21849					const shadowUniforms = shadowCache.get( light );
21850
21851					shadowUniforms.shadowBias = shadow.bias;
21852					shadowUniforms.shadowNormalBias = shadow.normalBias;
21853					shadowUniforms.shadowRadius = shadow.radius;
21854					shadowUniforms.shadowMapSize = shadow.mapSize;
21855					shadowUniforms.shadowCameraNear = shadow.camera.near;
21856					shadowUniforms.shadowCameraFar = shadow.camera.far;
21857
21858					state.pointShadow[ pointLength ] = shadowUniforms;
21859					state.pointShadowMap[ pointLength ] = shadowMap;
21860					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
21861
21862					numPointShadows ++;
21863
21864				}
21865
21866				state.point[ pointLength ] = uniforms;
21867
21868				pointLength ++;
21869
21870			} else if ( light.isHemisphereLight ) {
21871
21872				const uniforms = cache.get( light );
21873
21874				uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor );
21875				uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor );
21876
21877				state.hemi[ hemiLength ] = uniforms;
21878
21879				hemiLength ++;
21880
21881			}
21882
21883		}
21884
21885		if ( rectAreaLength > 0 ) {
21886
21887			if ( capabilities.isWebGL2 ) {
21888
21889				// WebGL 2
21890
21891				if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21892
21893					state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21894					state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21895
21896				} else {
21897
21898					state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21899					state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21900
21901				}
21902
21903			} else {
21904
21905				// WebGL 1
21906
21907				if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21908
21909					state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21910					state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21911
21912				} else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
21913
21914					state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21915					state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21916
21917				} else {
21918
21919					console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
21920
21921				}
21922
21923			}
21924
21925		}
21926
21927		state.ambient[ 0 ] = r;
21928		state.ambient[ 1 ] = g;
21929		state.ambient[ 2 ] = b;
21930
21931		const hash = state.hash;
21932
21933		if ( hash.directionalLength !== directionalLength ||
21934			hash.pointLength !== pointLength ||
21935			hash.spotLength !== spotLength ||
21936			hash.rectAreaLength !== rectAreaLength ||
21937			hash.hemiLength !== hemiLength ||
21938			hash.numDirectionalShadows !== numDirectionalShadows ||
21939			hash.numPointShadows !== numPointShadows ||
21940			hash.numSpotShadows !== numSpotShadows ||
21941			hash.numSpotMaps !== numSpotMaps ||
21942			hash.numLightProbes !== numLightProbes ) {
21943
21944			state.directional.length = directionalLength;
21945			state.spot.length = spotLength;
21946			state.rectArea.length = rectAreaLength;
21947			state.point.length = pointLength;
21948			state.hemi.length = hemiLength;
21949
21950			state.directionalShadow.length = numDirectionalShadows;
21951			state.directionalShadowMap.length = numDirectionalShadows;
21952			state.pointShadow.length = numPointShadows;
21953			state.pointShadowMap.length = numPointShadows;
21954			state.spotShadow.length = numSpotShadows;
21955			state.spotShadowMap.length = numSpotShadows;
21956			state.directionalShadowMatrix.length = numDirectionalShadows;
21957			state.pointShadowMatrix.length = numPointShadows;
21958			state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
21959			state.spotLightMap.length = numSpotMaps;
21960			state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
21961			state.numLightProbes = numLightProbes;
21962
21963			hash.directionalLength = directionalLength;
21964			hash.pointLength = pointLength;
21965			hash.spotLength = spotLength;
21966			hash.rectAreaLength = rectAreaLength;
21967			hash.hemiLength = hemiLength;
21968
21969			hash.numDirectionalShadows = numDirectionalShadows;
21970			hash.numPointShadows = numPointShadows;
21971			hash.numSpotShadows = numSpotShadows;
21972			hash.numSpotMaps = numSpotMaps;
21973
21974			hash.numLightProbes = numLightProbes;
21975
21976			state.version = nextVersion ++;
21977
21978		}
21979
21980	}
21981
21982	function setupView( lights, camera ) {
21983
21984		let directionalLength = 0;
21985		let pointLength = 0;
21986		let spotLength = 0;
21987		let rectAreaLength = 0;
21988		let hemiLength = 0;
21989
21990		const viewMatrix = camera.matrixWorldInverse;
21991
21992		for ( let i = 0, l = lights.length; i < l; i ++ ) {
21993
21994			const light = lights[ i ];
21995
21996			if ( light.isDirectionalLight ) {
21997
21998				const uniforms = state.directional[ directionalLength ];
21999
22000				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22001				vector3.setFromMatrixPosition( light.target.matrixWorld );
22002				uniforms.direction.sub( vector3 );
22003				uniforms.direction.transformDirection( viewMatrix );
22004
22005				directionalLength ++;
22006
22007			} else if ( light.isSpotLight ) {
22008
22009				const uniforms = state.spot[ spotLength ];
22010
22011				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22012				uniforms.position.applyMatrix4( viewMatrix );
22013
22014				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22015				vector3.setFromMatrixPosition( light.target.matrixWorld );
22016				uniforms.direction.sub( vector3 );
22017				uniforms.direction.transformDirection( viewMatrix );
22018
22019				spotLength ++;
22020
22021			} else if ( light.isRectAreaLight ) {
22022
22023				const uniforms = state.rectArea[ rectAreaLength ];
22024
22025				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22026				uniforms.position.applyMatrix4( viewMatrix );
22027
22028				// extract local rotation of light to derive width/height half vectors
22029				matrix42.identity();
22030				matrix4.copy( light.matrixWorld );
22031				matrix4.premultiply( viewMatrix );
22032				matrix42.extractRotation( matrix4 );
22033
22034				uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22035				uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22036
22037				uniforms.halfWidth.applyMatrix4( matrix42 );
22038				uniforms.halfHeight.applyMatrix4( matrix42 );
22039
22040				rectAreaLength ++;
22041
22042			} else if ( light.isPointLight ) {
22043
22044				const uniforms = state.point[ pointLength ];
22045
22046				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22047				uniforms.position.applyMatrix4( viewMatrix );
22048
22049				pointLength ++;
22050
22051			} else if ( light.isHemisphereLight ) {
22052
22053				const uniforms = state.hemi[ hemiLength ];
22054
22055				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22056				uniforms.direction.transformDirection( viewMatrix );
22057
22058				hemiLength ++;
22059
22060			}
22061
22062		}
22063
22064	}
22065
22066	return {
22067		setup: setup,
22068		setupView: setupView,
22069		state: state
22070	};
22071
22072}
22073
22074function WebGLRenderState( extensions, capabilities ) {
22075
22076	const lights = new WebGLLights( extensions, capabilities );
22077
22078	const lightsArray = [];
22079	const shadowsArray = [];
22080
22081	function init() {
22082
22083		lightsArray.length = 0;
22084		shadowsArray.length = 0;
22085
22086	}
22087
22088	function pushLight( light ) {
22089
22090		lightsArray.push( light );
22091
22092	}
22093
22094	function pushShadow( shadowLight ) {
22095
22096		shadowsArray.push( shadowLight );
22097
22098	}
22099
22100	function setupLights( useLegacyLights ) {
22101
22102		lights.setup( lightsArray, useLegacyLights );
22103
22104	}
22105
22106	function setupLightsView( camera ) {
22107
22108		lights.setupView( lightsArray, camera );
22109
22110	}
22111
22112	const state = {
22113		lightsArray: lightsArray,
22114		shadowsArray: shadowsArray,
22115
22116		lights: lights
22117	};
22118
22119	return {
22120		init: init,
22121		state: state,
22122		setupLights: setupLights,
22123		setupLightsView: setupLightsView,
22124
22125		pushLight: pushLight,
22126		pushShadow: pushShadow
22127	};
22128
22129}
22130
22131function WebGLRenderStates( extensions, capabilities ) {
22132
22133	let renderStates = new WeakMap();
22134
22135	function get( scene, renderCallDepth = 0 ) {
22136
22137		const renderStateArray = renderStates.get( scene );
22138		let renderState;
22139
22140		if ( renderStateArray === undefined ) {
22141
22142			renderState = new WebGLRenderState( extensions, capabilities );
22143			renderStates.set( scene, [ renderState ] );
22144
22145		} else {
22146
22147			if ( renderCallDepth >= renderStateArray.length ) {
22148
22149				renderState = new WebGLRenderState( extensions, capabilities );
22150				renderStateArray.push( renderState );
22151
22152			} else {
22153
22154				renderState = renderStateArray[ renderCallDepth ];
22155
22156			}
22157
22158		}
22159
22160		return renderState;
22161
22162	}
22163
22164	function dispose() {
22165
22166		renderStates = new WeakMap();
22167
22168	}
22169
22170	return {
22171		get: get,
22172		dispose: dispose
22173	};
22174
22175}
22176
22177class MeshDepthMaterial extends Material {
22178
22179	constructor( parameters ) {
22180
22181		super();
22182
22183		this.isMeshDepthMaterial = true;
22184
22185		this.type = 'MeshDepthMaterial';
22186
22187		this.depthPacking = BasicDepthPacking;
22188
22189		this.map = null;
22190
22191		this.alphaMap = null;
22192
22193		this.displacementMap = null;
22194		this.displacementScale = 1;
22195		this.displacementBias = 0;
22196
22197		this.wireframe = false;
22198		this.wireframeLinewidth = 1;
22199
22200		this.setValues( parameters );
22201
22202	}
22203
22204	copy( source ) {
22205
22206		super.copy( source );
22207
22208		this.depthPacking = source.depthPacking;
22209
22210		this.map = source.map;
22211
22212		this.alphaMap = source.alphaMap;
22213
22214		this.displacementMap = source.displacementMap;
22215		this.displacementScale = source.displacementScale;
22216		this.displacementBias = source.displacementBias;
22217
22218		this.wireframe = source.wireframe;
22219		this.wireframeLinewidth = source.wireframeLinewidth;
22220
22221		return this;
22222
22223	}
22224
22225}
22226
22227class MeshDistanceMaterial extends Material {
22228
22229	constructor( parameters ) {
22230
22231		super();
22232
22233		this.isMeshDistanceMaterial = true;
22234
22235		this.type = 'MeshDistanceMaterial';
22236
22237		this.map = null;
22238
22239		this.alphaMap = null;
22240
22241		this.displacementMap = null;
22242		this.displacementScale = 1;
22243		this.displacementBias = 0;
22244
22245		this.setValues( parameters );
22246
22247	}
22248
22249	copy( source ) {
22250
22251		super.copy( source );
22252
22253		this.map = source.map;
22254
22255		this.alphaMap = source.alphaMap;
22256
22257		this.displacementMap = source.displacementMap;
22258		this.displacementScale = source.displacementScale;
22259		this.displacementBias = source.displacementBias;
22260
22261		return this;
22262
22263	}
22264
22265}
22266
22267const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
22268
22269const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
22270
22271function WebGLShadowMap( _renderer, _objects, _capabilities ) {
22272
22273	let _frustum = new Frustum();
22274
22275	const _shadowMapSize = new Vector2(),
22276		_viewportSize = new Vector2(),
22277
22278		_viewport = new Vector4(),
22279
22280		_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
22281		_distanceMaterial = new MeshDistanceMaterial(),
22282
22283		_materialCache = {},
22284
22285		_maxTextureSize = _capabilities.maxTextureSize;
22286
22287	const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide };
22288
22289	const shadowMaterialVertical = new ShaderMaterial( {
22290		defines: {
22291			VSM_SAMPLES: 8
22292		},
22293		uniforms: {
22294			shadow_pass: { value: null },
22295			resolution: { value: new Vector2() },
22296			radius: { value: 4.0 }
22297		},
22298
22299		vertexShader: vertex,
22300		fragmentShader: fragment
22301
22302	} );
22303
22304	const shadowMaterialHorizontal = shadowMaterialVertical.clone();
22305	shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
22306
22307	const fullScreenTri = new BufferGeometry();
22308	fullScreenTri.setAttribute(
22309		'position',
22310		new BufferAttribute(
22311			new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
22312			3
22313		)
22314	);
22315
22316	const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
22317
22318	const scope = this;
22319
22320	this.enabled = false;
22321
22322	this.autoUpdate = true;
22323	this.needsUpdate = false;
22324
22325	this.type = PCFShadowMap;
22326	let _previousType = this.type;
22327
22328	this.render = function ( lights, scene, camera ) {
22329
22330		if ( scope.enabled === false ) return;
22331		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
22332
22333		if ( lights.length === 0 ) return;
22334
22335		const currentRenderTarget = _renderer.getRenderTarget();
22336		const activeCubeFace = _renderer.getActiveCubeFace();
22337		const activeMipmapLevel = _renderer.getActiveMipmapLevel();
22338
22339		const _state = _renderer.state;
22340
22341		// Set GL state for depth map.
22342		_state.setBlending( NoBlending );
22343		_state.buffers.color.setClear( 1, 1, 1, 1 );
22344		_state.buffers.depth.setTest( true );
22345		_state.setScissorTest( false );
22346
22347		// check for shadow map type changes
22348
22349		const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap );
22350		const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap );
22351
22352		// render depth map
22353
22354		for ( let i = 0, il = lights.length; i < il; i ++ ) {
22355
22356			const light = lights[ i ];
22357			const shadow = light.shadow;
22358
22359			if ( shadow === undefined ) {
22360
22361				console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
22362				continue;
22363
22364			}
22365
22366			if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
22367
22368			_shadowMapSize.copy( shadow.mapSize );
22369
22370			const shadowFrameExtents = shadow.getFrameExtents();
22371
22372			_shadowMapSize.multiply( shadowFrameExtents );
22373
22374			_viewportSize.copy( shadow.mapSize );
22375
22376			if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {
22377
22378				if ( _shadowMapSize.x > _maxTextureSize ) {
22379
22380					_viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );
22381					_shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
22382					shadow.mapSize.x = _viewportSize.x;
22383
22384				}
22385
22386				if ( _shadowMapSize.y > _maxTextureSize ) {
22387
22388					_viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );
22389					_shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
22390					shadow.mapSize.y = _viewportSize.y;
22391
22392				}
22393
22394			}
22395
22396			if ( shadow.map === null || toVSM === true || fromVSM === true ) {
22397
22398				const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {};
22399
22400				if ( shadow.map !== null ) {
22401
22402					shadow.map.dispose();
22403
22404				}
22405
22406				shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
22407				shadow.map.texture.name = light.name + '.shadowMap';
22408
22409				shadow.camera.updateProjectionMatrix();
22410
22411			}
22412
22413			_renderer.setRenderTarget( shadow.map );
22414			_renderer.clear();
22415
22416			const viewportCount = shadow.getViewportCount();
22417
22418			for ( let vp = 0; vp < viewportCount; vp ++ ) {
22419
22420				const viewport = shadow.getViewport( vp );
22421
22422				_viewport.set(
22423					_viewportSize.x * viewport.x,
22424					_viewportSize.y * viewport.y,
22425					_viewportSize.x * viewport.z,
22426					_viewportSize.y * viewport.w
22427				);
22428
22429				_state.viewport( _viewport );
22430
22431				shadow.updateMatrices( light, vp );
22432
22433				_frustum = shadow.getFrustum();
22434
22435				renderObject( scene, camera, shadow.camera, light, this.type );
22436
22437			}
22438
22439			// do blur pass for VSM
22440
22441			if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {
22442
22443				VSMPass( shadow, camera );
22444
22445			}
22446
22447			shadow.needsUpdate = false;
22448
22449		}
22450
22451		_previousType = this.type;
22452
22453		scope.needsUpdate = false;
22454
22455		_renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
22456
22457	};
22458
22459	function VSMPass( shadow, camera ) {
22460
22461		const geometry = _objects.update( fullScreenMesh );
22462
22463		if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {
22464
22465			shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
22466			shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;
22467
22468			shadowMaterialVertical.needsUpdate = true;
22469			shadowMaterialHorizontal.needsUpdate = true;
22470
22471		}
22472
22473		if ( shadow.mapPass === null ) {
22474
22475			shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );
22476
22477		}
22478
22479		// vertical pass
22480
22481		shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
22482		shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
22483		shadowMaterialVertical.uniforms.radius.value = shadow.radius;
22484		_renderer.setRenderTarget( shadow.mapPass );
22485		_renderer.clear();
22486		_renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
22487
22488		// horizontal pass
22489
22490		shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
22491		shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
22492		shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
22493		_renderer.setRenderTarget( shadow.map );
22494		_renderer.clear();
22495		_renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
22496
22497	}
22498
22499	function getDepthMaterial( object, material, light, type ) {
22500
22501		let result = null;
22502
22503		const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;
22504
22505		if ( customMaterial !== undefined ) {
22506
22507			result = customMaterial;
22508
22509		} else {
22510
22511			result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;
22512
22513			if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) ||
22514				( material.displacementMap && material.displacementScale !== 0 ) ||
22515				( material.alphaMap && material.alphaTest > 0 ) ||
22516				( material.map && material.alphaTest > 0 ) ) {
22517
22518				// in this case we need a unique material instance reflecting the
22519				// appropriate state
22520
22521				const keyA = result.uuid, keyB = material.uuid;
22522
22523				let materialsForVariant = _materialCache[ keyA ];
22524
22525				if ( materialsForVariant === undefined ) {
22526
22527					materialsForVariant = {};
22528					_materialCache[ keyA ] = materialsForVariant;
22529
22530				}
22531
22532				let cachedMaterial = materialsForVariant[ keyB ];
22533
22534				if ( cachedMaterial === undefined ) {
22535
22536					cachedMaterial = result.clone();
22537					materialsForVariant[ keyB ] = cachedMaterial;
22538					material.addEventListener( 'dispose', onMaterialDispose );
22539
22540				}
22541
22542				result = cachedMaterial;
22543
22544			}
22545
22546		}
22547
22548		result.visible = material.visible;
22549		result.wireframe = material.wireframe;
22550
22551		if ( type === VSMShadowMap ) {
22552
22553			result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
22554
22555		} else {
22556
22557			result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
22558
22559		}
22560
22561		result.alphaMap = material.alphaMap;
22562		result.alphaTest = material.alphaTest;
22563		result.map = material.map;
22564
22565		result.clipShadows = material.clipShadows;
22566		result.clippingPlanes = material.clippingPlanes;
22567		result.clipIntersection = material.clipIntersection;
22568
22569		result.displacementMap = material.displacementMap;
22570		result.displacementScale = material.displacementScale;
22571		result.displacementBias = material.displacementBias;
22572
22573		result.wireframeLinewidth = material.wireframeLinewidth;
22574		result.linewidth = material.linewidth;
22575
22576		if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
22577
22578			const materialProperties = _renderer.properties.get( result );
22579			materialProperties.light = light;
22580
22581		}
22582
22583		return result;
22584
22585	}
22586
22587	function renderObject( object, camera, shadowCamera, light, type ) {
22588
22589		if ( object.visible === false ) return;
22590
22591		const visible = object.layers.test( camera.layers );
22592
22593		if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
22594
22595			if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
22596
22597				object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
22598
22599				const geometry = _objects.update( object );
22600				const material = object.material;
22601
22602				if ( Array.isArray( material ) ) {
22603
22604					const groups = geometry.groups;
22605
22606					for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
22607
22608						const group = groups[ k ];
22609						const groupMaterial = material[ group.materialIndex ];
22610
22611						if ( groupMaterial && groupMaterial.visible ) {
22612
22613							const depthMaterial = getDepthMaterial( object, groupMaterial, light, type );
22614
22615							object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22616
22617							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
22618
22619							object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22620
22621						}
22622
22623					}
22624
22625				} else if ( material.visible ) {
22626
22627					const depthMaterial = getDepthMaterial( object, material, light, type );
22628
22629					object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22630
22631					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
22632
22633					object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22634
22635				}
22636
22637			}
22638
22639		}
22640
22641		const children = object.children;
22642
22643		for ( let i = 0, l = children.length; i < l; i ++ ) {
22644
22645			renderObject( children[ i ], camera, shadowCamera, light, type );
22646
22647		}
22648
22649	}
22650
22651	function onMaterialDispose( event ) {
22652
22653		const material = event.target;
22654
22655		material.removeEventListener( 'dispose', onMaterialDispose );
22656
22657		// make sure to remove the unique distance/depth materials used for shadow map rendering
22658
22659		for ( const id in _materialCache ) {
22660
22661			const cache = _materialCache[ id ];
22662
22663			const uuid = event.target.uuid;
22664
22665			if ( uuid in cache ) {
22666
22667				const shadowMaterial = cache[ uuid ];
22668				shadowMaterial.dispose();
22669				delete cache[ uuid ];
22670
22671			}
22672
22673		}
22674
22675	}
22676
22677}
22678
22679function WebGLState( gl, extensions, capabilities ) {
22680
22681	const isWebGL2 = capabilities.isWebGL2;
22682
22683	function ColorBuffer() {
22684
22685		let locked = false;
22686
22687		const color = new Vector4();
22688		let currentColorMask = null;
22689		const currentColorClear = new Vector4( 0, 0, 0, 0 );
22690
22691		return {
22692
22693			setMask: function ( colorMask ) {
22694
22695				if ( currentColorMask !== colorMask && ! locked ) {
22696
22697					gl.colorMask( colorMask, colorMask, colorMask, colorMask );
22698					currentColorMask = colorMask;
22699
22700				}
22701
22702			},
22703
22704			setLocked: function ( lock ) {
22705
22706				locked = lock;
22707
22708			},
22709
22710			setClear: function ( r, g, b, a, premultipliedAlpha ) {
22711
22712				if ( premultipliedAlpha === true ) {
22713
22714					r *= a; g *= a; b *= a;
22715
22716				}
22717
22718				color.set( r, g, b, a );
22719
22720				if ( currentColorClear.equals( color ) === false ) {
22721
22722					gl.clearColor( r, g, b, a );
22723					currentColorClear.copy( color );
22724
22725				}
22726
22727			},
22728
22729			reset: function () {
22730
22731				locked = false;
22732
22733				currentColorMask = null;
22734				currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
22735
22736			}
22737
22738		};
22739
22740	}
22741
22742	function DepthBuffer() {
22743
22744		let locked = false;
22745
22746		let currentDepthMask = null;
22747		let currentDepthFunc = null;
22748		let currentDepthClear = null;
22749
22750		return {
22751
22752			setTest: function ( depthTest ) {
22753
22754				if ( depthTest ) {
22755
22756					enable( gl.DEPTH_TEST );
22757
22758				} else {
22759
22760					disable( gl.DEPTH_TEST );
22761
22762				}
22763
22764			},
22765
22766			setMask: function ( depthMask ) {
22767
22768				if ( currentDepthMask !== depthMask && ! locked ) {
22769
22770					gl.depthMask( depthMask );
22771					currentDepthMask = depthMask;
22772
22773				}
22774
22775			},
22776
22777			setFunc: function ( depthFunc ) {
22778
22779				if ( currentDepthFunc !== depthFunc ) {
22780
22781					switch ( depthFunc ) {
22782
22783						case NeverDepth:
22784
22785							gl.depthFunc( gl.NEVER );
22786							break;
22787
22788						case AlwaysDepth:
22789
22790							gl.depthFunc( gl.ALWAYS );
22791							break;
22792
22793						case LessDepth:
22794
22795							gl.depthFunc( gl.LESS );
22796							break;
22797
22798						case LessEqualDepth:
22799
22800							gl.depthFunc( gl.LEQUAL );
22801							break;
22802
22803						case EqualDepth:
22804
22805							gl.depthFunc( gl.EQUAL );
22806							break;
22807
22808						case GreaterEqualDepth:
22809
22810							gl.depthFunc( gl.GEQUAL );
22811							break;
22812
22813						case GreaterDepth:
22814
22815							gl.depthFunc( gl.GREATER );
22816							break;
22817
22818						case NotEqualDepth:
22819
22820							gl.depthFunc( gl.NOTEQUAL );
22821							break;
22822
22823						default:
22824
22825							gl.depthFunc( gl.LEQUAL );
22826
22827					}
22828
22829					currentDepthFunc = depthFunc;
22830
22831				}
22832
22833			},
22834
22835			setLocked: function ( lock ) {
22836
22837				locked = lock;
22838
22839			},
22840
22841			setClear: function ( depth ) {
22842
22843				if ( currentDepthClear !== depth ) {
22844
22845					gl.clearDepth( depth );
22846					currentDepthClear = depth;
22847
22848				}
22849
22850			},
22851
22852			reset: function () {
22853
22854				locked = false;
22855
22856				currentDepthMask = null;
22857				currentDepthFunc = null;
22858				currentDepthClear = null;
22859
22860			}
22861
22862		};
22863
22864	}
22865
22866	function StencilBuffer() {
22867
22868		let locked = false;
22869
22870		let currentStencilMask = null;
22871		let currentStencilFunc = null;
22872		let currentStencilRef = null;
22873		let currentStencilFuncMask = null;
22874		let currentStencilFail = null;
22875		let currentStencilZFail = null;
22876		let currentStencilZPass = null;
22877		let currentStencilClear = null;
22878
22879		return {
22880
22881			setTest: function ( stencilTest ) {
22882
22883				if ( ! locked ) {
22884
22885					if ( stencilTest ) {
22886
22887						enable( gl.STENCIL_TEST );
22888
22889					} else {
22890
22891						disable( gl.STENCIL_TEST );
22892
22893					}
22894
22895				}
22896
22897			},
22898
22899			setMask: function ( stencilMask ) {
22900
22901				if ( currentStencilMask !== stencilMask && ! locked ) {
22902
22903					gl.stencilMask( stencilMask );
22904					currentStencilMask = stencilMask;
22905
22906				}
22907
22908			},
22909
22910			setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
22911
22912				if ( currentStencilFunc !== stencilFunc ||
22913				     currentStencilRef !== stencilRef ||
22914				     currentStencilFuncMask !== stencilMask ) {
22915
22916					gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
22917
22918					currentStencilFunc = stencilFunc;
22919					currentStencilRef = stencilRef;
22920					currentStencilFuncMask = stencilMask;
22921
22922				}
22923
22924			},
22925
22926			setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
22927
22928				if ( currentStencilFail !== stencilFail ||
22929				     currentStencilZFail !== stencilZFail ||
22930				     currentStencilZPass !== stencilZPass ) {
22931
22932					gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
22933
22934					currentStencilFail = stencilFail;
22935					currentStencilZFail = stencilZFail;
22936					currentStencilZPass = stencilZPass;
22937
22938				}
22939
22940			},
22941
22942			setLocked: function ( lock ) {
22943
22944				locked = lock;
22945
22946			},
22947
22948			setClear: function ( stencil ) {
22949
22950				if ( currentStencilClear !== stencil ) {
22951
22952					gl.clearStencil( stencil );
22953					currentStencilClear = stencil;
22954
22955				}
22956
22957			},
22958
22959			reset: function () {
22960
22961				locked = false;
22962
22963				currentStencilMask = null;
22964				currentStencilFunc = null;
22965				currentStencilRef = null;
22966				currentStencilFuncMask = null;
22967				currentStencilFail = null;
22968				currentStencilZFail = null;
22969				currentStencilZPass = null;
22970				currentStencilClear = null;
22971
22972			}
22973
22974		};
22975
22976	}
22977
22978	//
22979
22980	const colorBuffer = new ColorBuffer();
22981	const depthBuffer = new DepthBuffer();
22982	const stencilBuffer = new StencilBuffer();
22983
22984	const uboBindings = new WeakMap();
22985	const uboProgramMap = new WeakMap();
22986
22987	let enabledCapabilities = {};
22988
22989	let currentBoundFramebuffers = {};
22990	let currentDrawbuffers = new WeakMap();
22991	let defaultDrawbuffers = [];
22992
22993	let currentProgram = null;
22994
22995	let currentBlendingEnabled = false;
22996	let currentBlending = null;
22997	let currentBlendEquation = null;
22998	let currentBlendSrc = null;
22999	let currentBlendDst = null;
23000	let currentBlendEquationAlpha = null;
23001	let currentBlendSrcAlpha = null;
23002	let currentBlendDstAlpha = null;
23003	let currentBlendColor = new Color( 0, 0, 0 );
23004	let currentBlendAlpha = 0;
23005	let currentPremultipledAlpha = false;
23006
23007	let currentFlipSided = null;
23008	let currentCullFace = null;
23009
23010	let currentLineWidth = null;
23011
23012	let currentPolygonOffsetFactor = null;
23013	let currentPolygonOffsetUnits = null;
23014
23015	const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
23016
23017	let lineWidthAvailable = false;
23018	let version = 0;
23019	const glVersion = gl.getParameter( gl.VERSION );
23020
23021	if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
23022
23023		version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
23024		lineWidthAvailable = ( version >= 1.0 );
23025
23026	} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
23027
23028		version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
23029		lineWidthAvailable = ( version >= 2.0 );
23030
23031	}
23032
23033	let currentTextureSlot = null;
23034	let currentBoundTextures = {};
23035
23036	const scissorParam = gl.getParameter( gl.SCISSOR_BOX );
23037	const viewportParam = gl.getParameter( gl.VIEWPORT );
23038
23039	const currentScissor = new Vector4().fromArray( scissorParam );
23040	const currentViewport = new Vector4().fromArray( viewportParam );
23041
23042	function createTexture( type, target, count, dimensions ) {
23043
23044		const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
23045		const texture = gl.createTexture();
23046
23047		gl.bindTexture( type, texture );
23048		gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
23049		gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
23050
23051		for ( let i = 0; i < count; i ++ ) {
23052
23053			if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) {
23054
23055				gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23056
23057			} else {
23058
23059				gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23060
23061			}
23062
23063		}
23064
23065		return texture;
23066
23067	}
23068
23069	const emptyTextures = {};
23070	emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
23071	emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
23072
23073	if ( isWebGL2 ) {
23074
23075		emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );
23076		emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );
23077
23078	}
23079
23080	// init
23081
23082	colorBuffer.setClear( 0, 0, 0, 1 );
23083	depthBuffer.setClear( 1 );
23084	stencilBuffer.setClear( 0 );
23085
23086	enable( gl.DEPTH_TEST );
23087	depthBuffer.setFunc( LessEqualDepth );
23088
23089	setFlipSided( false );
23090	setCullFace( CullFaceBack );
23091	enable( gl.CULL_FACE );
23092
23093	setBlending( NoBlending );
23094
23095	//
23096
23097	function enable( id ) {
23098
23099		if ( enabledCapabilities[ id ] !== true ) {
23100
23101			gl.enable( id );
23102			enabledCapabilities[ id ] = true;
23103
23104		}
23105
23106	}
23107
23108	function disable( id ) {
23109
23110		if ( enabledCapabilities[ id ] !== false ) {
23111
23112			gl.disable( id );
23113			enabledCapabilities[ id ] = false;
23114
23115		}
23116
23117	}
23118
23119	function bindFramebuffer( target, framebuffer ) {
23120
23121		if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
23122
23123			gl.bindFramebuffer( target, framebuffer );
23124
23125			currentBoundFramebuffers[ target ] = framebuffer;
23126
23127			if ( isWebGL2 ) {
23128
23129				// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
23130
23131				if ( target === gl.DRAW_FRAMEBUFFER ) {
23132
23133					currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;
23134
23135				}
23136
23137				if ( target === gl.FRAMEBUFFER ) {
23138
23139					currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;
23140
23141				}
23142
23143			}
23144
23145			return true;
23146
23147		}
23148
23149		return false;
23150
23151	}
23152
23153	function drawBuffers( renderTarget, framebuffer ) {
23154
23155		let drawBuffers = defaultDrawbuffers;
23156
23157		let needsUpdate = false;
23158
23159		if ( renderTarget ) {
23160
23161			drawBuffers = currentDrawbuffers.get( framebuffer );
23162
23163			if ( drawBuffers === undefined ) {
23164
23165				drawBuffers = [];
23166				currentDrawbuffers.set( framebuffer, drawBuffers );
23167
23168			}
23169
23170			if ( renderTarget.isWebGLMultipleRenderTargets ) {
23171
23172				const textures = renderTarget.texture;
23173
23174				if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23175
23176					for ( let i = 0, il = textures.length; i < il; i ++ ) {
23177
23178						drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
23179
23180					}
23181
23182					drawBuffers.length = textures.length;
23183
23184					needsUpdate = true;
23185
23186				}
23187
23188			} else {
23189
23190				if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23191
23192					drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0;
23193
23194					needsUpdate = true;
23195
23196				}
23197
23198			}
23199
23200		} else {
23201
23202			if ( drawBuffers[ 0 ] !== gl.BACK ) {
23203
23204				drawBuffers[ 0 ] = gl.BACK;
23205
23206				needsUpdate = true;
23207
23208			}
23209
23210		}
23211
23212		if ( needsUpdate ) {
23213
23214			if ( capabilities.isWebGL2 ) {
23215
23216				gl.drawBuffers( drawBuffers );
23217
23218			} else {
23219
23220				extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers );
23221
23222			}
23223
23224		}
23225
23226
23227	}
23228
23229	function useProgram( program ) {
23230
23231		if ( currentProgram !== program ) {
23232
23233			gl.useProgram( program );
23234
23235			currentProgram = program;
23236
23237			return true;
23238
23239		}
23240
23241		return false;
23242
23243	}
23244
23245	const equationToGL = {
23246		[ AddEquation ]: gl.FUNC_ADD,
23247		[ SubtractEquation ]: gl.FUNC_SUBTRACT,
23248		[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
23249	};
23250
23251	if ( isWebGL2 ) {
23252
23253		equationToGL[ MinEquation ] = gl.MIN;
23254		equationToGL[ MaxEquation ] = gl.MAX;
23255
23256	} else {
23257
23258		const extension = extensions.get( 'EXT_blend_minmax' );
23259
23260		if ( extension !== null ) {
23261
23262			equationToGL[ MinEquation ] = extension.MIN_EXT;
23263			equationToGL[ MaxEquation ] = extension.MAX_EXT;
23264
23265		}
23266
23267	}
23268
23269	const factorToGL = {
23270		[ ZeroFactor ]: gl.ZERO,
23271		[ OneFactor ]: gl.ONE,
23272		[ SrcColorFactor ]: gl.SRC_COLOR,
23273		[ SrcAlphaFactor ]: gl.SRC_ALPHA,
23274		[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
23275		[ DstColorFactor ]: gl.DST_COLOR,
23276		[ DstAlphaFactor ]: gl.DST_ALPHA,
23277		[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
23278		[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
23279		[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
23280		[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
23281		[ ConstantColorFactor ]: gl.CONSTANT_COLOR,
23282		[ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
23283		[ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
23284		[ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
23285	};
23286
23287	function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {
23288
23289		if ( blending === NoBlending ) {
23290
23291			if ( currentBlendingEnabled === true ) {
23292
23293				disable( gl.BLEND );
23294				currentBlendingEnabled = false;
23295
23296			}
23297
23298			return;
23299
23300		}
23301
23302		if ( currentBlendingEnabled === false ) {
23303
23304			enable( gl.BLEND );
23305			currentBlendingEnabled = true;
23306
23307		}
23308
23309		if ( blending !== CustomBlending ) {
23310
23311			if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
23312
23313				if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
23314
23315					gl.blendEquation( gl.FUNC_ADD );
23316
23317					currentBlendEquation = AddEquation;
23318					currentBlendEquationAlpha = AddEquation;
23319
23320				}
23321
23322				if ( premultipliedAlpha ) {
23323
23324					switch ( blending ) {
23325
23326						case NormalBlending:
23327							gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23328							break;
23329
23330						case AdditiveBlending:
23331							gl.blendFunc( gl.ONE, gl.ONE );
23332							break;
23333
23334						case SubtractiveBlending:
23335							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23336							break;
23337
23338						case MultiplyBlending:
23339							gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
23340							break;
23341
23342						default:
23343							console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23344							break;
23345
23346					}
23347
23348				} else {
23349
23350					switch ( blending ) {
23351
23352						case NormalBlending:
23353							gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23354							break;
23355
23356						case AdditiveBlending:
23357							gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
23358							break;
23359
23360						case SubtractiveBlending:
23361							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23362							break;
23363
23364						case MultiplyBlending:
23365							gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
23366							break;
23367
23368						default:
23369							console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23370							break;
23371
23372					}
23373
23374				}
23375
23376				currentBlendSrc = null;
23377				currentBlendDst = null;
23378				currentBlendSrcAlpha = null;
23379				currentBlendDstAlpha = null;
23380				currentBlendColor.set( 0, 0, 0 );
23381				currentBlendAlpha = 0;
23382
23383				currentBlending = blending;
23384				currentPremultipledAlpha = premultipliedAlpha;
23385
23386			}
23387
23388			return;
23389
23390		}
23391
23392		// custom blending
23393
23394		blendEquationAlpha = blendEquationAlpha || blendEquation;
23395		blendSrcAlpha = blendSrcAlpha || blendSrc;
23396		blendDstAlpha = blendDstAlpha || blendDst;
23397
23398		if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
23399
23400			gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
23401
23402			currentBlendEquation = blendEquation;
23403			currentBlendEquationAlpha = blendEquationAlpha;
23404
23405		}
23406
23407		if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
23408
23409			gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
23410
23411			currentBlendSrc = blendSrc;
23412			currentBlendDst = blendDst;
23413			currentBlendSrcAlpha = blendSrcAlpha;
23414			currentBlendDstAlpha = blendDstAlpha;
23415
23416		}
23417
23418		if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {
23419
23420			gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );
23421
23422			currentBlendColor.copy( blendColor );
23423			currentBlendAlpha = blendAlpha;
23424
23425		}
23426
23427		currentBlending = blending;
23428		currentPremultipledAlpha = false;
23429
23430	}
23431
23432	function setMaterial( material, frontFaceCW ) {
23433
23434		material.side === DoubleSide
23435			? disable( gl.CULL_FACE )
23436			: enable( gl.CULL_FACE );
23437
23438		let flipSided = ( material.side === BackSide );
23439		if ( frontFaceCW ) flipSided = ! flipSided;
23440
23441		setFlipSided( flipSided );
23442
23443		( material.blending === NormalBlending && material.transparent === false )
23444			? setBlending( NoBlending )
23445			: setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
23446
23447		depthBuffer.setFunc( material.depthFunc );
23448		depthBuffer.setTest( material.depthTest );
23449		depthBuffer.setMask( material.depthWrite );
23450		colorBuffer.setMask( material.colorWrite );
23451
23452		const stencilWrite = material.stencilWrite;
23453		stencilBuffer.setTest( stencilWrite );
23454		if ( stencilWrite ) {
23455
23456			stencilBuffer.setMask( material.stencilWriteMask );
23457			stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
23458			stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
23459
23460		}
23461
23462		setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
23463
23464		material.alphaToCoverage === true
23465			? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
23466			: disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
23467
23468	}
23469
23470	//
23471
23472	function setFlipSided( flipSided ) {
23473
23474		if ( currentFlipSided !== flipSided ) {
23475
23476			if ( flipSided ) {
23477
23478				gl.frontFace( gl.CW );
23479
23480			} else {
23481
23482				gl.frontFace( gl.CCW );
23483
23484			}
23485
23486			currentFlipSided = flipSided;
23487
23488		}
23489
23490	}
23491
23492	function setCullFace( cullFace ) {
23493
23494		if ( cullFace !== CullFaceNone ) {
23495
23496			enable( gl.CULL_FACE );
23497
23498			if ( cullFace !== currentCullFace ) {
23499
23500				if ( cullFace === CullFaceBack ) {
23501
23502					gl.cullFace( gl.BACK );
23503
23504				} else if ( cullFace === CullFaceFront ) {
23505
23506					gl.cullFace( gl.FRONT );
23507
23508				} else {
23509
23510					gl.cullFace( gl.FRONT_AND_BACK );
23511
23512				}
23513
23514			}
23515
23516		} else {
23517
23518			disable( gl.CULL_FACE );
23519
23520		}
23521
23522		currentCullFace = cullFace;
23523
23524	}
23525
23526	function setLineWidth( width ) {
23527
23528		if ( width !== currentLineWidth ) {
23529
23530			if ( lineWidthAvailable ) gl.lineWidth( width );
23531
23532			currentLineWidth = width;
23533
23534		}
23535
23536	}
23537
23538	function setPolygonOffset( polygonOffset, factor, units ) {
23539
23540		if ( polygonOffset ) {
23541
23542			enable( gl.POLYGON_OFFSET_FILL );
23543
23544			if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
23545
23546				gl.polygonOffset( factor, units );
23547
23548				currentPolygonOffsetFactor = factor;
23549				currentPolygonOffsetUnits = units;
23550
23551			}
23552
23553		} else {
23554
23555			disable( gl.POLYGON_OFFSET_FILL );
23556
23557		}
23558
23559	}
23560
23561	function setScissorTest( scissorTest ) {
23562
23563		if ( scissorTest ) {
23564
23565			enable( gl.SCISSOR_TEST );
23566
23567		} else {
23568
23569			disable( gl.SCISSOR_TEST );
23570
23571		}
23572
23573	}
23574
23575	// texture
23576
23577	function activeTexture( webglSlot ) {
23578
23579		if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
23580
23581		if ( currentTextureSlot !== webglSlot ) {
23582
23583			gl.activeTexture( webglSlot );
23584			currentTextureSlot = webglSlot;
23585
23586		}
23587
23588	}
23589
23590	function bindTexture( webglType, webglTexture, webglSlot ) {
23591
23592		if ( webglSlot === undefined ) {
23593
23594			if ( currentTextureSlot === null ) {
23595
23596				webglSlot = gl.TEXTURE0 + maxTextures - 1;
23597
23598			} else {
23599
23600				webglSlot = currentTextureSlot;
23601
23602			}
23603
23604		}
23605
23606		let boundTexture = currentBoundTextures[ webglSlot ];
23607
23608		if ( boundTexture === undefined ) {
23609
23610			boundTexture = { type: undefined, texture: undefined };
23611			currentBoundTextures[ webglSlot ] = boundTexture;
23612
23613		}
23614
23615		if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
23616
23617			if ( currentTextureSlot !== webglSlot ) {
23618
23619				gl.activeTexture( webglSlot );
23620				currentTextureSlot = webglSlot;
23621
23622			}
23623
23624			gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
23625
23626			boundTexture.type = webglType;
23627			boundTexture.texture = webglTexture;
23628
23629		}
23630
23631	}
23632
23633	function unbindTexture() {
23634
23635		const boundTexture = currentBoundTextures[ currentTextureSlot ];
23636
23637
23638		if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
23639
23640			gl.bindTexture( boundTexture.type, null );
23641
23642			boundTexture.type = undefined;
23643			boundTexture.texture = undefined;
23644
23645		}
23646
23647	}
23648
23649	function compressedTexImage2D() {
23650
23651		try {
23652
23653			gl.compressedTexImage2D.apply( gl, arguments );
23654
23655		} catch ( error ) {
23656
23657			console.error( 'THREE.WebGLState:', error );
23658
23659		}
23660
23661	}
23662
23663	function compressedTexImage3D() {
23664
23665		try {
23666
23667			gl.compressedTexImage3D.apply( gl, arguments );
23668
23669		} catch ( error ) {
23670
23671			console.error( 'THREE.WebGLState:', error );
23672
23673		}
23674
23675	}
23676
23677	function texSubImage2D() {
23678
23679		try {
23680
23681			gl.texSubImage2D.apply( gl, arguments );
23682
23683		} catch ( error ) {
23684
23685			console.error( 'THREE.WebGLState:', error );
23686
23687		}
23688
23689	}
23690
23691	function texSubImage3D() {
23692
23693		try {
23694
23695			gl.texSubImage3D.apply( gl, arguments );
23696
23697		} catch ( error ) {
23698
23699			console.error( 'THREE.WebGLState:', error );
23700
23701		}
23702
23703	}
23704
23705	function compressedTexSubImage2D() {
23706
23707		try {
23708
23709			gl.compressedTexSubImage2D.apply( gl, arguments );
23710
23711		} catch ( error ) {
23712
23713			console.error( 'THREE.WebGLState:', error );
23714
23715		}
23716
23717	}
23718
23719	function compressedTexSubImage3D() {
23720
23721		try {
23722
23723			gl.compressedTexSubImage3D.apply( gl, arguments );
23724
23725		} catch ( error ) {
23726
23727			console.error( 'THREE.WebGLState:', error );
23728
23729		}
23730
23731	}
23732
23733	function texStorage2D() {
23734
23735		try {
23736
23737			gl.texStorage2D.apply( gl, arguments );
23738
23739		} catch ( error ) {
23740
23741			console.error( 'THREE.WebGLState:', error );
23742
23743		}
23744
23745	}
23746
23747	function texStorage3D() {
23748
23749		try {
23750
23751			gl.texStorage3D.apply( gl, arguments );
23752
23753		} catch ( error ) {
23754
23755			console.error( 'THREE.WebGLState:', error );
23756
23757		}
23758
23759	}
23760
23761	function texImage2D() {
23762
23763		try {
23764
23765			gl.texImage2D.apply( gl, arguments );
23766
23767		} catch ( error ) {
23768
23769			console.error( 'THREE.WebGLState:', error );
23770
23771		}
23772
23773	}
23774
23775	function texImage3D() {
23776
23777		try {
23778
23779			gl.texImage3D.apply( gl, arguments );
23780
23781		} catch ( error ) {
23782
23783			console.error( 'THREE.WebGLState:', error );
23784
23785		}
23786
23787	}
23788
23789	//
23790
23791	function scissor( scissor ) {
23792
23793		if ( currentScissor.equals( scissor ) === false ) {
23794
23795			gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
23796			currentScissor.copy( scissor );
23797
23798		}
23799
23800	}
23801
23802	function viewport( viewport ) {
23803
23804		if ( currentViewport.equals( viewport ) === false ) {
23805
23806			gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
23807			currentViewport.copy( viewport );
23808
23809		}
23810
23811	}
23812
23813	function updateUBOMapping( uniformsGroup, program ) {
23814
23815		let mapping = uboProgramMap.get( program );
23816
23817		if ( mapping === undefined ) {
23818
23819			mapping = new WeakMap();
23820
23821			uboProgramMap.set( program, mapping );
23822
23823		}
23824
23825		let blockIndex = mapping.get( uniformsGroup );
23826
23827		if ( blockIndex === undefined ) {
23828
23829			blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );
23830
23831			mapping.set( uniformsGroup, blockIndex );
23832
23833		}
23834
23835	}
23836
23837	function uniformBlockBinding( uniformsGroup, program ) {
23838
23839		const mapping = uboProgramMap.get( program );
23840		const blockIndex = mapping.get( uniformsGroup );
23841
23842		if ( uboBindings.get( program ) !== blockIndex ) {
23843
23844			// bind shader specific block index to global block point
23845			gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );
23846
23847			uboBindings.set( program, blockIndex );
23848
23849		}
23850
23851	}
23852
23853	//
23854
23855	function reset() {
23856
23857		// reset state
23858
23859		gl.disable( gl.BLEND );
23860		gl.disable( gl.CULL_FACE );
23861		gl.disable( gl.DEPTH_TEST );
23862		gl.disable( gl.POLYGON_OFFSET_FILL );
23863		gl.disable( gl.SCISSOR_TEST );
23864		gl.disable( gl.STENCIL_TEST );
23865		gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
23866
23867		gl.blendEquation( gl.FUNC_ADD );
23868		gl.blendFunc( gl.ONE, gl.ZERO );
23869		gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
23870		gl.blendColor( 0, 0, 0, 0 );
23871
23872		gl.colorMask( true, true, true, true );
23873		gl.clearColor( 0, 0, 0, 0 );
23874
23875		gl.depthMask( true );
23876		gl.depthFunc( gl.LESS );
23877		gl.clearDepth( 1 );
23878
23879		gl.stencilMask( 0xffffffff );
23880		gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
23881		gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
23882		gl.clearStencil( 0 );
23883
23884		gl.cullFace( gl.BACK );
23885		gl.frontFace( gl.CCW );
23886
23887		gl.polygonOffset( 0, 0 );
23888
23889		gl.activeTexture( gl.TEXTURE0 );
23890
23891		gl.bindFramebuffer( gl.FRAMEBUFFER, null );
23892
23893		if ( isWebGL2 === true ) {
23894
23895			gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
23896			gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
23897
23898		}
23899
23900		gl.useProgram( null );
23901
23902		gl.lineWidth( 1 );
23903
23904		gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
23905		gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
23906
23907		// reset internals
23908
23909		enabledCapabilities = {};
23910
23911		currentTextureSlot = null;
23912		currentBoundTextures = {};
23913
23914		currentBoundFramebuffers = {};
23915		currentDrawbuffers = new WeakMap();
23916		defaultDrawbuffers = [];
23917
23918		currentProgram = null;
23919
23920		currentBlendingEnabled = false;
23921		currentBlending = null;
23922		currentBlendEquation = null;
23923		currentBlendSrc = null;
23924		currentBlendDst = null;
23925		currentBlendEquationAlpha = null;
23926		currentBlendSrcAlpha = null;
23927		currentBlendDstAlpha = null;
23928		currentBlendColor = new Color( 0, 0, 0 );
23929		currentBlendAlpha = 0;
23930		currentPremultipledAlpha = false;
23931
23932		currentFlipSided = null;
23933		currentCullFace = null;
23934
23935		currentLineWidth = null;
23936
23937		currentPolygonOffsetFactor = null;
23938		currentPolygonOffsetUnits = null;
23939
23940		currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
23941		currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );
23942
23943		colorBuffer.reset();
23944		depthBuffer.reset();
23945		stencilBuffer.reset();
23946
23947	}
23948
23949	return {
23950
23951		buffers: {
23952			color: colorBuffer,
23953			depth: depthBuffer,
23954			stencil: stencilBuffer
23955		},
23956
23957		enable: enable,
23958		disable: disable,
23959
23960		bindFramebuffer: bindFramebuffer,
23961		drawBuffers: drawBuffers,
23962
23963		useProgram: useProgram,
23964
23965		setBlending: setBlending,
23966		setMaterial: setMaterial,
23967
23968		setFlipSided: setFlipSided,
23969		setCullFace: setCullFace,
23970
23971		setLineWidth: setLineWidth,
23972		setPolygonOffset: setPolygonOffset,
23973
23974		setScissorTest: setScissorTest,
23975
23976		activeTexture: activeTexture,
23977		bindTexture: bindTexture,
23978		unbindTexture: unbindTexture,
23979		compressedTexImage2D: compressedTexImage2D,
23980		compressedTexImage3D: compressedTexImage3D,
23981		texImage2D: texImage2D,
23982		texImage3D: texImage3D,
23983
23984		updateUBOMapping: updateUBOMapping,
23985		uniformBlockBinding: uniformBlockBinding,
23986
23987		texStorage2D: texStorage2D,
23988		texStorage3D: texStorage3D,
23989		texSubImage2D: texSubImage2D,
23990		texSubImage3D: texSubImage3D,
23991		compressedTexSubImage2D: compressedTexSubImage2D,
23992		compressedTexSubImage3D: compressedTexSubImage3D,
23993
23994		scissor: scissor,
23995		viewport: viewport,
23996
23997		reset: reset
23998
23999	};
24000
24001}
24002
24003function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
24004
24005	const isWebGL2 = capabilities.isWebGL2;
24006	const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;
24007	const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent );
24008
24009	const _videoTextures = new WeakMap();
24010	let _canvas;
24011
24012	const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source
24013
24014	// cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
24015	// also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
24016	// Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
24017
24018	let useOffscreenCanvas = false;
24019
24020	try {
24021
24022		useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
24023			// eslint-disable-next-line compat/compat
24024			&& ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
24025
24026	} catch ( err ) {
24027
24028		// Ignore any errors
24029
24030	}
24031
24032	function createCanvas( width, height ) {
24033
24034		// Use OffscreenCanvas when available. Specially needed in web workers
24035
24036		return useOffscreenCanvas ?
24037			// eslint-disable-next-line compat/compat
24038			new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );
24039
24040	}
24041
24042	function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
24043
24044		let scale = 1;
24045
24046		// handle case if texture exceeds max size
24047
24048		if ( image.width > maxSize || image.height > maxSize ) {
24049
24050			scale = maxSize / Math.max( image.width, image.height );
24051
24052		}
24053
24054		// only perform resize if necessary
24055
24056		if ( scale < 1 || needsPowerOfTwo === true ) {
24057
24058			// only perform resize for certain image types
24059
24060			if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
24061				( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
24062				( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
24063
24064				const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor;
24065
24066				const width = floor( scale * image.width );
24067				const height = floor( scale * image.height );
24068
24069				if ( _canvas === undefined ) _canvas = createCanvas( width, height );
24070
24071				// cube textures can't reuse the same canvas
24072
24073				const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
24074
24075				canvas.width = width;
24076				canvas.height = height;
24077
24078				const context = canvas.getContext( '2d' );
24079				context.drawImage( image, 0, 0, width, height );
24080
24081				console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
24082
24083				return canvas;
24084
24085			} else {
24086
24087				if ( 'data' in image ) {
24088
24089					console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
24090
24091				}
24092
24093				return image;
24094
24095			}
24096
24097		}
24098
24099		return image;
24100
24101	}
24102
24103	function isPowerOfTwo$1( image ) {
24104
24105		return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height );
24106
24107	}
24108
24109	function textureNeedsPowerOfTwo( texture ) {
24110
24111		if ( isWebGL2 ) return false;
24112
24113		return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
24114			( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
24115
24116	}
24117
24118	function textureNeedsGenerateMipmaps( texture, supportsMips ) {
24119
24120		return texture.generateMipmaps && supportsMips &&
24121			texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
24122
24123	}
24124
24125	function generateMipmap( target ) {
24126
24127		_gl.generateMipmap( target );
24128
24129	}
24130
24131	function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {
24132
24133		if ( isWebGL2 === false ) return glFormat;
24134
24135		if ( internalFormatName !== null ) {
24136
24137			if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
24138
24139			console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
24140
24141		}
24142
24143		let internalFormat = glFormat;
24144
24145		if ( glFormat === _gl.RED ) {
24146
24147			if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
24148			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
24149			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
24150
24151		}
24152
24153		if ( glFormat === _gl.RED_INTEGER ) {
24154
24155			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI;
24156			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI;
24157			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI;
24158			if ( glType === _gl.BYTE ) internalFormat = _gl.R8I;
24159			if ( glType === _gl.SHORT ) internalFormat = _gl.R16I;
24160			if ( glType === _gl.INT ) internalFormat = _gl.R32I;
24161
24162		}
24163
24164		if ( glFormat === _gl.RG ) {
24165
24166			if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;
24167			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;
24168			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;
24169
24170		}
24171
24172		if ( glFormat === _gl.RGBA ) {
24173
24174			const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace );
24175
24176			if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
24177			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
24178			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
24179			if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;
24180			if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;
24181
24182		}
24183
24184		if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||
24185			internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
24186			internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {
24187
24188			extensions.get( 'EXT_color_buffer_float' );
24189
24190		}
24191
24192		return internalFormat;
24193
24194	}
24195
24196	function getMipLevels( texture, image, supportsMips ) {
24197
24198		if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {
24199
24200			return Math.log2( Math.max( image.width, image.height ) ) + 1;
24201
24202		} else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {
24203
24204			// user-defined mipmaps
24205
24206			return texture.mipmaps.length;
24207
24208		} else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {
24209
24210			return image.mipmaps.length;
24211
24212		} else {
24213
24214			// texture without mipmaps (only base level)
24215
24216			return 1;
24217
24218		}
24219
24220	}
24221
24222	// Fallback filters for non-power-of-2 textures
24223
24224	function filterFallback( f ) {
24225
24226		if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
24227
24228			return _gl.NEAREST;
24229
24230		}
24231
24232		return _gl.LINEAR;
24233
24234	}
24235
24236	//
24237
24238	function onTextureDispose( event ) {
24239
24240		const texture = event.target;
24241
24242		texture.removeEventListener( 'dispose', onTextureDispose );
24243
24244		deallocateTexture( texture );
24245
24246		if ( texture.isVideoTexture ) {
24247
24248			_videoTextures.delete( texture );
24249
24250		}
24251
24252	}
24253
24254	function onRenderTargetDispose( event ) {
24255
24256		const renderTarget = event.target;
24257
24258		renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
24259
24260		deallocateRenderTarget( renderTarget );
24261
24262	}
24263
24264	//
24265
24266	function deallocateTexture( texture ) {
24267
24268		const textureProperties = properties.get( texture );
24269
24270		if ( textureProperties.__webglInit === undefined ) return;
24271
24272		// check if it's necessary to remove the WebGLTexture object
24273
24274		const source = texture.source;
24275		const webglTextures = _sources.get( source );
24276
24277		if ( webglTextures ) {
24278
24279			const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24280			webglTexture.usedTimes --;
24281
24282			// the WebGLTexture object is not used anymore, remove it
24283
24284			if ( webglTexture.usedTimes === 0 ) {
24285
24286				deleteTexture( texture );
24287
24288			}
24289
24290			// remove the weak map entry if no WebGLTexture uses the source anymore
24291
24292			if ( Object.keys( webglTextures ).length === 0 ) {
24293
24294				_sources.delete( source );
24295
24296			}
24297
24298		}
24299
24300		properties.remove( texture );
24301
24302	}
24303
24304	function deleteTexture( texture ) {
24305
24306		const textureProperties = properties.get( texture );
24307		_gl.deleteTexture( textureProperties.__webglTexture );
24308
24309		const source = texture.source;
24310		const webglTextures = _sources.get( source );
24311		delete webglTextures[ textureProperties.__cacheKey ];
24312
24313		info.memory.textures --;
24314
24315	}
24316
24317	function deallocateRenderTarget( renderTarget ) {
24318
24319		const texture = renderTarget.texture;
24320
24321		const renderTargetProperties = properties.get( renderTarget );
24322		const textureProperties = properties.get( texture );
24323
24324		if ( textureProperties.__webglTexture !== undefined ) {
24325
24326			_gl.deleteTexture( textureProperties.__webglTexture );
24327
24328			info.memory.textures --;
24329
24330		}
24331
24332		if ( renderTarget.depthTexture ) {
24333
24334			renderTarget.depthTexture.dispose();
24335
24336		}
24337
24338		if ( renderTarget.isWebGLCubeRenderTarget ) {
24339
24340			for ( let i = 0; i < 6; i ++ ) {
24341
24342				if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {
24343
24344					for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] );
24345
24346				} else {
24347
24348					_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
24349
24350				}
24351
24352				if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
24353
24354			}
24355
24356		} else {
24357
24358			if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) {
24359
24360				for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] );
24361
24362			} else {
24363
24364				_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
24365
24366			}
24367
24368			if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
24369			if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
24370
24371			if ( renderTargetProperties.__webglColorRenderbuffer ) {
24372
24373				for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {
24374
24375					if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );
24376
24377				}
24378
24379			}
24380
24381			if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
24382
24383		}
24384
24385		if ( renderTarget.isWebGLMultipleRenderTargets ) {
24386
24387			for ( let i = 0, il = texture.length; i < il; i ++ ) {
24388
24389				const attachmentProperties = properties.get( texture[ i ] );
24390
24391				if ( attachmentProperties.__webglTexture ) {
24392
24393					_gl.deleteTexture( attachmentProperties.__webglTexture );
24394
24395					info.memory.textures --;
24396
24397				}
24398
24399				properties.remove( texture[ i ] );
24400
24401			}
24402
24403		}
24404
24405		properties.remove( texture );
24406		properties.remove( renderTarget );
24407
24408	}
24409
24410	//
24411
24412	let textureUnits = 0;
24413
24414	function resetTextureUnits() {
24415
24416		textureUnits = 0;
24417
24418	}
24419
24420	function allocateTextureUnit() {
24421
24422		const textureUnit = textureUnits;
24423
24424		if ( textureUnit >= capabilities.maxTextures ) {
24425
24426			console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
24427
24428		}
24429
24430		textureUnits += 1;
24431
24432		return textureUnit;
24433
24434	}
24435
24436	function getTextureCacheKey( texture ) {
24437
24438		const array = [];
24439
24440		array.push( texture.wrapS );
24441		array.push( texture.wrapT );
24442		array.push( texture.wrapR || 0 );
24443		array.push( texture.magFilter );
24444		array.push( texture.minFilter );
24445		array.push( texture.anisotropy );
24446		array.push( texture.internalFormat );
24447		array.push( texture.format );
24448		array.push( texture.type );
24449		array.push( texture.generateMipmaps );
24450		array.push( texture.premultiplyAlpha );
24451		array.push( texture.flipY );
24452		array.push( texture.unpackAlignment );
24453		array.push( texture.colorSpace );
24454
24455		return array.join();
24456
24457	}
24458
24459	//
24460
24461	function setTexture2D( texture, slot ) {
24462
24463		const textureProperties = properties.get( texture );
24464
24465		if ( texture.isVideoTexture ) updateVideoTexture( texture );
24466
24467		if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {
24468
24469			const image = texture.image;
24470
24471			if ( image === null ) {
24472
24473				console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );
24474
24475			} else if ( image.complete === false ) {
24476
24477				console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
24478
24479			} else {
24480
24481				uploadTexture( textureProperties, texture, slot );
24482				return;
24483
24484			}
24485
24486		}
24487
24488		state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24489
24490	}
24491
24492	function setTexture2DArray( texture, slot ) {
24493
24494		const textureProperties = properties.get( texture );
24495
24496		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24497
24498			uploadTexture( textureProperties, texture, slot );
24499			return;
24500
24501		}
24502
24503		state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24504
24505	}
24506
24507	function setTexture3D( texture, slot ) {
24508
24509		const textureProperties = properties.get( texture );
24510
24511		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24512
24513			uploadTexture( textureProperties, texture, slot );
24514			return;
24515
24516		}
24517
24518		state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24519
24520	}
24521
24522	function setTextureCube( texture, slot ) {
24523
24524		const textureProperties = properties.get( texture );
24525
24526		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24527
24528			uploadCubeTexture( textureProperties, texture, slot );
24529			return;
24530
24531		}
24532
24533		state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24534
24535	}
24536
24537	const wrappingToGL = {
24538		[ RepeatWrapping ]: _gl.REPEAT,
24539		[ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
24540		[ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
24541	};
24542
24543	const filterToGL = {
24544		[ NearestFilter ]: _gl.NEAREST,
24545		[ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
24546		[ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,
24547
24548		[ LinearFilter ]: _gl.LINEAR,
24549		[ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
24550		[ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
24551	};
24552
24553	const compareToGL = {
24554		[ NeverCompare ]: _gl.NEVER,
24555		[ AlwaysCompare ]: _gl.ALWAYS,
24556		[ LessCompare ]: _gl.LESS,
24557		[ LessEqualCompare ]: _gl.LEQUAL,
24558		[ EqualCompare ]: _gl.EQUAL,
24559		[ GreaterEqualCompare ]: _gl.GEQUAL,
24560		[ GreaterCompare ]: _gl.GREATER,
24561		[ NotEqualCompare ]: _gl.NOTEQUAL
24562	};
24563
24564	function setTextureParameters( textureType, texture, supportsMips ) {
24565
24566		if ( supportsMips ) {
24567
24568			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
24569			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );
24570
24571			if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24572
24573				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );
24574
24575			}
24576
24577			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
24578			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );
24579
24580		} else {
24581
24582			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
24583			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
24584
24585			if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24586
24587				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE );
24588
24589			}
24590
24591			if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
24592
24593				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
24594
24595			}
24596
24597			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
24598			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
24599
24600			if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
24601
24602				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
24603
24604			}
24605
24606		}
24607
24608		if ( texture.compareFunction ) {
24609
24610			_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE );
24611			_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );
24612
24613		}
24614
24615		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
24616
24617			const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
24618
24619			if ( texture.magFilter === NearestFilter ) return;
24620			if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;
24621			if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
24622			if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only
24623
24624			if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
24625
24626				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
24627				properties.get( texture ).__currentAnisotropy = texture.anisotropy;
24628
24629			}
24630
24631		}
24632
24633	}
24634
24635	function initTexture( textureProperties, texture ) {
24636
24637		let forceUpload = false;
24638
24639		if ( textureProperties.__webglInit === undefined ) {
24640
24641			textureProperties.__webglInit = true;
24642
24643			texture.addEventListener( 'dispose', onTextureDispose );
24644
24645		}
24646
24647		// create Source <-> WebGLTextures mapping if necessary
24648
24649		const source = texture.source;
24650		let webglTextures = _sources.get( source );
24651
24652		if ( webglTextures === undefined ) {
24653
24654			webglTextures = {};
24655			_sources.set( source, webglTextures );
24656
24657		}
24658
24659		// check if there is already a WebGLTexture object for the given texture parameters
24660
24661		const textureCacheKey = getTextureCacheKey( texture );
24662
24663		if ( textureCacheKey !== textureProperties.__cacheKey ) {
24664
24665			// if not, create a new instance of WebGLTexture
24666
24667			if ( webglTextures[ textureCacheKey ] === undefined ) {
24668
24669				// create new entry
24670
24671				webglTextures[ textureCacheKey ] = {
24672					texture: _gl.createTexture(),
24673					usedTimes: 0
24674				};
24675
24676				info.memory.textures ++;
24677
24678				// when a new instance of WebGLTexture was created, a texture upload is required
24679				// even if the image contents are identical
24680
24681				forceUpload = true;
24682
24683			}
24684
24685			webglTextures[ textureCacheKey ].usedTimes ++;
24686
24687			// every time the texture cache key changes, it's necessary to check if an instance of
24688			// WebGLTexture can be deleted in order to avoid a memory leak.
24689
24690			const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24691
24692			if ( webglTexture !== undefined ) {
24693
24694				webglTextures[ textureProperties.__cacheKey ].usedTimes --;
24695
24696				if ( webglTexture.usedTimes === 0 ) {
24697
24698					deleteTexture( texture );
24699
24700				}
24701
24702			}
24703
24704			// store references to cache key and WebGLTexture object
24705
24706			textureProperties.__cacheKey = textureCacheKey;
24707			textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;
24708
24709		}
24710
24711		return forceUpload;
24712
24713	}
24714
24715	function uploadTexture( textureProperties, texture, slot ) {
24716
24717		let textureType = _gl.TEXTURE_2D;
24718
24719		if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY;
24720		if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;
24721
24722		const forceUpload = initTexture( textureProperties, texture );
24723		const source = texture.source;
24724
24725		state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24726
24727		const sourceProperties = properties.get( source );
24728
24729		if ( source.version !== sourceProperties.__version || forceUpload === true ) {
24730
24731			state.activeTexture( _gl.TEXTURE0 + slot );
24732
24733			const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
24734			const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
24735			const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
24736
24737			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
24738			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
24739			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
24740			_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
24741
24742			const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false;
24743			let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize );
24744			image = verifyColorSpace( texture, image );
24745
24746			const supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
24747				glFormat = utils.convert( texture.format, texture.colorSpace );
24748
24749			let glType = utils.convert( texture.type ),
24750				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
24751
24752			setTextureParameters( textureType, texture, supportsMips );
24753
24754			let mipmap;
24755			const mipmaps = texture.mipmaps;
24756
24757			const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format );
24758			const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
24759			const levels = getMipLevels( texture, image, supportsMips );
24760
24761			if ( texture.isDepthTexture ) {
24762
24763				// populate depth texture with dummy data
24764
24765				glInternalFormat = _gl.DEPTH_COMPONENT;
24766
24767				if ( isWebGL2 ) {
24768
24769					if ( texture.type === FloatType ) {
24770
24771						glInternalFormat = _gl.DEPTH_COMPONENT32F;
24772
24773					} else if ( texture.type === UnsignedIntType ) {
24774
24775						glInternalFormat = _gl.DEPTH_COMPONENT24;
24776
24777					} else if ( texture.type === UnsignedInt248Type ) {
24778
24779						glInternalFormat = _gl.DEPTH24_STENCIL8;
24780
24781					} else {
24782
24783						glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D
24784
24785					}
24786
24787				} else {
24788
24789					if ( texture.type === FloatType ) {
24790
24791						console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
24792
24793					}
24794
24795				}
24796
24797				// validation checks for WebGL 1
24798
24799				if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24800
24801					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24802					// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
24803					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24804					if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
24805
24806						console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
24807
24808						texture.type = UnsignedIntType;
24809						glType = utils.convert( texture.type );
24810
24811					}
24812
24813				}
24814
24815				if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24816
24817					// Depth stencil textures need the DEPTH_STENCIL internal format
24818					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24819					glInternalFormat = _gl.DEPTH_STENCIL;
24820
24821					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24822					// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
24823					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24824					if ( texture.type !== UnsignedInt248Type ) {
24825
24826						console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
24827
24828						texture.type = UnsignedInt248Type;
24829						glType = utils.convert( texture.type );
24830
24831					}
24832
24833				}
24834
24835				//
24836
24837				if ( allocateMemory ) {
24838
24839					if ( useTexStorage ) {
24840
24841						state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );
24842
24843					} else {
24844
24845						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
24846
24847					}
24848
24849				}
24850
24851			} else if ( texture.isDataTexture ) {
24852
24853				// use manually created mipmaps if available
24854				// if there are no manual mipmaps
24855				// set 0 level mipmap and then use GL to generate other mipmap levels
24856
24857				if ( mipmaps.length > 0 && supportsMips ) {
24858
24859					if ( useTexStorage && allocateMemory ) {
24860
24861						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24862
24863					}
24864
24865					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24866
24867						mipmap = mipmaps[ i ];
24868
24869						if ( useTexStorage ) {
24870
24871							state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24872
24873						} else {
24874
24875							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24876
24877						}
24878
24879					}
24880
24881					texture.generateMipmaps = false;
24882
24883				} else {
24884
24885					if ( useTexStorage ) {
24886
24887						if ( allocateMemory ) {
24888
24889							state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
24890
24891						}
24892
24893						state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
24894
24895					} else {
24896
24897						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
24898
24899					}
24900
24901				}
24902
24903			} else if ( texture.isCompressedTexture ) {
24904
24905				if ( texture.isCompressedArrayTexture ) {
24906
24907					if ( useTexStorage && allocateMemory ) {
24908
24909						state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );
24910
24911					}
24912
24913					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24914
24915						mipmap = mipmaps[ i ];
24916
24917						if ( texture.format !== RGBAFormat ) {
24918
24919							if ( glFormat !== null ) {
24920
24921								if ( useTexStorage ) {
24922
24923									state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
24924
24925								} else {
24926
24927									state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );
24928
24929								}
24930
24931							} else {
24932
24933								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24934
24935							}
24936
24937						} else {
24938
24939							if ( useTexStorage ) {
24940
24941								state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );
24942
24943							} else {
24944
24945								state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );
24946
24947							}
24948
24949						}
24950
24951					}
24952
24953				} else {
24954
24955					if ( useTexStorage && allocateMemory ) {
24956
24957						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24958
24959					}
24960
24961					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24962
24963						mipmap = mipmaps[ i ];
24964
24965						if ( texture.format !== RGBAFormat ) {
24966
24967							if ( glFormat !== null ) {
24968
24969								if ( useTexStorage ) {
24970
24971									state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
24972
24973								} else {
24974
24975									state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24976
24977								}
24978
24979							} else {
24980
24981								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24982
24983							}
24984
24985						} else {
24986
24987							if ( useTexStorage ) {
24988
24989								state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24990
24991							} else {
24992
24993								state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24994
24995							}
24996
24997						}
24998
24999					}
25000
25001				}
25002
25003			} else if ( texture.isDataArrayTexture ) {
25004
25005				if ( useTexStorage ) {
25006
25007					if ( allocateMemory ) {
25008
25009						state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );
25010
25011					}
25012
25013					state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25014
25015				} else {
25016
25017					state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25018
25019				}
25020
25021			} else if ( texture.isData3DTexture ) {
25022
25023				if ( useTexStorage ) {
25024
25025					if ( allocateMemory ) {
25026
25027						state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );
25028
25029					}
25030
25031					state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25032
25033				} else {
25034
25035					state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25036
25037				}
25038
25039			} else if ( texture.isFramebufferTexture ) {
25040
25041				if ( allocateMemory ) {
25042
25043					if ( useTexStorage ) {
25044
25045						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25046
25047					} else {
25048
25049						let width = image.width, height = image.height;
25050
25051						for ( let i = 0; i < levels; i ++ ) {
25052
25053							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );
25054
25055							width >>= 1;
25056							height >>= 1;
25057
25058						}
25059
25060					}
25061
25062				}
25063
25064			} else {
25065
25066				// regular Texture (image, video, canvas)
25067
25068				// use manually created mipmaps if available
25069				// if there are no manual mipmaps
25070				// set 0 level mipmap and then use GL to generate other mipmap levels
25071
25072				if ( mipmaps.length > 0 && supportsMips ) {
25073
25074					if ( useTexStorage && allocateMemory ) {
25075
25076						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
25077
25078					}
25079
25080					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25081
25082						mipmap = mipmaps[ i ];
25083
25084						if ( useTexStorage ) {
25085
25086							state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );
25087
25088						} else {
25089
25090							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
25091
25092						}
25093
25094					}
25095
25096					texture.generateMipmaps = false;
25097
25098				} else {
25099
25100					if ( useTexStorage ) {
25101
25102						if ( allocateMemory ) {
25103
25104							state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25105
25106						}
25107
25108						state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );
25109
25110					} else {
25111
25112						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
25113
25114					}
25115
25116				}
25117
25118			}
25119
25120			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25121
25122				generateMipmap( textureType );
25123
25124			}
25125
25126			sourceProperties.__version = source.version;
25127
25128			if ( texture.onUpdate ) texture.onUpdate( texture );
25129
25130		}
25131
25132		textureProperties.__version = texture.version;
25133
25134	}
25135
25136	function uploadCubeTexture( textureProperties, texture, slot ) {
25137
25138		if ( texture.image.length !== 6 ) return;
25139
25140		const forceUpload = initTexture( textureProperties, texture );
25141		const source = texture.source;
25142
25143		state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
25144
25145		const sourceProperties = properties.get( source );
25146
25147		if ( source.version !== sourceProperties.__version || forceUpload === true ) {
25148
25149			state.activeTexture( _gl.TEXTURE0 + slot );
25150
25151			const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
25152			const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
25153			const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
25154
25155			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
25156			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
25157			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
25158			_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
25159
25160			const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );
25161			const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
25162
25163			const cubeImage = [];
25164
25165			for ( let i = 0; i < 6; i ++ ) {
25166
25167				if ( ! isCompressed && ! isDataTexture ) {
25168
25169					cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize );
25170
25171				} else {
25172
25173					cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
25174
25175				}
25176
25177				cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );
25178
25179			}
25180
25181			const image = cubeImage[ 0 ],
25182				supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
25183				glFormat = utils.convert( texture.format, texture.colorSpace ),
25184				glType = utils.convert( texture.type ),
25185				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25186
25187			const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true );
25188			const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
25189			let levels = getMipLevels( texture, image, supportsMips );
25190
25191			setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25192
25193			let mipmaps;
25194
25195			if ( isCompressed ) {
25196
25197				if ( useTexStorage && allocateMemory ) {
25198
25199					state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );
25200
25201				}
25202
25203				for ( let i = 0; i < 6; i ++ ) {
25204
25205					mipmaps = cubeImage[ i ].mipmaps;
25206
25207					for ( let j = 0; j < mipmaps.length; j ++ ) {
25208
25209						const mipmap = mipmaps[ j ];
25210
25211						if ( texture.format !== RGBAFormat ) {
25212
25213							if ( glFormat !== null ) {
25214
25215								if ( useTexStorage ) {
25216
25217									state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
25218
25219								} else {
25220
25221									state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
25222
25223								}
25224
25225							} else {
25226
25227								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
25228
25229							}
25230
25231						} else {
25232
25233							if ( useTexStorage ) {
25234
25235								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
25236
25237							} else {
25238
25239								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25240
25241							}
25242
25243						}
25244
25245					}
25246
25247				}
25248
25249			} else {
25250
25251				mipmaps = texture.mipmaps;
25252
25253				if ( useTexStorage && allocateMemory ) {
25254
25255					// TODO: Uniformly handle mipmap definitions
25256					// Normal textures and compressed cube textures define base level + mips with their mipmap array
25257					// Uncompressed cube textures use their mipmap array only for mips (no base level)
25258
25259					if ( mipmaps.length > 0 ) levels ++;
25260
25261					state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height );
25262
25263				}
25264
25265				for ( let i = 0; i < 6; i ++ ) {
25266
25267					if ( isDataTexture ) {
25268
25269						if ( useTexStorage ) {
25270
25271							state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );
25272
25273						} else {
25274
25275							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
25276
25277						}
25278
25279						for ( let j = 0; j < mipmaps.length; j ++ ) {
25280
25281							const mipmap = mipmaps[ j ];
25282							const mipmapImage = mipmap.image[ i ].image;
25283
25284							if ( useTexStorage ) {
25285
25286								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );
25287
25288							} else {
25289
25290								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
25291
25292							}
25293
25294						}
25295
25296					} else {
25297
25298						if ( useTexStorage ) {
25299
25300							state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );
25301
25302						} else {
25303
25304							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
25305
25306						}
25307
25308						for ( let j = 0; j < mipmaps.length; j ++ ) {
25309
25310							const mipmap = mipmaps[ j ];
25311
25312							if ( useTexStorage ) {
25313
25314								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );
25315
25316							} else {
25317
25318								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
25319
25320							}
25321
25322						}
25323
25324					}
25325
25326				}
25327
25328			}
25329
25330			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25331
25332				// We assume images for cube map have the same size.
25333				generateMipmap( _gl.TEXTURE_CUBE_MAP );
25334
25335			}
25336
25337			sourceProperties.__version = source.version;
25338
25339			if ( texture.onUpdate ) texture.onUpdate( texture );
25340
25341		}
25342
25343		textureProperties.__version = texture.version;
25344
25345	}
25346
25347	// Render targets
25348
25349	// Setup storage for target texture and bind it to correct framebuffer
25350	function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {
25351
25352		const glFormat = utils.convert( texture.format, texture.colorSpace );
25353		const glType = utils.convert( texture.type );
25354		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25355		const renderTargetProperties = properties.get( renderTarget );
25356
25357		if ( ! renderTargetProperties.__hasExternalTextures ) {
25358
25359			const width = Math.max( 1, renderTarget.width >> level );
25360			const height = Math.max( 1, renderTarget.height >> level );
25361
25362			if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
25363
25364				state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null );
25365
25366			} else {
25367
25368				state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null );
25369
25370			}
25371
25372		}
25373
25374		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25375
25376		if ( useMultisampledRTT( renderTarget ) ) {
25377
25378			multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
25379
25380		} else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753
25381
25382			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );
25383
25384		}
25385
25386		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25387
25388	}
25389
25390
25391	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
25392	function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
25393
25394		_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
25395
25396		if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
25397
25398			let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16;
25399
25400			if ( isMultisample || useMultisampledRTT( renderTarget ) ) {
25401
25402				const depthTexture = renderTarget.depthTexture;
25403
25404				if ( depthTexture && depthTexture.isDepthTexture ) {
25405
25406					if ( depthTexture.type === FloatType ) {
25407
25408						glInternalFormat = _gl.DEPTH_COMPONENT32F;
25409
25410					} else if ( depthTexture.type === UnsignedIntType ) {
25411
25412						glInternalFormat = _gl.DEPTH_COMPONENT24;
25413
25414					}
25415
25416				}
25417
25418				const samples = getRenderTargetSamples( renderTarget );
25419
25420				if ( useMultisampledRTT( renderTarget ) ) {
25421
25422					multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25423
25424				} else {
25425
25426					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25427
25428				}
25429
25430			} else {
25431
25432				_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25433
25434			}
25435
25436			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25437
25438		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
25439
25440			const samples = getRenderTargetSamples( renderTarget );
25441
25442			if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25443
25444				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25445
25446			} else if ( useMultisampledRTT( renderTarget ) ) {
25447
25448				multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25449
25450			} else {
25451
25452				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
25453
25454			}
25455
25456
25457			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25458
25459		} else {
25460
25461			const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25462
25463			for ( let i = 0; i < textures.length; i ++ ) {
25464
25465				const texture = textures[ i ];
25466
25467				const glFormat = utils.convert( texture.format, texture.colorSpace );
25468				const glType = utils.convert( texture.type );
25469				const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25470				const samples = getRenderTargetSamples( renderTarget );
25471
25472				if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25473
25474					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25475
25476				} else if ( useMultisampledRTT( renderTarget ) ) {
25477
25478					multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25479
25480				} else {
25481
25482					_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25483
25484				}
25485
25486			}
25487
25488		}
25489
25490		_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25491
25492	}
25493
25494	// Setup resources for a Depth Texture for a FBO (needs an extension)
25495	function setupDepthTexture( framebuffer, renderTarget ) {
25496
25497		const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
25498		if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
25499
25500		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25501
25502		if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
25503
25504			throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
25505
25506		}
25507
25508		// upload an empty depth texture with framebuffer size
25509		if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
25510				renderTarget.depthTexture.image.width !== renderTarget.width ||
25511				renderTarget.depthTexture.image.height !== renderTarget.height ) {
25512
25513			renderTarget.depthTexture.image.width = renderTarget.width;
25514			renderTarget.depthTexture.image.height = renderTarget.height;
25515			renderTarget.depthTexture.needsUpdate = true;
25516
25517		}
25518
25519		setTexture2D( renderTarget.depthTexture, 0 );
25520
25521		const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
25522		const samples = getRenderTargetSamples( renderTarget );
25523
25524		if ( renderTarget.depthTexture.format === DepthFormat ) {
25525
25526			if ( useMultisampledRTT( renderTarget ) ) {
25527
25528				multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25529
25530			} else {
25531
25532				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25533
25534			}
25535
25536		} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
25537
25538			if ( useMultisampledRTT( renderTarget ) ) {
25539
25540				multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25541
25542			} else {
25543
25544				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25545
25546			}
25547
25548		} else {
25549
25550			throw new Error( 'Unknown depthTexture format' );
25551
25552		}
25553
25554	}
25555
25556	// Setup GL resources for a non-texture depth buffer
25557	function setupDepthRenderbuffer( renderTarget ) {
25558
25559		const renderTargetProperties = properties.get( renderTarget );
25560		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25561
25562		if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {
25563
25564			if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
25565
25566			setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
25567
25568		} else {
25569
25570			if ( isCube ) {
25571
25572				renderTargetProperties.__webglDepthbuffer = [];
25573
25574				for ( let i = 0; i < 6; i ++ ) {
25575
25576					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
25577					renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
25578					setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
25579
25580				}
25581
25582			} else {
25583
25584
25585				state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25586				renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
25587				setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
25588
25589			}
25590
25591		}
25592
25593		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25594
25595	}
25596
25597	// rebind framebuffer with external textures
25598	function rebindTextures( renderTarget, colorTexture, depthTexture ) {
25599
25600		const renderTargetProperties = properties.get( renderTarget );
25601
25602		if ( colorTexture !== undefined ) {
25603
25604			setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );
25605
25606		}
25607
25608		if ( depthTexture !== undefined ) {
25609
25610			setupDepthRenderbuffer( renderTarget );
25611
25612		}
25613
25614	}
25615
25616	// Set up GL resources for the render target
25617	function setupRenderTarget( renderTarget ) {
25618
25619		const texture = renderTarget.texture;
25620
25621		const renderTargetProperties = properties.get( renderTarget );
25622		const textureProperties = properties.get( texture );
25623
25624		renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
25625
25626		if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
25627
25628			if ( textureProperties.__webglTexture === undefined ) {
25629
25630				textureProperties.__webglTexture = _gl.createTexture();
25631
25632			}
25633
25634			textureProperties.__version = texture.version;
25635			info.memory.textures ++;
25636
25637		}
25638
25639		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25640		const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25641		const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25642
25643		// Setup framebuffer
25644
25645		if ( isCube ) {
25646
25647			renderTargetProperties.__webglFramebuffer = [];
25648
25649			for ( let i = 0; i < 6; i ++ ) {
25650
25651				if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25652
25653					renderTargetProperties.__webglFramebuffer[ i ] = [];
25654
25655					for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25656
25657						renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer();
25658
25659					}
25660
25661				} else {
25662
25663					renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
25664
25665				}
25666
25667			}
25668
25669		} else {
25670
25671			if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25672
25673				renderTargetProperties.__webglFramebuffer = [];
25674
25675				for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25676
25677					renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer();
25678
25679				}
25680
25681			} else {
25682
25683				renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
25684
25685			}
25686
25687			if ( isMultipleRenderTargets ) {
25688
25689				if ( capabilities.drawBuffers ) {
25690
25691					const textures = renderTarget.texture;
25692
25693					for ( let i = 0, il = textures.length; i < il; i ++ ) {
25694
25695						const attachmentProperties = properties.get( textures[ i ] );
25696
25697						if ( attachmentProperties.__webglTexture === undefined ) {
25698
25699							attachmentProperties.__webglTexture = _gl.createTexture();
25700
25701							info.memory.textures ++;
25702
25703						}
25704
25705					}
25706
25707				} else {
25708
25709					console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' );
25710
25711				}
25712
25713			}
25714
25715			if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25716
25717				const textures = isMultipleRenderTargets ? texture : [ texture ];
25718
25719				renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
25720				renderTargetProperties.__webglColorRenderbuffer = [];
25721
25722				state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25723
25724				for ( let i = 0; i < textures.length; i ++ ) {
25725
25726					const texture = textures[ i ];
25727					renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer();
25728
25729					_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25730
25731					const glFormat = utils.convert( texture.format, texture.colorSpace );
25732					const glType = utils.convert( texture.type );
25733					const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
25734					const samples = getRenderTargetSamples( renderTarget );
25735					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25736
25737					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25738
25739				}
25740
25741				_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25742
25743				if ( renderTarget.depthBuffer ) {
25744
25745					renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
25746					setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
25747
25748				}
25749
25750				state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25751
25752			}
25753
25754		}
25755
25756		// Setup color buffer
25757
25758		if ( isCube ) {
25759
25760			state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
25761			setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25762
25763			for ( let i = 0; i < 6; i ++ ) {
25764
25765				if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25766
25767					for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25768
25769						setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );
25770
25771					}
25772
25773				} else {
25774
25775					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 );
25776
25777				}
25778
25779			}
25780
25781			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25782
25783				generateMipmap( _gl.TEXTURE_CUBE_MAP );
25784
25785			}
25786
25787			state.unbindTexture();
25788
25789		} else if ( isMultipleRenderTargets ) {
25790
25791			const textures = renderTarget.texture;
25792
25793			for ( let i = 0, il = textures.length; i < il; i ++ ) {
25794
25795				const attachment = textures[ i ];
25796				const attachmentProperties = properties.get( attachment );
25797
25798				state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );
25799				setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips );
25800				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );
25801
25802				if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) {
25803
25804					generateMipmap( _gl.TEXTURE_2D );
25805
25806				}
25807
25808			}
25809
25810			state.unbindTexture();
25811
25812		} else {
25813
25814			let glTextureType = _gl.TEXTURE_2D;
25815
25816			if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {
25817
25818				if ( isWebGL2 ) {
25819
25820					glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;
25821
25822				} else {
25823
25824					console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' );
25825
25826				}
25827
25828			}
25829
25830			state.bindTexture( glTextureType, textureProperties.__webglTexture );
25831			setTextureParameters( glTextureType, texture, supportsMips );
25832
25833			if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25834
25835				for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25836
25837					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level );
25838
25839				}
25840
25841			} else {
25842
25843				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );
25844
25845			}
25846
25847			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25848
25849				generateMipmap( glTextureType );
25850
25851			}
25852
25853			state.unbindTexture();
25854
25855		}
25856
25857		// Setup depth and stencil buffers
25858
25859		if ( renderTarget.depthBuffer ) {
25860
25861			setupDepthRenderbuffer( renderTarget );
25862
25863		}
25864
25865	}
25866
25867	function updateRenderTargetMipmap( renderTarget ) {
25868
25869		const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25870
25871		const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25872
25873		for ( let i = 0, il = textures.length; i < il; i ++ ) {
25874
25875			const texture = textures[ i ];
25876
25877			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25878
25879				const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
25880				const webglTexture = properties.get( texture ).__webglTexture;
25881
25882				state.bindTexture( target, webglTexture );
25883				generateMipmap( target );
25884				state.unbindTexture();
25885
25886			}
25887
25888		}
25889
25890	}
25891
25892	function updateMultisampleRenderTarget( renderTarget ) {
25893
25894		if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25895
25896			const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ];
25897			const width = renderTarget.width;
25898			const height = renderTarget.height;
25899			let mask = _gl.COLOR_BUFFER_BIT;
25900			const invalidationArray = [];
25901			const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
25902			const renderTargetProperties = properties.get( renderTarget );
25903			const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25904
25905			// If MRT we need to remove FBO attachments
25906			if ( isMultipleRenderTargets ) {
25907
25908				for ( let i = 0; i < textures.length; i ++ ) {
25909
25910					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25911					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );
25912
25913					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25914					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );
25915
25916				}
25917
25918			}
25919
25920			state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25921			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25922
25923			for ( let i = 0; i < textures.length; i ++ ) {
25924
25925				invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i );
25926
25927				if ( renderTarget.depthBuffer ) {
25928
25929					invalidationArray.push( depthStyle );
25930
25931				}
25932
25933				const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false;
25934
25935				if ( ignoreDepthValues === false ) {
25936
25937					if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
25938					if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
25939
25940				}
25941
25942				if ( isMultipleRenderTargets ) {
25943
25944					_gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25945
25946				}
25947
25948				if ( ignoreDepthValues === true ) {
25949
25950					_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] );
25951					_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
25952
25953				}
25954
25955				if ( isMultipleRenderTargets ) {
25956
25957					const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25958					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );
25959
25960				}
25961
25962				_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
25963
25964				if ( supportsInvalidateFramebuffer ) {
25965
25966					_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray );
25967
25968				}
25969
25970
25971			}
25972
25973			state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
25974			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );
25975
25976			// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments
25977			if ( isMultipleRenderTargets ) {
25978
25979				for ( let i = 0; i < textures.length; i ++ ) {
25980
25981					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25982					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25983
25984					const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25985
25986					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25987					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );
25988
25989				}
25990
25991			}
25992
25993			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25994
25995		}
25996
25997	}
25998
25999	function getRenderTargetSamples( renderTarget ) {
26000
26001		return Math.min( capabilities.maxSamples, renderTarget.samples );
26002
26003	}
26004
26005	function useMultisampledRTT( renderTarget ) {
26006
26007		const renderTargetProperties = properties.get( renderTarget );
26008
26009		return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;
26010
26011	}
26012
26013	function updateVideoTexture( texture ) {
26014
26015		const frame = info.render.frame;
26016
26017		// Check the last frame we updated the VideoTexture
26018
26019		if ( _videoTextures.get( texture ) !== frame ) {
26020
26021			_videoTextures.set( texture, frame );
26022			texture.update();
26023
26024		}
26025
26026	}
26027
26028	function verifyColorSpace( texture, image ) {
26029
26030		const colorSpace = texture.colorSpace;
26031		const format = texture.format;
26032		const type = texture.type;
26033
26034		if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
26035
26036		if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {
26037
26038			// sRGB
26039
26040			if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {
26041
26042				if ( isWebGL2 === false ) {
26043
26044					// in WebGL 1, try to use EXT_sRGB extension and unsized formats
26045
26046					if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) {
26047
26048						texture.format = _SRGBAFormat;
26049
26050						// it's not possible to generate mips in WebGL 1 with this extension
26051
26052						texture.minFilter = LinearFilter;
26053						texture.generateMipmaps = false;
26054
26055					} else {
26056
26057						// slow fallback (CPU decode)
26058
26059						image = ImageUtils.sRGBToLinear( image );
26060
26061					}
26062
26063				} else {
26064
26065					// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
26066
26067					if ( format !== RGBAFormat || type !== UnsignedByteType ) {
26068
26069						console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );
26070
26071					}
26072
26073				}
26074
26075			} else {
26076
26077				console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );
26078
26079			}
26080
26081		}
26082
26083		return image;
26084
26085	}
26086
26087	//
26088
26089	this.allocateTextureUnit = allocateTextureUnit;
26090	this.resetTextureUnits = resetTextureUnits;
26091
26092	this.setTexture2D = setTexture2D;
26093	this.setTexture2DArray = setTexture2DArray;
26094	this.setTexture3D = setTexture3D;
26095	this.setTextureCube = setTextureCube;
26096	this.rebindTextures = rebindTextures;
26097	this.setupRenderTarget = setupRenderTarget;
26098	this.updateRenderTargetMipmap = updateRenderTargetMipmap;
26099	this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
26100	this.setupDepthRenderbuffer = setupDepthRenderbuffer;
26101	this.setupFrameBufferTexture = setupFrameBufferTexture;
26102	this.useMultisampledRTT = useMultisampledRTT;
26103
26104}
26105
26106function WebGLUtils( gl, extensions, capabilities ) {
26107
26108	const isWebGL2 = capabilities.isWebGL2;
26109
26110	function convert( p, colorSpace = NoColorSpace ) {
26111
26112		let extension;
26113
26114		const transfer = ColorManagement.getTransfer( colorSpace );
26115
26116		if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
26117		if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
26118		if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
26119
26120		if ( p === ByteType ) return gl.BYTE;
26121		if ( p === ShortType ) return gl.SHORT;
26122		if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
26123		if ( p === IntType ) return gl.INT;
26124		if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
26125		if ( p === FloatType ) return gl.FLOAT;
26126
26127		if ( p === HalfFloatType ) {
26128
26129			if ( isWebGL2 ) return gl.HALF_FLOAT;
26130
26131			extension = extensions.get( 'OES_texture_half_float' );
26132
26133			if ( extension !== null ) {
26134
26135				return extension.HALF_FLOAT_OES;
26136
26137			} else {
26138
26139				return null;
26140
26141			}
26142
26143		}
26144
26145		if ( p === AlphaFormat ) return gl.ALPHA;
26146		if ( p === RGBAFormat ) return gl.RGBA;
26147		if ( p === LuminanceFormat ) return gl.LUMINANCE;
26148		if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
26149		if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
26150		if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
26151
26152		// WebGL 1 sRGB fallback
26153
26154		if ( p === _SRGBAFormat ) {
26155
26156			extension = extensions.get( 'EXT_sRGB' );
26157
26158			if ( extension !== null ) {
26159
26160				return extension.SRGB_ALPHA_EXT;
26161
26162			} else {
26163
26164				return null;
26165
26166			}
26167
26168		}
26169
26170		// WebGL2 formats.
26171
26172		if ( p === RedFormat ) return gl.RED;
26173		if ( p === RedIntegerFormat ) return gl.RED_INTEGER;
26174		if ( p === RGFormat ) return gl.RG;
26175		if ( p === RGIntegerFormat ) return gl.RG_INTEGER;
26176		if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;
26177
26178		// S3TC
26179
26180		if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
26181
26182			if ( transfer === SRGBTransfer ) {
26183
26184				extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
26185
26186				if ( extension !== null ) {
26187
26188					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
26189					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
26190					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
26191					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
26192
26193				} else {
26194
26195					return null;
26196
26197				}
26198
26199			} else {
26200
26201				extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
26202
26203				if ( extension !== null ) {
26204
26205					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
26206					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
26207					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
26208					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
26209
26210				} else {
26211
26212					return null;
26213
26214				}
26215
26216			}
26217
26218		}
26219
26220		// PVRTC
26221
26222		if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
26223
26224			extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
26225
26226			if ( extension !== null ) {
26227
26228				if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
26229				if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
26230				if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
26231				if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
26232
26233			} else {
26234
26235				return null;
26236
26237			}
26238
26239		}
26240
26241		// ETC1
26242
26243		if ( p === RGB_ETC1_Format ) {
26244
26245			extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
26246
26247			if ( extension !== null ) {
26248
26249				return extension.COMPRESSED_RGB_ETC1_WEBGL;
26250
26251			} else {
26252
26253				return null;
26254
26255			}
26256
26257		}
26258
26259		// ETC2
26260
26261		if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
26262
26263			extension = extensions.get( 'WEBGL_compressed_texture_etc' );
26264
26265			if ( extension !== null ) {
26266
26267				if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
26268				if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
26269
26270			} else {
26271
26272				return null;
26273
26274			}
26275
26276		}
26277
26278		// ASTC
26279
26280		if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
26281			p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
26282			p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
26283			p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
26284			p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {
26285
26286			extension = extensions.get( 'WEBGL_compressed_texture_astc' );
26287
26288			if ( extension !== null ) {
26289
26290				if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
26291				if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
26292				if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
26293				if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
26294				if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
26295				if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
26296				if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
26297				if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
26298				if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
26299				if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
26300				if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
26301				if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
26302				if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
26303				if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
26304
26305			} else {
26306
26307				return null;
26308
26309			}
26310
26311		}
26312
26313		// BPTC
26314
26315		if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {
26316
26317			extension = extensions.get( 'EXT_texture_compression_bptc' );
26318
26319			if ( extension !== null ) {
26320
26321				if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
26322				if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
26323				if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
26324
26325			} else {
26326
26327				return null;
26328
26329			}
26330
26331		}
26332
26333		// RGTC
26334
26335		if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) {
26336
26337			extension = extensions.get( 'EXT_texture_compression_rgtc' );
26338
26339			if ( extension !== null ) {
26340
26341				if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;
26342				if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;
26343				if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;
26344				if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
26345
26346			} else {
26347
26348				return null;
26349
26350			}
26351
26352		}
26353
26354		//
26355
26356		if ( p === UnsignedInt248Type ) {
26357
26358			if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8;
26359
26360			extension = extensions.get( 'WEBGL_depth_texture' );
26361
26362			if ( extension !== null ) {
26363
26364				return extension.UNSIGNED_INT_24_8_WEBGL;
26365
26366			} else {
26367
26368				return null;
26369
26370			}
26371
26372		}
26373
26374		// if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)
26375
26376		return ( gl[ p ] !== undefined ) ? gl[ p ] : null;
26377
26378	}
26379
26380	return { convert: convert };
26381
26382}
26383
26384class ArrayCamera extends PerspectiveCamera {
26385
26386	constructor( array = [] ) {
26387
26388		super();
26389
26390		this.isArrayCamera = true;
26391
26392		this.cameras = array;
26393
26394	}
26395
26396}
26397
26398class Group extends Object3D {
26399
26400	constructor() {
26401
26402		super();
26403
26404		this.isGroup = true;
26405
26406		this.type = 'Group';
26407
26408	}
26409
26410}
26411
26412const _moveEvent = { type: 'move' };
26413
26414class WebXRController {
26415
26416	constructor() {
26417
26418		this._targetRay = null;
26419		this._grip = null;
26420		this._hand = null;
26421
26422	}
26423
26424	getHandSpace() {
26425
26426		if ( this._hand === null ) {
26427
26428			this._hand = new Group();
26429			this._hand.matrixAutoUpdate = false;
26430			this._hand.visible = false;
26431
26432			this._hand.joints = {};
26433			this._hand.inputState = { pinching: false };
26434
26435		}
26436
26437		return this._hand;
26438
26439	}
26440
26441	getTargetRaySpace() {
26442
26443		if ( this._targetRay === null ) {
26444
26445			this._targetRay = new Group();
26446			this._targetRay.matrixAutoUpdate = false;
26447			this._targetRay.visible = false;
26448			this._targetRay.hasLinearVelocity = false;
26449			this._targetRay.linearVelocity = new Vector3();
26450			this._targetRay.hasAngularVelocity = false;
26451			this._targetRay.angularVelocity = new Vector3();
26452
26453		}
26454
26455		return this._targetRay;
26456
26457	}
26458
26459	getGripSpace() {
26460
26461		if ( this._grip === null ) {
26462
26463			this._grip = new Group();
26464			this._grip.matrixAutoUpdate = false;
26465			this._grip.visible = false;
26466			this._grip.hasLinearVelocity = false;
26467			this._grip.linearVelocity = new Vector3();
26468			this._grip.hasAngularVelocity = false;
26469			this._grip.angularVelocity = new Vector3();
26470
26471		}
26472
26473		return this._grip;
26474
26475	}
26476
26477	dispatchEvent( event ) {
26478
26479		if ( this._targetRay !== null ) {
26480
26481			this._targetRay.dispatchEvent( event );
26482
26483		}
26484
26485		if ( this._grip !== null ) {
26486
26487			this._grip.dispatchEvent( event );
26488
26489		}
26490
26491		if ( this._hand !== null ) {
26492
26493			this._hand.dispatchEvent( event );
26494
26495		}
26496
26497		return this;
26498
26499	}
26500
26501	connect( inputSource ) {
26502
26503		if ( inputSource && inputSource.hand ) {
26504
26505			const hand = this._hand;
26506
26507			if ( hand ) {
26508
26509				for ( const inputjoint of inputSource.hand.values() ) {
26510
26511					// Initialize hand with joints when connected
26512					this._getHandJoint( hand, inputjoint );
26513
26514				}
26515
26516			}
26517
26518		}
26519
26520		this.dispatchEvent( { type: 'connected', data: inputSource } );
26521
26522		return this;
26523
26524	}
26525
26526	disconnect( inputSource ) {
26527
26528		this.dispatchEvent( { type: 'disconnected', data: inputSource } );
26529
26530		if ( this._targetRay !== null ) {
26531
26532			this._targetRay.visible = false;
26533
26534		}
26535
26536		if ( this._grip !== null ) {
26537
26538			this._grip.visible = false;
26539
26540		}
26541
26542		if ( this._hand !== null ) {
26543
26544			this._hand.visible = false;
26545
26546		}
26547
26548		return this;
26549
26550	}
26551
26552	update( inputSource, frame, referenceSpace ) {
26553
26554		let inputPose = null;
26555		let gripPose = null;
26556		let handPose = null;
26557
26558		const targetRay = this._targetRay;
26559		const grip = this._grip;
26560		const hand = this._hand;
26561
26562		if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
26563
26564			if ( hand && inputSource.hand ) {
26565
26566				handPose = true;
26567
26568				for ( const inputjoint of inputSource.hand.values() ) {
26569
26570					// Update the joints groups with the XRJoint poses
26571					const jointPose = frame.getJointPose( inputjoint, referenceSpace );
26572
26573					// The transform of this joint will be updated with the joint pose on each frame
26574					const joint = this._getHandJoint( hand, inputjoint );
26575
26576					if ( jointPose !== null ) {
26577
26578						joint.matrix.fromArray( jointPose.transform.matrix );
26579						joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
26580						joint.matrixWorldNeedsUpdate = true;
26581						joint.jointRadius = jointPose.radius;
26582
26583					}
26584
26585					joint.visible = jointPose !== null;
26586
26587				}
26588
26589				// Custom events
26590
26591				// Check pinchz
26592				const indexTip = hand.joints[ 'index-finger-tip' ];
26593				const thumbTip = hand.joints[ 'thumb-tip' ];
26594				const distance = indexTip.position.distanceTo( thumbTip.position );
26595
26596				const distanceToPinch = 0.02;
26597				const threshold = 0.005;
26598
26599
26600				if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
26601
26602					hand.inputState.pinching = false;
26603					this.dispatchEvent( {
26604						type: 'pinchend',
26605						handedness: inputSource.handedness,
26606						target: this
26607					} );
26608
26609				} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
26610
26611					hand.inputState.pinching = true;
26612					this.dispatchEvent( {
26613						type: 'pinchstart',
26614						handedness: inputSource.handedness,
26615						target: this
26616					} );
26617
26618				}
26619
26620			} else {
26621
26622				if ( grip !== null && inputSource.gripSpace ) {
26623
26624					gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
26625
26626					if ( gripPose !== null ) {
26627
26628						grip.matrix.fromArray( gripPose.transform.matrix );
26629						grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
26630						grip.matrixWorldNeedsUpdate = true;
26631
26632						if ( gripPose.linearVelocity ) {
26633
26634							grip.hasLinearVelocity = true;
26635							grip.linearVelocity.copy( gripPose.linearVelocity );
26636
26637						} else {
26638
26639							grip.hasLinearVelocity = false;
26640
26641						}
26642
26643						if ( gripPose.angularVelocity ) {
26644
26645							grip.hasAngularVelocity = true;
26646							grip.angularVelocity.copy( gripPose.angularVelocity );
26647
26648						} else {
26649
26650							grip.hasAngularVelocity = false;
26651
26652						}
26653
26654					}
26655
26656				}
26657
26658			}
26659
26660			if ( targetRay !== null ) {
26661
26662				inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
26663
26664				// Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it
26665				if ( inputPose === null && gripPose !== null ) {
26666
26667					inputPose = gripPose;
26668
26669				}
26670
26671				if ( inputPose !== null ) {
26672
26673					targetRay.matrix.fromArray( inputPose.transform.matrix );
26674					targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
26675					targetRay.matrixWorldNeedsUpdate = true;
26676
26677					if ( inputPose.linearVelocity ) {
26678
26679						targetRay.hasLinearVelocity = true;
26680						targetRay.linearVelocity.copy( inputPose.linearVelocity );
26681
26682					} else {
26683
26684						targetRay.hasLinearVelocity = false;
26685
26686					}
26687
26688					if ( inputPose.angularVelocity ) {
26689
26690						targetRay.hasAngularVelocity = true;
26691						targetRay.angularVelocity.copy( inputPose.angularVelocity );
26692
26693					} else {
26694
26695						targetRay.hasAngularVelocity = false;
26696
26697					}
26698
26699					this.dispatchEvent( _moveEvent );
26700
26701				}
26702
26703			}
26704
26705
26706		}
26707
26708		if ( targetRay !== null ) {
26709
26710			targetRay.visible = ( inputPose !== null );
26711
26712		}
26713
26714		if ( grip !== null ) {
26715
26716			grip.visible = ( gripPose !== null );
26717
26718		}
26719
26720		if ( hand !== null ) {
26721
26722			hand.visible = ( handPose !== null );
26723
26724		}
26725
26726		return this;
26727
26728	}
26729
26730	// private method
26731
26732	_getHandJoint( hand, inputjoint ) {
26733
26734		if ( hand.joints[ inputjoint.jointName ] === undefined ) {
26735
26736			const joint = new Group();
26737			joint.matrixAutoUpdate = false;
26738			joint.visible = false;
26739			hand.joints[ inputjoint.jointName ] = joint;
26740
26741			hand.add( joint );
26742
26743		}
26744
26745		return hand.joints[ inputjoint.jointName ];
26746
26747	}
26748
26749}
26750
26751class WebXRManager extends EventDispatcher {
26752
26753	constructor( renderer, gl ) {
26754
26755		super();
26756
26757		const scope = this;
26758
26759		let session = null;
26760
26761		let framebufferScaleFactor = 1.0;
26762
26763		let referenceSpace = null;
26764		let referenceSpaceType = 'local-floor';
26765		// Set default foveation to maximum.
26766		let foveation = 1.0;
26767		let customReferenceSpace = null;
26768
26769		let pose = null;
26770		let glBinding = null;
26771		let glProjLayer = null;
26772		let glBaseLayer = null;
26773		let xrFrame = null;
26774		const attributes = gl.getContextAttributes();
26775		let initialRenderTarget = null;
26776		let newRenderTarget = null;
26777
26778		const controllers = [];
26779		const controllerInputSources = [];
26780
26781		const currentSize = new Vector2();
26782		let currentPixelRatio = null;
26783
26784		//
26785
26786		const cameraL = new PerspectiveCamera();
26787		cameraL.layers.enable( 1 );
26788		cameraL.viewport = new Vector4();
26789
26790		const cameraR = new PerspectiveCamera();
26791		cameraR.layers.enable( 2 );
26792		cameraR.viewport = new Vector4();
26793
26794		const cameras = [ cameraL, cameraR ];
26795
26796		const cameraXR = new ArrayCamera();
26797		cameraXR.layers.enable( 1 );
26798		cameraXR.layers.enable( 2 );
26799
26800		let _currentDepthNear = null;
26801		let _currentDepthFar = null;
26802
26803		//
26804
26805		this.cameraAutoUpdate = true;
26806		this.enabled = false;
26807
26808		this.isPresenting = false;
26809
26810		this.getController = function ( index ) {
26811
26812			let controller = controllers[ index ];
26813
26814			if ( controller === undefined ) {
26815
26816				controller = new WebXRController();
26817				controllers[ index ] = controller;
26818
26819			}
26820
26821			return controller.getTargetRaySpace();
26822
26823		};
26824
26825		this.getControllerGrip = function ( index ) {
26826
26827			let controller = controllers[ index ];
26828
26829			if ( controller === undefined ) {
26830
26831				controller = new WebXRController();
26832				controllers[ index ] = controller;
26833
26834			}
26835
26836			return controller.getGripSpace();
26837
26838		};
26839
26840		this.getHand = function ( index ) {
26841
26842			let controller = controllers[ index ];
26843
26844			if ( controller === undefined ) {
26845
26846				controller = new WebXRController();
26847				controllers[ index ] = controller;
26848
26849			}
26850
26851			return controller.getHandSpace();
26852
26853		};
26854
26855		//
26856
26857		function onSessionEvent( event ) {
26858
26859			const controllerIndex = controllerInputSources.indexOf( event.inputSource );
26860
26861			if ( controllerIndex === - 1 ) {
26862
26863				return;
26864
26865			}
26866
26867			const controller = controllers[ controllerIndex ];
26868
26869			if ( controller !== undefined ) {
26870
26871				controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );
26872				controller.dispatchEvent( { type: event.type, data: event.inputSource } );
26873
26874			}
26875
26876		}
26877
26878		function onSessionEnd() {
26879
26880			session.removeEventListener( 'select', onSessionEvent );
26881			session.removeEventListener( 'selectstart', onSessionEvent );
26882			session.removeEventListener( 'selectend', onSessionEvent );
26883			session.removeEventListener( 'squeeze', onSessionEvent );
26884			session.removeEventListener( 'squeezestart', onSessionEvent );
26885			session.removeEventListener( 'squeezeend', onSessionEvent );
26886			session.removeEventListener( 'end', onSessionEnd );
26887			session.removeEventListener( 'inputsourceschange', onInputSourcesChange );
26888
26889			for ( let i = 0; i < controllers.length; i ++ ) {
26890
26891				const inputSource = controllerInputSources[ i ];
26892
26893				if ( inputSource === null ) continue;
26894
26895				controllerInputSources[ i ] = null;
26896
26897				controllers[ i ].disconnect( inputSource );
26898
26899			}
26900
26901			_currentDepthNear = null;
26902			_currentDepthFar = null;
26903
26904			// restore framebuffer/rendering state
26905
26906			renderer.setRenderTarget( initialRenderTarget );
26907
26908			glBaseLayer = null;
26909			glProjLayer = null;
26910			glBinding = null;
26911			session = null;
26912			newRenderTarget = null;
26913
26914			//
26915
26916			animation.stop();
26917
26918			scope.isPresenting = false;
26919
26920			renderer.setPixelRatio( currentPixelRatio );
26921			renderer.setSize( currentSize.width, currentSize.height, false );
26922
26923			scope.dispatchEvent( { type: 'sessionend' } );
26924
26925		}
26926
26927		this.setFramebufferScaleFactor = function ( value ) {
26928
26929			framebufferScaleFactor = value;
26930
26931			if ( scope.isPresenting === true ) {
26932
26933				console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
26934
26935			}
26936
26937		};
26938
26939		this.setReferenceSpaceType = function ( value ) {
26940
26941			referenceSpaceType = value;
26942
26943			if ( scope.isPresenting === true ) {
26944
26945				console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
26946
26947			}
26948
26949		};
26950
26951		this.getReferenceSpace = function () {
26952
26953			return customReferenceSpace || referenceSpace;
26954
26955		};
26956
26957		this.setReferenceSpace = function ( space ) {
26958
26959			customReferenceSpace = space;
26960
26961		};
26962
26963		this.getBaseLayer = function () {
26964
26965			return glProjLayer !== null ? glProjLayer : glBaseLayer;
26966
26967		};
26968
26969		this.getBinding = function () {
26970
26971			return glBinding;
26972
26973		};
26974
26975		this.getFrame = function () {
26976
26977			return xrFrame;
26978
26979		};
26980
26981		this.getSession = function () {
26982
26983			return session;
26984
26985		};
26986
26987		this.setSession = async function ( value ) {
26988
26989			session = value;
26990
26991			if ( session !== null ) {
26992
26993				initialRenderTarget = renderer.getRenderTarget();
26994
26995				session.addEventListener( 'select', onSessionEvent );
26996				session.addEventListener( 'selectstart', onSessionEvent );
26997				session.addEventListener( 'selectend', onSessionEvent );
26998				session.addEventListener( 'squeeze', onSessionEvent );
26999				session.addEventListener( 'squeezestart', onSessionEvent );
27000				session.addEventListener( 'squeezeend', onSessionEvent );
27001				session.addEventListener( 'end', onSessionEnd );
27002				session.addEventListener( 'inputsourceschange', onInputSourcesChange );
27003
27004				if ( attributes.xrCompatible !== true ) {
27005
27006					await gl.makeXRCompatible();
27007
27008				}
27009
27010				currentPixelRatio = renderer.getPixelRatio();
27011				renderer.getSize( currentSize );
27012
27013				if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) {
27014
27015					const layerInit = {
27016						antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true,
27017						alpha: true,
27018						depth: attributes.depth,
27019						stencil: attributes.stencil,
27020						framebufferScaleFactor: framebufferScaleFactor
27021					};
27022
27023					glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
27024
27025					session.updateRenderState( { baseLayer: glBaseLayer } );
27026
27027					renderer.setPixelRatio( 1 );
27028					renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );
27029
27030					newRenderTarget = new WebGLRenderTarget(
27031						glBaseLayer.framebufferWidth,
27032						glBaseLayer.framebufferHeight,
27033						{
27034							format: RGBAFormat,
27035							type: UnsignedByteType,
27036							colorSpace: renderer.outputColorSpace,
27037							stencilBuffer: attributes.stencil
27038						}
27039					);
27040
27041				} else {
27042
27043					let depthFormat = null;
27044					let depthType = null;
27045					let glDepthFormat = null;
27046
27047					if ( attributes.depth ) {
27048
27049						glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
27050						depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;
27051						depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType;
27052
27053					}
27054
27055					const projectionlayerInit = {
27056						colorFormat: gl.RGBA8,
27057						depthFormat: glDepthFormat,
27058						scaleFactor: framebufferScaleFactor
27059					};
27060
27061					glBinding = new XRWebGLBinding( session, gl );
27062
27063					glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
27064
27065					session.updateRenderState( { layers: [ glProjLayer ] } );
27066
27067					renderer.setPixelRatio( 1 );
27068					renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );
27069
27070					newRenderTarget = new WebGLRenderTarget(
27071						glProjLayer.textureWidth,
27072						glProjLayer.textureHeight,
27073						{
27074							format: RGBAFormat,
27075							type: UnsignedByteType,
27076							depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
27077							stencilBuffer: attributes.stencil,
27078							colorSpace: renderer.outputColorSpace,
27079							samples: attributes.antialias ? 4 : 0
27080						} );
27081
27082					const renderTargetProperties = renderer.properties.get( newRenderTarget );
27083					renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues;
27084
27085				}
27086
27087				newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278
27088
27089				this.setFoveation( foveation );
27090
27091				customReferenceSpace = null;
27092				referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
27093
27094				animation.setContext( session );
27095				animation.start();
27096
27097				scope.isPresenting = true;
27098
27099				scope.dispatchEvent( { type: 'sessionstart' } );
27100
27101			}
27102
27103		};
27104
27105		this.getEnvironmentBlendMode = function () {
27106
27107			if ( session !== null ) {
27108
27109				return session.environmentBlendMode;
27110
27111			}
27112
27113		};
27114
27115		function onInputSourcesChange( event ) {
27116
27117			// Notify disconnected
27118
27119			for ( let i = 0; i < event.removed.length; i ++ ) {
27120
27121				const inputSource = event.removed[ i ];
27122				const index = controllerInputSources.indexOf( inputSource );
27123
27124				if ( index >= 0 ) {
27125
27126					controllerInputSources[ index ] = null;
27127					controllers[ index ].disconnect( inputSource );
27128
27129				}
27130
27131			}
27132
27133			// Notify connected
27134
27135			for ( let i = 0; i < event.added.length; i ++ ) {
27136
27137				const inputSource = event.added[ i ];
27138
27139				let controllerIndex = controllerInputSources.indexOf( inputSource );
27140
27141				if ( controllerIndex === - 1 ) {
27142
27143					// Assign input source a controller that currently has no input source
27144
27145					for ( let i = 0; i < controllers.length; i ++ ) {
27146
27147						if ( i >= controllerInputSources.length ) {
27148
27149							controllerInputSources.push( inputSource );
27150							controllerIndex = i;
27151							break;
27152
27153						} else if ( controllerInputSources[ i ] === null ) {
27154
27155							controllerInputSources[ i ] = inputSource;
27156							controllerIndex = i;
27157							break;
27158
27159						}
27160
27161					}
27162
27163					// If all controllers do currently receive input we ignore new ones
27164
27165					if ( controllerIndex === - 1 ) break;
27166
27167				}
27168
27169				const controller = controllers[ controllerIndex ];
27170
27171				if ( controller ) {
27172
27173					controller.connect( inputSource );
27174
27175				}
27176
27177			}
27178
27179		}
27180
27181		//
27182
27183		const cameraLPos = new Vector3();
27184		const cameraRPos = new Vector3();
27185
27186		/**
27187		 * Assumes 2 cameras that are parallel and share an X-axis, and that
27188		 * the cameras' projection and world matrices have already been set.
27189		 * And that near and far planes are identical for both cameras.
27190		 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
27191		 */
27192		function setProjectionFromUnion( camera, cameraL, cameraR ) {
27193
27194			cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
27195			cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
27196
27197			const ipd = cameraLPos.distanceTo( cameraRPos );
27198
27199			const projL = cameraL.projectionMatrix.elements;
27200			const projR = cameraR.projectionMatrix.elements;
27201
27202			// VR systems will have identical far and near planes, and
27203			// most likely identical top and bottom frustum extents.
27204			// Use the left camera for these values.
27205			const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
27206			const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
27207			const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
27208			const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
27209
27210			const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
27211			const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
27212			const left = near * leftFov;
27213			const right = near * rightFov;
27214
27215			// Calculate the new camera's position offset from the
27216			// left camera. xOffset should be roughly half `ipd`.
27217			const zOffset = ipd / ( - leftFov + rightFov );
27218			const xOffset = zOffset * - leftFov;
27219
27220			// TODO: Better way to apply this offset?
27221			cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
27222			camera.translateX( xOffset );
27223			camera.translateZ( zOffset );
27224			camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
27225			camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27226
27227			// Find the union of the frustum values of the cameras and scale
27228			// the values so that the near plane's position does not change in world space,
27229			// although must now be relative to the new union camera.
27230			const near2 = near + zOffset;
27231			const far2 = far + zOffset;
27232			const left2 = left - xOffset;
27233			const right2 = right + ( ipd - xOffset );
27234			const top2 = topFov * far / far2 * near2;
27235			const bottom2 = bottomFov * far / far2 * near2;
27236
27237			camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
27238			camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27239
27240		}
27241
27242		function updateCamera( camera, parent ) {
27243
27244			if ( parent === null ) {
27245
27246				camera.matrixWorld.copy( camera.matrix );
27247
27248			} else {
27249
27250				camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
27251
27252			}
27253
27254			camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27255
27256		}
27257
27258		this.updateCamera = function ( camera ) {
27259
27260			if ( session === null ) return;
27261
27262			cameraXR.near = cameraR.near = cameraL.near = camera.near;
27263			cameraXR.far = cameraR.far = cameraL.far = camera.far;
27264
27265			if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {
27266
27267				// Note that the new renderState won't apply until the next frame. See #18320
27268
27269				session.updateRenderState( {
27270					depthNear: cameraXR.near,
27271					depthFar: cameraXR.far
27272				} );
27273
27274				_currentDepthNear = cameraXR.near;
27275				_currentDepthFar = cameraXR.far;
27276
27277			}
27278
27279			const parent = camera.parent;
27280			const cameras = cameraXR.cameras;
27281
27282			updateCamera( cameraXR, parent );
27283
27284			for ( let i = 0; i < cameras.length; i ++ ) {
27285
27286				updateCamera( cameras[ i ], parent );
27287
27288			}
27289
27290			// update projection matrix for proper view frustum culling
27291
27292			if ( cameras.length === 2 ) {
27293
27294				setProjectionFromUnion( cameraXR, cameraL, cameraR );
27295
27296			} else {
27297
27298				// assume single camera setup (AR)
27299
27300				cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );
27301
27302			}
27303
27304			// update user camera and its children
27305
27306			updateUserCamera( camera, cameraXR, parent );
27307
27308		};
27309
27310		function updateUserCamera( camera, cameraXR, parent ) {
27311
27312			if ( parent === null ) {
27313
27314				camera.matrix.copy( cameraXR.matrixWorld );
27315
27316			} else {
27317
27318				camera.matrix.copy( parent.matrixWorld );
27319				camera.matrix.invert();
27320				camera.matrix.multiply( cameraXR.matrixWorld );
27321
27322			}
27323
27324			camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27325			camera.updateMatrixWorld( true );
27326
27327			camera.projectionMatrix.copy( cameraXR.projectionMatrix );
27328			camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
27329
27330			if ( camera.isPerspectiveCamera ) {
27331
27332				camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
27333				camera.zoom = 1;
27334
27335			}
27336
27337		}
27338
27339		this.getCamera = function () {
27340
27341			return cameraXR;
27342
27343		};
27344
27345		this.getFoveation = function () {
27346
27347			if ( glProjLayer === null && glBaseLayer === null ) {
27348
27349				return undefined;
27350
27351			}
27352
27353			return foveation;
27354
27355		};
27356
27357		this.setFoveation = function ( value ) {
27358
27359			// 0 = no foveation = full resolution
27360			// 1 = maximum foveation = the edges render at lower resolution
27361
27362			foveation = value;
27363
27364			if ( glProjLayer !== null ) {
27365
27366				glProjLayer.fixedFoveation = value;
27367
27368			}
27369
27370			if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {
27371
27372				glBaseLayer.fixedFoveation = value;
27373
27374			}
27375
27376		};
27377
27378		// Animation Loop
27379
27380		let onAnimationFrameCallback = null;
27381
27382		function onAnimationFrame( time, frame ) {
27383
27384			pose = frame.getViewerPose( customReferenceSpace || referenceSpace );
27385			xrFrame = frame;
27386
27387			if ( pose !== null ) {
27388
27389				const views = pose.views;
27390
27391				if ( glBaseLayer !== null ) {
27392
27393					renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
27394					renderer.setRenderTarget( newRenderTarget );
27395
27396				}
27397
27398				let cameraXRNeedsUpdate = false;
27399
27400				// check if it's necessary to rebuild cameraXR's camera list
27401
27402				if ( views.length !== cameraXR.cameras.length ) {
27403
27404					cameraXR.cameras.length = 0;
27405					cameraXRNeedsUpdate = true;
27406
27407				}
27408
27409				for ( let i = 0; i < views.length; i ++ ) {
27410
27411					const view = views[ i ];
27412
27413					let viewport = null;
27414
27415					if ( glBaseLayer !== null ) {
27416
27417						viewport = glBaseLayer.getViewport( view );
27418
27419					} else {
27420
27421						const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
27422						viewport = glSubImage.viewport;
27423
27424						// For side-by-side projection, we only produce a single texture for both eyes.
27425						if ( i === 0 ) {
27426
27427							renderer.setRenderTargetTextures(
27428								newRenderTarget,
27429								glSubImage.colorTexture,
27430								glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );
27431
27432							renderer.setRenderTarget( newRenderTarget );
27433
27434						}
27435
27436					}
27437
vendor: 6,492 bytes, lines 27438-27723
27438					let camera = cameras[ i ];
27439
27440					if ( camera === undefined ) {
27441
27442						camera = new PerspectiveCamera();
27443						camera.layers.enable( i );
27444						camera.viewport = new Vector4();
27445						cameras[ i ] = camera;
27446
27447					}
27448
27449					camera.matrix.fromArray( view.transform.matrix );
27450					camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27451					camera.projectionMatrix.fromArray( view.projectionMatrix );
27452					camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27453					camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
27454
27455					if ( i === 0 ) {
27456
27457						cameraXR.matrix.copy( camera.matrix );
27458						cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );
27459
27460					}
27461
27462					if ( cameraXRNeedsUpdate === true ) {
27463
27464						cameraXR.cameras.push( camera );
27465
27466					}
27467
27468				}
27469
27470			}
27471
27472			//
27473
27474			for ( let i = 0; i < controllers.length; i ++ ) {
27475
27476				const inputSource = controllerInputSources[ i ];
27477				const controller = controllers[ i ];
27478
27479				if ( inputSource !== null && controller !== undefined ) {
27480
27481					controller.update( inputSource, frame, customReferenceSpace || referenceSpace );
27482
27483				}
27484
27485			}
27486
27487			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
27488
27489			if ( frame.detectedPlanes ) {
27490
27491				scope.dispatchEvent( { type: 'planesdetected', data: frame } );
27492
27493			}
27494
27495			xrFrame = null;
27496
27497		}
27498
27499		const animation = new WebGLAnimation();
27500
27501		animation.setAnimationLoop( onAnimationFrame );
27502
27503		this.setAnimationLoop = function ( callback ) {
27504
27505			onAnimationFrameCallback = callback;
27506
27507		};
27508
27509		this.dispose = function () {};
27510
27511	}
27512
27513}
27514
27515function WebGLMaterials( renderer, properties ) {
27516
27517	function refreshTransformUniform( map, uniform ) {
27518
27519		if ( map.matrixAutoUpdate === true ) {
27520
27521			map.updateMatrix();
27522
27523		}
27524
27525		uniform.value.copy( map.matrix );
27526
27527	}
27528
27529	function refreshFogUniforms( uniforms, fog ) {
27530
27531		fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );
27532
27533		if ( fog.isFog ) {
27534
27535			uniforms.fogNear.value = fog.near;
27536			uniforms.fogFar.value = fog.far;
27537
27538		} else if ( fog.isFogExp2 ) {
27539
27540			uniforms.fogDensity.value = fog.density;
27541
27542		}
27543
27544	}
27545
27546	function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {
27547
27548		if ( material.isMeshBasicMaterial ) {
27549
27550			refreshUniformsCommon( uniforms, material );
27551
27552		} else if ( material.isMeshLambertMaterial ) {
27553
27554			refreshUniformsCommon( uniforms, material );
27555
27556		} else if ( material.isMeshToonMaterial ) {
27557
27558			refreshUniformsCommon( uniforms, material );
27559			refreshUniformsToon( uniforms, material );
27560
27561		} else if ( material.isMeshPhongMaterial ) {
27562
27563			refreshUniformsCommon( uniforms, material );
27564			refreshUniformsPhong( uniforms, material );
27565
27566		} else if ( material.isMeshStandardMaterial ) {
27567
27568			refreshUniformsCommon( uniforms, material );
27569			refreshUniformsStandard( uniforms, material );
27570
27571			if ( material.isMeshPhysicalMaterial ) {
27572
27573				refreshUniformsPhysical( uniforms, material, transmissionRenderTarget );
27574
27575			}
27576
27577		} else if ( material.isMeshMatcapMaterial ) {
27578
27579			refreshUniformsCommon( uniforms, material );
27580			refreshUniformsMatcap( uniforms, material );
27581
27582		} else if ( material.isMeshDepthMaterial ) {
27583
27584			refreshUniformsCommon( uniforms, material );
27585
27586		} else if ( material.isMeshDistanceMaterial ) {
27587
27588			refreshUniformsCommon( uniforms, material );
27589			refreshUniformsDistance( uniforms, material );
27590
27591		} else if ( material.isMeshNormalMaterial ) {
27592
27593			refreshUniformsCommon( uniforms, material );
27594
27595		} else if ( material.isLineBasicMaterial ) {
27596
27597			refreshUniformsLine( uniforms, material );
27598
27599			if ( material.isLineDashedMaterial ) {
27600
27601				refreshUniformsDash( uniforms, material );
27602
27603			}
27604
27605		} else if ( material.isPointsMaterial ) {
27606
27607			refreshUniformsPoints( uniforms, material, pixelRatio, height );
27608
27609		} else if ( material.isSpriteMaterial ) {
27610
27611			refreshUniformsSprites( uniforms, material );
27612
27613		} else if ( material.isShadowMaterial ) {
27614
27615			uniforms.color.value.copy( material.color );
27616			uniforms.opacity.value = material.opacity;
27617
27618		} else if ( material.isShaderMaterial ) {
27619
27620			material.uniformsNeedUpdate = false; // #15581
27621
27622		}
27623
27624	}
27625
27626	function refreshUniformsCommon( uniforms, material ) {
27627
27628		uniforms.opacity.value = material.opacity;
27629
27630		if ( material.color ) {
27631
27632			uniforms.diffuse.value.copy( material.color );
27633
27634		}
27635
27636		if ( material.emissive ) {
27637
27638			uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
27639
27640		}
27641
27642		if ( material.map ) {
27643
27644			uniforms.map.value = material.map;
27645
27646			refreshTransformUniform( material.map, uniforms.mapTransform );
27647
27648		}
27649
27650		if ( material.alphaMap ) {
27651
27652			uniforms.alphaMap.value = material.alphaMap;
27653
27654			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27655
27656		}
27657
27658		if ( material.bumpMap ) {
27659
27660			uniforms.bumpMap.value = material.bumpMap;
27661
27662			refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform );
27663
27664			uniforms.bumpScale.value = material.bumpScale;
27665
27666			if ( material.side === BackSide ) {
27667
27668				uniforms.bumpScale.value *= - 1;
27669
27670			}
27671
27672		}
27673
27674		if ( material.normalMap ) {
27675
27676			uniforms.normalMap.value = material.normalMap;
27677
27678			refreshTransformUniform( material.normalMap, uniforms.normalMapTransform );
27679
27680			uniforms.normalScale.value.copy( material.normalScale );
27681
27682			if ( material.side === BackSide ) {
27683
27684				uniforms.normalScale.value.negate();
27685
27686			}
27687
27688		}
27689
27690		if ( material.displacementMap ) {
27691
27692			uniforms.displacementMap.value = material.displacementMap;
27693
27694			refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform );
27695
27696			uniforms.displacementScale.value = material.displacementScale;
27697			uniforms.displacementBias.value = material.displacementBias;
27698
27699		}
27700
27701		if ( material.emissiveMap ) {
27702
27703			uniforms.emissiveMap.value = material.emissiveMap;
27704
27705			refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );
27706
27707		}
27708
27709		if ( material.specularMap ) {
27710
27711			uniforms.specularMap.value = material.specularMap;
27712
27713			refreshTransformUniform( material.specularMap, uniforms.specularMapTransform );
27714
27715		}
27716
27717		if ( material.alphaTest > 0 ) {
27718
27719			uniforms.alphaTest.value = material.alphaTest;
27720
27721		}
27722
27723		const envMap = properties.get( material ).envMap;
vendor: 87,068 bytes, lines 27724-31034
27724
27725		if ( envMap ) {
27726
27727			uniforms.envMap.value = envMap;
27728
27729			uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
27730
27731			uniforms.reflectivity.value = material.reflectivity;
27732			uniforms.ior.value = material.ior;
27733			uniforms.refractionRatio.value = material.refractionRatio;
27734
27735		}
27736
27737		if ( material.lightMap ) {
27738
27739			uniforms.lightMap.value = material.lightMap;
27740
27741			// artist-friendly light intensity scaling factor
27742			const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1;
27743
27744			uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor;
27745
27746			refreshTransformUniform( material.lightMap, uniforms.lightMapTransform );
27747
27748		}
27749
27750		if ( material.aoMap ) {
27751
27752			uniforms.aoMap.value = material.aoMap;
27753			uniforms.aoMapIntensity.value = material.aoMapIntensity;
27754
27755			refreshTransformUniform( material.aoMap, uniforms.aoMapTransform );
27756
27757		}
27758
27759	}
27760
27761	function refreshUniformsLine( uniforms, material ) {
27762
27763		uniforms.diffuse.value.copy( material.color );
27764		uniforms.opacity.value = material.opacity;
27765
27766		if ( material.map ) {
27767
27768			uniforms.map.value = material.map;
27769
27770			refreshTransformUniform( material.map, uniforms.mapTransform );
27771
27772		}
27773
27774	}
27775
27776	function refreshUniformsDash( uniforms, material ) {
27777
27778		uniforms.dashSize.value = material.dashSize;
27779		uniforms.totalSize.value = material.dashSize + material.gapSize;
27780		uniforms.scale.value = material.scale;
27781
27782	}
27783
27784	function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
27785
27786		uniforms.diffuse.value.copy( material.color );
27787		uniforms.opacity.value = material.opacity;
27788		uniforms.size.value = material.size * pixelRatio;
27789		uniforms.scale.value = height * 0.5;
27790
27791		if ( material.map ) {
27792
27793			uniforms.map.value = material.map;
27794
27795			refreshTransformUniform( material.map, uniforms.uvTransform );
27796
27797		}
27798
27799		if ( material.alphaMap ) {
27800
27801			uniforms.alphaMap.value = material.alphaMap;
27802
27803			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27804
27805		}
27806
27807		if ( material.alphaTest > 0 ) {
27808
27809			uniforms.alphaTest.value = material.alphaTest;
27810
27811		}
27812
27813	}
27814
27815	function refreshUniformsSprites( uniforms, material ) {
27816
27817		uniforms.diffuse.value.copy( material.color );
27818		uniforms.opacity.value = material.opacity;
27819		uniforms.rotation.value = material.rotation;
27820
27821		if ( material.map ) {
27822
27823			uniforms.map.value = material.map;
27824
27825			refreshTransformUniform( material.map, uniforms.mapTransform );
27826
27827		}
27828
27829		if ( material.alphaMap ) {
27830
27831			uniforms.alphaMap.value = material.alphaMap;
27832
27833			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27834
27835		}
27836
27837		if ( material.alphaTest > 0 ) {
27838
27839			uniforms.alphaTest.value = material.alphaTest;
27840
27841		}
27842
27843	}
27844
27845	function refreshUniformsPhong( uniforms, material ) {
27846
27847		uniforms.specular.value.copy( material.specular );
27848		uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
27849
27850	}
27851
27852	function refreshUniformsToon( uniforms, material ) {
27853
27854		if ( material.gradientMap ) {
27855
27856			uniforms.gradientMap.value = material.gradientMap;
27857
27858		}
27859
27860	}
27861
27862	function refreshUniformsStandard( uniforms, material ) {
27863
27864		uniforms.metalness.value = material.metalness;
27865
27866		if ( material.metalnessMap ) {
27867
27868			uniforms.metalnessMap.value = material.metalnessMap;
27869
27870			refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );
27871
27872		}
27873
27874		uniforms.roughness.value = material.roughness;
27875
27876		if ( material.roughnessMap ) {
27877
27878			uniforms.roughnessMap.value = material.roughnessMap;
27879
27880			refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );
27881
27882		}
27883
27884		const envMap = properties.get( material ).envMap;
27885
27886		if ( envMap ) {
27887
27888			//uniforms.envMap.value = material.envMap; // part of uniforms common
27889			uniforms.envMapIntensity.value = material.envMapIntensity;
27890
27891		}
27892
27893	}
27894
27895	function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {
27896
27897		uniforms.ior.value = material.ior; // also part of uniforms common
27898
27899		if ( material.sheen > 0 ) {
27900
27901			uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );
27902
27903			uniforms.sheenRoughness.value = material.sheenRoughness;
27904
27905			if ( material.sheenColorMap ) {
27906
27907				uniforms.sheenColorMap.value = material.sheenColorMap;
27908
27909				refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );
27910
27911			}
27912
27913			if ( material.sheenRoughnessMap ) {
27914
27915				uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;
27916
27917				refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );
27918
27919			}
27920
27921		}
27922
27923		if ( material.clearcoat > 0 ) {
27924
27925			uniforms.clearcoat.value = material.clearcoat;
27926			uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
27927
27928			if ( material.clearcoatMap ) {
27929
27930				uniforms.clearcoatMap.value = material.clearcoatMap;
27931
27932				refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );
27933
27934			}
27935
27936			if ( material.clearcoatRoughnessMap ) {
27937
27938				uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
27939
27940				refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );
27941
27942			}
27943
27944			if ( material.clearcoatNormalMap ) {
27945
27946				uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
27947
27948				refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );
27949
27950				uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
27951
27952				if ( material.side === BackSide ) {
27953
27954					uniforms.clearcoatNormalScale.value.negate();
27955
27956				}
27957
27958			}
27959
27960		}
27961
27962		if ( material.iridescence > 0 ) {
27963
27964			uniforms.iridescence.value = material.iridescence;
27965			uniforms.iridescenceIOR.value = material.iridescenceIOR;
27966			uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];
27967			uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];
27968
27969			if ( material.iridescenceMap ) {
27970
27971				uniforms.iridescenceMap.value = material.iridescenceMap;
27972
27973				refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );
27974
27975			}
27976
27977			if ( material.iridescenceThicknessMap ) {
27978
27979				uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;
27980
27981				refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );
27982
27983			}
27984
27985		}
27986
27987		if ( material.transmission > 0 ) {
27988
27989			uniforms.transmission.value = material.transmission;
27990			uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
27991			uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );
27992
27993			if ( material.transmissionMap ) {
27994
27995				uniforms.transmissionMap.value = material.transmissionMap;
27996
27997				refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );
27998
27999			}
28000
28001			uniforms.thickness.value = material.thickness;
28002
28003			if ( material.thicknessMap ) {
28004
28005				uniforms.thicknessMap.value = material.thicknessMap;
28006
28007				refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );
28008
28009			}
28010
28011			uniforms.attenuationDistance.value = material.attenuationDistance;
28012			uniforms.attenuationColor.value.copy( material.attenuationColor );
28013
28014		}
28015
28016		if ( material.anisotropy > 0 ) {
28017
28018			uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );
28019
28020			if ( material.anisotropyMap ) {
28021
28022				uniforms.anisotropyMap.value = material.anisotropyMap;
28023
28024				refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );
28025
28026			}
28027
28028		}
28029
28030		uniforms.specularIntensity.value = material.specularIntensity;
28031		uniforms.specularColor.value.copy( material.specularColor );
28032
28033		if ( material.specularColorMap ) {
28034
28035			uniforms.specularColorMap.value = material.specularColorMap;
28036
28037			refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );
28038
28039		}
28040
28041		if ( material.specularIntensityMap ) {
28042
28043			uniforms.specularIntensityMap.value = material.specularIntensityMap;
28044
28045			refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );
28046
28047		}
28048
28049	}
28050
28051	function refreshUniformsMatcap( uniforms, material ) {
28052
28053		if ( material.matcap ) {
28054
28055			uniforms.matcap.value = material.matcap;
28056
28057		}
28058
28059	}
28060
28061	function refreshUniformsDistance( uniforms, material ) {
28062
28063		const light = properties.get( material ).light;
28064
28065		uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );
28066		uniforms.nearDistance.value = light.shadow.camera.near;
28067		uniforms.farDistance.value = light.shadow.camera.far;
28068
28069	}
28070
28071	return {
28072		refreshFogUniforms: refreshFogUniforms,
28073		refreshMaterialUniforms: refreshMaterialUniforms
28074	};
28075
28076}
28077
28078function WebGLUniformsGroups( gl, info, capabilities, state ) {
28079
28080	let buffers = {};
28081	let updateList = {};
28082	let allocatedBindingPoints = [];
28083
28084	const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program
28085
28086	function bind( uniformsGroup, program ) {
28087
28088		const webglProgram = program.program;
28089		state.uniformBlockBinding( uniformsGroup, webglProgram );
28090
28091	}
28092
28093	function update( uniformsGroup, program ) {
28094
28095		let buffer = buffers[ uniformsGroup.id ];
28096
28097		if ( buffer === undefined ) {
28098
28099			prepareUniformsGroup( uniformsGroup );
28100
28101			buffer = createBuffer( uniformsGroup );
28102			buffers[ uniformsGroup.id ] = buffer;
28103
28104			uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );
28105
28106		}
28107
28108		// ensure to update the binding points/block indices mapping for this program
28109
28110		const webglProgram = program.program;
28111		state.updateUBOMapping( uniformsGroup, webglProgram );
28112
28113		// update UBO once per frame
28114
28115		const frame = info.render.frame;
28116
28117		if ( updateList[ uniformsGroup.id ] !== frame ) {
28118
28119			updateBufferData( uniformsGroup );
28120
28121			updateList[ uniformsGroup.id ] = frame;
28122
28123		}
28124
28125	}
28126
28127	function createBuffer( uniformsGroup ) {
28128
28129		// the setup of an UBO is independent of a particular shader program but global
28130
28131		const bindingPointIndex = allocateBindingPointIndex();
28132		uniformsGroup.__bindingPointIndex = bindingPointIndex;
28133
28134		const buffer = gl.createBuffer();
28135		const size = uniformsGroup.__size;
28136		const usage = uniformsGroup.usage;
28137
28138		gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28139		gl.bufferData( gl.UNIFORM_BUFFER, size, usage );
28140		gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28141		gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer );
28142
28143		return buffer;
28144
28145	}
28146
28147	function allocateBindingPointIndex() {
28148
28149		for ( let i = 0; i < maxBindingPoints; i ++ ) {
28150
28151			if ( allocatedBindingPoints.indexOf( i ) === - 1 ) {
28152
28153				allocatedBindingPoints.push( i );
28154				return i;
28155
28156			}
28157
28158		}
28159
28160		console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );
28161
28162		return 0;
28163
28164	}
28165
28166	function updateBufferData( uniformsGroup ) {
28167
28168		const buffer = buffers[ uniformsGroup.id ];
28169		const uniforms = uniformsGroup.uniforms;
28170		const cache = uniformsGroup.__cache;
28171
28172		gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28173
28174		for ( let i = 0, il = uniforms.length; i < il; i ++ ) {
28175
28176			const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28177
28178			for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28179
28180				const uniform = uniformArray[ j ];
28181
28182				if ( hasUniformChanged( uniform, i, j, cache ) === true ) {
28183
28184					const offset = uniform.__offset;
28185
28186					const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28187
28188					let arrayOffset = 0;
28189
28190					for ( let k = 0; k < values.length; k ++ ) {
28191
28192						const value = values[ k ];
28193
28194						const info = getUniformSize( value );
28195
28196						// TODO add integer and struct support
28197						if ( typeof value === 'number' || typeof value === 'boolean' ) {
28198
28199							uniform.__data[ 0 ] = value;
28200							gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );
28201
28202						} else if ( value.isMatrix3 ) {
28203
28204							// manually converting 3x3 to 3x4
28205
28206							uniform.__data[ 0 ] = value.elements[ 0 ];
28207							uniform.__data[ 1 ] = value.elements[ 1 ];
28208							uniform.__data[ 2 ] = value.elements[ 2 ];
28209							uniform.__data[ 3 ] = 0;
28210							uniform.__data[ 4 ] = value.elements[ 3 ];
28211							uniform.__data[ 5 ] = value.elements[ 4 ];
28212							uniform.__data[ 6 ] = value.elements[ 5 ];
28213							uniform.__data[ 7 ] = 0;
28214							uniform.__data[ 8 ] = value.elements[ 6 ];
28215							uniform.__data[ 9 ] = value.elements[ 7 ];
28216							uniform.__data[ 10 ] = value.elements[ 8 ];
28217							uniform.__data[ 11 ] = 0;
28218
28219						} else {
28220
28221							value.toArray( uniform.__data, arrayOffset );
28222
28223							arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;
28224
28225						}
28226
28227					}
28228
28229					gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
28230
28231				}
28232
28233			}
28234
28235		}
28236
28237		gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28238
28239	}
28240
28241	function hasUniformChanged( uniform, index, indexArray, cache ) {
28242
28243		const value = uniform.value;
28244		const indexString = index + '_' + indexArray;
28245
28246		if ( cache[ indexString ] === undefined ) {
28247
28248			// cache entry does not exist so far
28249
28250			if ( typeof value === 'number' || typeof value === 'boolean' ) {
28251
28252				cache[ indexString ] = value;
28253
28254			} else {
28255
28256				cache[ indexString ] = value.clone();
28257
28258			}
28259
28260			return true;
28261
28262		} else {
28263
28264			const cachedObject = cache[ indexString ];
28265
28266			// compare current value with cached entry
28267
28268			if ( typeof value === 'number' || typeof value === 'boolean' ) {
28269
28270				if ( cachedObject !== value ) {
28271
28272					cache[ indexString ] = value;
28273					return true;
28274
28275				}
28276
28277			} else {
28278
28279				if ( cachedObject.equals( value ) === false ) {
28280
28281					cachedObject.copy( value );
28282					return true;
28283
28284				}
28285
28286			}
28287
28288		}
28289
28290		return false;
28291
28292	}
28293
28294	function prepareUniformsGroup( uniformsGroup ) {
28295
28296		// determine total buffer size according to the STD140 layout
28297		// Hint: STD140 is the only supported layout in WebGL 2
28298
28299		const uniforms = uniformsGroup.uniforms;
28300
28301		let offset = 0; // global buffer offset in bytes
28302		const chunkSize = 16; // size of a chunk in bytes
28303
28304		for ( let i = 0, l = uniforms.length; i < l; i ++ ) {
28305
28306			const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28307
28308			for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28309
28310				const uniform = uniformArray[ j ];
28311
28312				const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28313
28314				for ( let k = 0, kl = values.length; k < kl; k ++ ) {
28315
28316					const value = values[ k ];
28317
28318					const info = getUniformSize( value );
28319
28320					// Calculate the chunk offset
28321					const chunkOffsetUniform = offset % chunkSize;
28322
28323					// Check for chunk overflow
28324					if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) {
28325
28326						// Add padding and adjust offset
28327						offset += ( chunkSize - chunkOffsetUniform );
28328
28329					}
28330
28331					// the following two properties will be used for partial buffer updates
28332
28333					uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
28334					uniform.__offset = offset;
28335
28336
28337					// Update the global offset
28338					offset += info.storage;
28339
28340
28341				}
28342
28343			}
28344
28345		}
28346
28347		// ensure correct final padding
28348
28349		const chunkOffset = offset % chunkSize;
28350
28351		if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );
28352
28353		//
28354
28355		uniformsGroup.__size = offset;
28356		uniformsGroup.__cache = {};
28357
28358		return this;
28359
28360	}
28361
28362	function getUniformSize( value ) {
28363
28364		const info = {
28365			boundary: 0, // bytes
28366			storage: 0 // bytes
28367		};
28368
28369		// determine sizes according to STD140
28370
28371		if ( typeof value === 'number' || typeof value === 'boolean' ) {
28372
28373			// float/int/bool
28374
28375			info.boundary = 4;
28376			info.storage = 4;
28377
28378		} else if ( value.isVector2 ) {
28379
28380			// vec2
28381
28382			info.boundary = 8;
28383			info.storage = 8;
28384
28385		} else if ( value.isVector3 || value.isColor ) {
28386
28387			// vec3
28388
28389			info.boundary = 16;
28390			info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes
28391
28392		} else if ( value.isVector4 ) {
28393
28394			// vec4
28395
28396			info.boundary = 16;
28397			info.storage = 16;
28398
28399		} else if ( value.isMatrix3 ) {
28400
28401			// mat3 (in STD140 a 3x3 matrix is represented as 3x4)
28402
28403			info.boundary = 48;
28404			info.storage = 48;
28405
28406		} else if ( value.isMatrix4 ) {
28407
28408			// mat4
28409
28410			info.boundary = 64;
28411			info.storage = 64;
28412
28413		} else if ( value.isTexture ) {
28414
28415			console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' );
28416
28417		} else {
28418
28419			console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value );
28420
28421		}
28422
28423		return info;
28424
28425	}
28426
28427	function onUniformsGroupsDispose( event ) {
28428
28429		const uniformsGroup = event.target;
28430
28431		uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose );
28432
28433		const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );
28434		allocatedBindingPoints.splice( index, 1 );
28435
28436		gl.deleteBuffer( buffers[ uniformsGroup.id ] );
28437
28438		delete buffers[ uniformsGroup.id ];
28439		delete updateList[ uniformsGroup.id ];
28440
28441	}
28442
28443	function dispose() {
28444
28445		for ( const id in buffers ) {
28446
28447			gl.deleteBuffer( buffers[ id ] );
28448
28449		}
28450
28451		allocatedBindingPoints = [];
28452		buffers = {};
28453		updateList = {};
28454
28455	}
28456
28457	return {
28458
28459		bind: bind,
28460		update: update,
28461
28462		dispose: dispose
28463
28464	};
28465
28466}
28467
28468class WebGLRenderer {
28469
28470	constructor( parameters = {} ) {
28471
28472		const {
28473			canvas = createCanvasElement(),
28474			context = null,
28475			depth = true,
28476			stencil = true,
28477			alpha = false,
28478			antialias = false,
28479			premultipliedAlpha = true,
28480			preserveDrawingBuffer = false,
28481			powerPreference = 'default',
28482			failIfMajorPerformanceCaveat = false,
28483		} = parameters;
28484
28485		this.isWebGLRenderer = true;
28486
28487		let _alpha;
28488
28489		if ( context !== null ) {
28490
28491			_alpha = context.getContextAttributes().alpha;
28492
28493		} else {
28494
28495			_alpha = alpha;
28496
28497		}
28498
28499		const uintClearColor = new Uint32Array( 4 );
28500		const intClearColor = new Int32Array( 4 );
28501
28502		let currentRenderList = null;
28503		let currentRenderState = null;
28504
28505		// render() can be called from within a callback triggered by another render.
28506		// We track this so that the nested render call gets its list and state isolated from the parent render call.
28507
28508		const renderListStack = [];
28509		const renderStateStack = [];
28510
28511		// public properties
28512
28513		this.domElement = canvas;
28514
28515		// Debug configuration container
28516		this.debug = {
28517
28518			/**
28519			 * Enables error checking and reporting when shader programs are being compiled
28520			 * @type {boolean}
28521			 */
28522			checkShaderErrors: true,
28523			/**
28524			 * Callback for custom error reporting.
28525			 * @type {?Function}
28526			 */
28527			onShaderError: null
28528		};
28529
28530		// clearing
28531
28532		this.autoClear = true;
28533		this.autoClearColor = true;
28534		this.autoClearDepth = true;
28535		this.autoClearStencil = true;
28536
28537		// scene graph
28538
28539		this.sortObjects = true;
28540
28541		// user-defined clipping
28542
28543		this.clippingPlanes = [];
28544		this.localClippingEnabled = false;
28545
28546		// physically based shading
28547
28548		this._outputColorSpace = SRGBColorSpace;
28549
28550		// physical lights
28551
28552		this._useLegacyLights = false;
28553
28554		// tone mapping
28555
28556		this.toneMapping = NoToneMapping;
28557		this.toneMappingExposure = 1.0;
28558
28559		// internal properties
28560
28561		const _this = this;
28562
28563		let _isContextLost = false;
28564
28565		// internal state cache
28566
28567		let _currentActiveCubeFace = 0;
28568		let _currentActiveMipmapLevel = 0;
28569		let _currentRenderTarget = null;
28570		let _currentMaterialId = - 1;
28571
28572		let _currentCamera = null;
28573
28574		const _currentViewport = new Vector4();
28575		const _currentScissor = new Vector4();
28576		let _currentScissorTest = null;
28577
28578		const _currentClearColor = new Color( 0x000000 );
28579		let _currentClearAlpha = 0;
28580
28581		//
28582
28583		let _width = canvas.width;
28584		let _height = canvas.height;
28585
28586		let _pixelRatio = 1;
28587		let _opaqueSort = null;
28588		let _transparentSort = null;
28589
28590		const _viewport = new Vector4( 0, 0, _width, _height );
28591		const _scissor = new Vector4( 0, 0, _width, _height );
28592		let _scissorTest = false;
28593
28594		// frustum
28595
28596		const _frustum = new Frustum();
28597
28598		// clipping
28599
28600		let _clippingEnabled = false;
28601		let _localClippingEnabled = false;
28602
28603		// transmission
28604
28605		let _transmissionRenderTarget = null;
28606
28607		// camera matrices cache
28608
28609		const _projScreenMatrix = new Matrix4();
28610
28611		const _vector2 = new Vector2();
28612		const _vector3 = new Vector3();
28613
28614		const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
28615
28616		function getTargetPixelRatio() {
28617
28618			return _currentRenderTarget === null ? _pixelRatio : 1;
28619
28620		}
28621
28622		// initialize
28623
28624		let _gl = context;
28625
28626		function getContext( contextNames, contextAttributes ) {
28627
28628			for ( let i = 0; i < contextNames.length; i ++ ) {
28629
28630				const contextName = contextNames[ i ];
28631				const context = canvas.getContext( contextName, contextAttributes );
28632				if ( context !== null ) return context;
28633
28634			}
28635
28636			return null;
28637
28638		}
28639
28640		try {
28641
28642			const contextAttributes = {
28643				alpha: true,
28644				depth,
28645				stencil,
28646				antialias,
28647				premultipliedAlpha,
28648				preserveDrawingBuffer,
28649				powerPreference,
28650				failIfMajorPerformanceCaveat,
28651			};
28652
28653			// OffscreenCanvas does not have setAttribute, see #22811
28654			if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );
28655
28656			// event listeners must be registered before WebGL context is created, see #12753
28657			canvas.addEventListener( 'webglcontextlost', onContextLost, false );
28658			canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
28659			canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );
28660
28661			if ( _gl === null ) {
28662
28663				const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
28664
28665				if ( _this.isWebGL1Renderer === true ) {
28666
28667					contextNames.shift();
28668
28669				}
28670
28671				_gl = getContext( contextNames, contextAttributes );
28672
28673				if ( _gl === null ) {
28674
28675					if ( getContext( contextNames ) ) {
28676
28677						throw new Error( 'Error creating WebGL context with your selected attributes.' );
28678
28679					} else {
28680
28681						throw new Error( 'Error creating WebGL context.' );
28682
28683					}
28684
28685				}
28686
28687			}
28688
28689			if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153
28690
28691				console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' );
28692
28693			}
28694
28695			// Some experimental-webgl implementations do not have getShaderPrecisionFormat
28696
28697			if ( _gl.getShaderPrecisionFormat === undefined ) {
28698
28699				_gl.getShaderPrecisionFormat = function () {
28700
28701					return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
28702
28703				};
28704
28705			}
28706
28707		} catch ( error ) {
28708
28709			console.error( 'THREE.WebGLRenderer: ' + error.message );
28710			throw error;
28711
28712		}
28713
28714		let extensions, capabilities, state, info;
28715		let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
28716		let programCache, materials, renderLists, renderStates, clipping, shadowMap;
28717
28718		let background, morphtargets, bufferRenderer, indexedBufferRenderer;
28719
28720		let utils, bindingStates, uniformsGroups;
28721
28722		function initGLContext() {
28723
28724			extensions = new WebGLExtensions( _gl );
28725
28726			capabilities = new WebGLCapabilities( _gl, extensions, parameters );
28727
28728			extensions.init( capabilities );
28729
28730			utils = new WebGLUtils( _gl, extensions, capabilities );
28731
28732			state = new WebGLState( _gl, extensions, capabilities );
28733
28734			info = new WebGLInfo( _gl );
28735			properties = new WebGLProperties();
28736			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
28737			cubemaps = new WebGLCubeMaps( _this );
28738			cubeuvmaps = new WebGLCubeUVMaps( _this );
28739			attributes = new WebGLAttributes( _gl, capabilities );
28740			bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
28741			geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
28742			objects = new WebGLObjects( _gl, geometries, attributes, info );
28743			morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
28744			clipping = new WebGLClipping( properties );
28745			programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );
28746			materials = new WebGLMaterials( _this, properties );
28747			renderLists = new WebGLRenderLists();
28748			renderStates = new WebGLRenderStates( extensions, capabilities );
28749			background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
28750			shadowMap = new WebGLShadowMap( _this, objects, capabilities );
28751			uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
28752
28753			bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
28754			indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
28755
28756			info.programs = programCache.programs;
28757
28758			_this.capabilities = capabilities;
28759			_this.extensions = extensions;
28760			_this.properties = properties;
28761			_this.renderLists = renderLists;
28762			_this.shadowMap = shadowMap;
28763			_this.state = state;
28764			_this.info = info;
28765
28766		}
28767
28768		initGLContext();
28769
28770		// xr
28771
28772		const xr = new WebXRManager( _this, _gl );
28773
28774		this.xr = xr;
28775
28776		// API
28777
28778		this.getContext = function () {
28779
28780			return _gl;
28781
28782		};
28783
28784		this.getContextAttributes = function () {
28785
28786			return _gl.getContextAttributes();
28787
28788		};
28789
28790		this.forceContextLoss = function () {
28791
28792			const extension = extensions.get( 'WEBGL_lose_context' );
28793			if ( extension ) extension.loseContext();
28794
28795		};
28796
28797		this.forceContextRestore = function () {
28798
28799			const extension = extensions.get( 'WEBGL_lose_context' );
28800			if ( extension ) extension.restoreContext();
28801
28802		};
28803
28804		this.getPixelRatio = function () {
28805
28806			return _pixelRatio;
28807
28808		};
28809
28810		this.setPixelRatio = function ( value ) {
28811
28812			if ( value === undefined ) return;
28813
28814			_pixelRatio = value;
28815
28816			this.setSize( _width, _height, false );
28817
28818		};
28819
28820		this.getSize = function ( target ) {
28821
28822			return target.set( _width, _height );
28823
28824		};
28825
28826		this.setSize = function ( width, height, updateStyle = true ) {
28827
28828			if ( xr.isPresenting ) {
28829
28830				console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
28831				return;
28832
28833			}
28834
28835			_width = width;
28836			_height = height;
28837
28838			canvas.width = Math.floor( width * _pixelRatio );
28839			canvas.height = Math.floor( height * _pixelRatio );
28840
28841			if ( updateStyle === true ) {
28842
28843				canvas.style.width = width + 'px';
28844				canvas.style.height = height + 'px';
28845
28846			}
28847
28848			this.setViewport( 0, 0, width, height );
28849
28850		};
28851
28852		this.getDrawingBufferSize = function ( target ) {
28853
28854			return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
28855
28856		};
28857
28858		this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
28859
28860			_width = width;
28861			_height = height;
28862
28863			_pixelRatio = pixelRatio;
28864
28865			canvas.width = Math.floor( width * pixelRatio );
28866			canvas.height = Math.floor( height * pixelRatio );
28867
28868			this.setViewport( 0, 0, width, height );
28869
28870		};
28871
28872		this.getCurrentViewport = function ( target ) {
28873
28874			return target.copy( _currentViewport );
28875
28876		};
28877
28878		this.getViewport = function ( target ) {
28879
28880			return target.copy( _viewport );
28881
28882		};
28883
28884		this.setViewport = function ( x, y, width, height ) {
28885
28886			if ( x.isVector4 ) {
28887
28888				_viewport.set( x.x, x.y, x.z, x.w );
28889
28890			} else {
28891
28892				_viewport.set( x, y, width, height );
28893
28894			}
28895
28896			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
28897
28898		};
28899
28900		this.getScissor = function ( target ) {
28901
28902			return target.copy( _scissor );
28903
28904		};
28905
28906		this.setScissor = function ( x, y, width, height ) {
28907
28908			if ( x.isVector4 ) {
28909
28910				_scissor.set( x.x, x.y, x.z, x.w );
28911
28912			} else {
28913
28914				_scissor.set( x, y, width, height );
28915
28916			}
28917
28918			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
28919
28920		};
28921
28922		this.getScissorTest = function () {
28923
28924			return _scissorTest;
28925
28926		};
28927
28928		this.setScissorTest = function ( boolean ) {
28929
28930			state.setScissorTest( _scissorTest = boolean );
28931
28932		};
28933
28934		this.setOpaqueSort = function ( method ) {
28935
28936			_opaqueSort = method;
28937
28938		};
28939
28940		this.setTransparentSort = function ( method ) {
28941
28942			_transparentSort = method;
28943
28944		};
28945
28946		// Clearing
28947
28948		this.getClearColor = function ( target ) {
28949
28950			return target.copy( background.getClearColor() );
28951
28952		};
28953
28954		this.setClearColor = function () {
28955
28956			background.setClearColor.apply( background, arguments );
28957
28958		};
28959
28960		this.getClearAlpha = function () {
28961
28962			return background.getClearAlpha();
28963
28964		};
28965
28966		this.setClearAlpha = function () {
28967
28968			background.setClearAlpha.apply( background, arguments );
28969
28970		};
28971
28972		this.clear = function ( color = true, depth = true, stencil = true ) {
28973
28974			let bits = 0;
28975
28976			if ( color ) {
28977
28978				// check if we're trying to clear an integer target
28979				let isIntegerFormat = false;
28980				if ( _currentRenderTarget !== null ) {
28981
28982					const targetFormat = _currentRenderTarget.texture.format;
28983					isIntegerFormat = targetFormat === RGBAIntegerFormat ||
28984						targetFormat === RGIntegerFormat ||
28985						targetFormat === RedIntegerFormat;
28986
28987				}
28988
28989				// use the appropriate clear functions to clear the target if it's a signed
28990				// or unsigned integer target
28991				if ( isIntegerFormat ) {
28992
28993					const targetType = _currentRenderTarget.texture.type;
28994					const isUnsignedType = targetType === UnsignedByteType ||
28995						targetType === UnsignedIntType ||
28996						targetType === UnsignedShortType ||
28997						targetType === UnsignedInt248Type ||
28998						targetType === UnsignedShort4444Type ||
28999						targetType === UnsignedShort5551Type;
29000
29001					const clearColor = background.getClearColor();
29002					const a = background.getClearAlpha();
29003					const r = clearColor.r;
29004					const g = clearColor.g;
29005					const b = clearColor.b;
29006
29007					if ( isUnsignedType ) {
29008
29009						uintClearColor[ 0 ] = r;
29010						uintClearColor[ 1 ] = g;
29011						uintClearColor[ 2 ] = b;
29012						uintClearColor[ 3 ] = a;
29013						_gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );
29014
29015					} else {
29016
29017						intClearColor[ 0 ] = r;
29018						intClearColor[ 1 ] = g;
29019						intClearColor[ 2 ] = b;
29020						intClearColor[ 3 ] = a;
29021						_gl.clearBufferiv( _gl.COLOR, 0, intClearColor );
29022
29023					}
29024
29025				} else {
29026
29027					bits |= _gl.COLOR_BUFFER_BIT;
29028
29029				}
29030
29031			}
29032
29033			if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
29034			if ( stencil ) {
29035
29036				bits |= _gl.STENCIL_BUFFER_BIT;
29037				this.state.buffers.stencil.setMask( 0xffffffff );
29038
29039			}
29040
29041			_gl.clear( bits );
29042
29043		};
29044
29045		this.clearColor = function () {
29046
29047			this.clear( true, false, false );
29048
29049		};
29050
29051		this.clearDepth = function () {
29052
29053			this.clear( false, true, false );
29054
29055		};
29056
29057		this.clearStencil = function () {
29058
29059			this.clear( false, false, true );
29060
29061		};
29062
29063		//
29064
29065		this.dispose = function () {
29066
29067			canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
29068			canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
29069			canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );
29070
29071			renderLists.dispose();
29072			renderStates.dispose();
29073			properties.dispose();
29074			cubemaps.dispose();
29075			cubeuvmaps.dispose();
29076			objects.dispose();
29077			bindingStates.dispose();
29078			uniformsGroups.dispose();
29079			programCache.dispose();
29080
29081			xr.dispose();
29082
29083			xr.removeEventListener( 'sessionstart', onXRSessionStart );
29084			xr.removeEventListener( 'sessionend', onXRSessionEnd );
29085
29086			if ( _transmissionRenderTarget ) {
29087
29088				_transmissionRenderTarget.dispose();
29089				_transmissionRenderTarget = null;
29090
29091			}
29092
29093			animation.stop();
29094
29095		};
29096
29097		// Events
29098
29099		function onContextLost( event ) {
29100
29101			event.preventDefault();
29102
29103			console.log( 'THREE.WebGLRenderer: Context Lost.' );
29104
29105			_isContextLost = true;
29106
29107		}
29108
29109		function onContextRestore( /* event */ ) {
29110
29111			console.log( 'THREE.WebGLRenderer: Context Restored.' );
29112
29113			_isContextLost = false;
29114
29115			const infoAutoReset = info.autoReset;
29116			const shadowMapEnabled = shadowMap.enabled;
29117			const shadowMapAutoUpdate = shadowMap.autoUpdate;
29118			const shadowMapNeedsUpdate = shadowMap.needsUpdate;
29119			const shadowMapType = shadowMap.type;
29120
29121			initGLContext();
29122
29123			info.autoReset = infoAutoReset;
29124			shadowMap.enabled = shadowMapEnabled;
29125			shadowMap.autoUpdate = shadowMapAutoUpdate;
29126			shadowMap.needsUpdate = shadowMapNeedsUpdate;
29127			shadowMap.type = shadowMapType;
29128
29129		}
29130
29131		function onContextCreationError( event ) {
29132
29133			console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );
29134
29135		}
29136
29137		function onMaterialDispose( event ) {
29138
29139			const material = event.target;
29140
29141			material.removeEventListener( 'dispose', onMaterialDispose );
29142
29143			deallocateMaterial( material );
29144
29145		}
29146
29147		// Buffer deallocation
29148
29149		function deallocateMaterial( material ) {
29150
29151			releaseMaterialProgramReferences( material );
29152
29153			properties.remove( material );
29154
29155		}
29156
29157
29158		function releaseMaterialProgramReferences( material ) {
29159
29160			const programs = properties.get( material ).programs;
29161
29162			if ( programs !== undefined ) {
29163
29164				programs.forEach( function ( program ) {
29165
29166					programCache.releaseProgram( program );
29167
29168				} );
29169
29170				if ( material.isShaderMaterial ) {
29171
29172					programCache.releaseShaderCache( material );
29173
29174				}
29175
29176			}
29177
29178		}
29179
29180		// Buffer rendering
29181
29182		this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
29183
29184			if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
29185
29186			const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
29187
29188			const program = setProgram( camera, scene, geometry, material, object );
29189
29190			state.setMaterial( material, frontFaceCW );
29191
29192			//
29193
29194			let index = geometry.index;
29195			let rangeFactor = 1;
29196
29197			if ( material.wireframe === true ) {
29198
29199				index = geometries.getWireframeAttribute( geometry );
29200
29201				if ( index === undefined ) return;
29202
29203				rangeFactor = 2;
29204
29205			}
29206
29207			//
29208
29209			const drawRange = geometry.drawRange;
29210			const position = geometry.attributes.position;
29211
29212			let drawStart = drawRange.start * rangeFactor;
29213			let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;
29214
29215			if ( group !== null ) {
29216
29217				drawStart = Math.max( drawStart, group.start * rangeFactor );
29218				drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );
29219
29220			}
29221
29222			if ( index !== null ) {
29223
29224				drawStart = Math.max( drawStart, 0 );
29225				drawEnd = Math.min( drawEnd, index.count );
29226
29227			} else if ( position !== undefined && position !== null ) {
29228
29229				drawStart = Math.max( drawStart, 0 );
29230				drawEnd = Math.min( drawEnd, position.count );
29231
29232			}
29233
29234			const drawCount = drawEnd - drawStart;
29235
29236			if ( drawCount < 0 || drawCount === Infinity ) return;
29237
29238			//
29239
29240			bindingStates.setup( object, material, program, geometry, index );
29241
29242			let attribute;
29243			let renderer = bufferRenderer;
29244
29245			if ( index !== null ) {
29246
29247				attribute = attributes.get( index );
29248
29249				renderer = indexedBufferRenderer;
29250				renderer.setIndex( attribute );
29251
29252			}
29253
29254			//
29255
29256			if ( object.isMesh ) {
29257
29258				if ( material.wireframe === true ) {
29259
29260					state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
29261					renderer.setMode( _gl.LINES );
29262
29263				} else {
29264
29265					renderer.setMode( _gl.TRIANGLES );
29266
29267				}
29268
29269			} else if ( object.isLine ) {
29270
29271				let lineWidth = material.linewidth;
29272
29273				if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
29274
29275				state.setLineWidth( lineWidth * getTargetPixelRatio() );
29276
29277				if ( object.isLineSegments ) {
29278
29279					renderer.setMode( _gl.LINES );
29280
29281				} else if ( object.isLineLoop ) {
29282
29283					renderer.setMode( _gl.LINE_LOOP );
29284
29285				} else {
29286
29287					renderer.setMode( _gl.LINE_STRIP );
29288
29289				}
29290
29291			} else if ( object.isPoints ) {
29292
29293				renderer.setMode( _gl.POINTS );
29294
29295			} else if ( object.isSprite ) {
29296
29297				renderer.setMode( _gl.TRIANGLES );
29298
29299			}
29300
29301			if ( object.isBatchedMesh ) {
29302
29303				renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
29304
29305			} else if ( object.isInstancedMesh ) {
29306
29307				renderer.renderInstances( drawStart, drawCount, object.count );
29308
29309			} else if ( geometry.isInstancedBufferGeometry ) {
29310
29311				const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;
29312				const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );
29313
29314				renderer.renderInstances( drawStart, drawCount, instanceCount );
29315
29316			} else {
29317
29318				renderer.render( drawStart, drawCount );
29319
29320			}
29321
29322		};
29323
29324		// Compile
29325
29326		function prepareMaterial( material, scene, object ) {
29327
29328			if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29329
29330				material.side = BackSide;
29331				material.needsUpdate = true;
29332				getProgram( material, scene, object );
29333
29334				material.side = FrontSide;
29335				material.needsUpdate = true;
29336				getProgram( material, scene, object );
29337
29338				material.side = DoubleSide;
29339
29340			} else {
29341
29342				getProgram( material, scene, object );
29343
29344			}
29345
29346		}
29347
29348		this.compile = function ( scene, camera, targetScene = null ) {
29349
29350			if ( targetScene === null ) targetScene = scene;
29351
29352			currentRenderState = renderStates.get( targetScene );
29353			currentRenderState.init();
29354
29355			renderStateStack.push( currentRenderState );
29356
29357			// gather lights from both the target scene and the new object that will be added to the scene.
29358
29359			targetScene.traverseVisible( function ( object ) {
29360
29361				if ( object.isLight && object.layers.test( camera.layers ) ) {
29362
29363					currentRenderState.pushLight( object );
29364
29365					if ( object.castShadow ) {
29366
29367						currentRenderState.pushShadow( object );
29368
29369					}
29370
29371				}
29372
29373			} );
29374
29375			if ( scene !== targetScene ) {
29376
29377				scene.traverseVisible( function ( object ) {
29378
29379					if ( object.isLight && object.layers.test( camera.layers ) ) {
29380
29381						currentRenderState.pushLight( object );
29382
29383						if ( object.castShadow ) {
29384
29385							currentRenderState.pushShadow( object );
29386
29387						}
29388
29389					}
29390
29391				} );
29392
29393			}
29394
29395			currentRenderState.setupLights( _this._useLegacyLights );
29396
29397			// Only initialize materials in the new scene, not the targetScene.
29398
29399			const materials = new Set();
29400
29401			scene.traverse( function ( object ) {
29402
29403				const material = object.material;
29404
29405				if ( material ) {
29406
29407					if ( Array.isArray( material ) ) {
29408
29409						for ( let i = 0; i < material.length; i ++ ) {
29410
29411							const material2 = material[ i ];
29412
29413							prepareMaterial( material2, targetScene, object );
29414							materials.add( material2 );
29415
29416						}
29417
29418					} else {
29419
29420						prepareMaterial( material, targetScene, object );
29421						materials.add( material );
29422
29423					}
29424
29425				}
29426
29427			} );
29428
29429			renderStateStack.pop();
29430			currentRenderState = null;
29431
29432			return materials;
29433
29434		};
29435
29436		// compileAsync
29437
29438		this.compileAsync = function ( scene, camera, targetScene = null ) {
29439
29440			const materials = this.compile( scene, camera, targetScene );
29441
29442			// Wait for all the materials in the new object to indicate that they're
29443			// ready to be used before resolving the promise.
29444
29445			return new Promise( ( resolve ) => {
29446
29447				function checkMaterialsReady() {
29448
29449					materials.forEach( function ( material ) {
29450
29451						const materialProperties = properties.get( material );
29452						const program = materialProperties.currentProgram;
29453
29454						if ( program.isReady() ) {
29455
29456							// remove any programs that report they're ready to use from the list
29457							materials.delete( material );
29458
29459						}
29460
29461					} );
29462
29463					// once the list of compiling materials is empty, call the callback
29464
29465					if ( materials.size === 0 ) {
29466
29467						resolve( scene );
29468						return;
29469
29470					}
29471
29472					// if some materials are still not ready, wait a bit and check again
29473
29474					setTimeout( checkMaterialsReady, 10 );
29475
29476				}
29477
29478				if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) {
29479
29480					// If we can check the compilation status of the materials without
29481					// blocking then do so right away.
29482
29483					checkMaterialsReady();
29484
29485				} else {
29486
29487					// Otherwise start by waiting a bit to give the materials we just
29488					// initialized a chance to finish.
29489
29490					setTimeout( checkMaterialsReady, 10 );
29491
29492				}
29493
29494			} );
29495
29496		};
29497
29498		// Animation Loop
29499
29500		let onAnimationFrameCallback = null;
29501
29502		function onAnimationFrame( time ) {
29503
29504			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
29505
29506		}
29507
29508		function onXRSessionStart() {
29509
29510			animation.stop();
29511
29512		}
29513
29514		function onXRSessionEnd() {
29515
29516			animation.start();
29517
29518		}
29519
29520		const animation = new WebGLAnimation();
29521		animation.setAnimationLoop( onAnimationFrame );
29522
29523		if ( typeof self !== 'undefined' ) animation.setContext( self );
29524
29525		this.setAnimationLoop = function ( callback ) {
29526
29527			onAnimationFrameCallback = callback;
29528			xr.setAnimationLoop( callback );
29529
29530			( callback === null ) ? animation.stop() : animation.start();
29531
29532		};
29533
29534		xr.addEventListener( 'sessionstart', onXRSessionStart );
29535		xr.addEventListener( 'sessionend', onXRSessionEnd );
29536
29537		// Rendering
29538
29539		this.render = function ( scene, camera ) {
29540
29541			if ( camera !== undefined && camera.isCamera !== true ) {
29542
29543				console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
29544				return;
29545
29546			}
29547
29548			if ( _isContextLost === true ) return;
29549
29550			// update scene graph
29551
29552			if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
29553
29554			// update camera matrices and frustum
29555
29556			if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
29557
29558			if ( xr.enabled === true && xr.isPresenting === true ) {
29559
29560				if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
29561
29562				camera = xr.getCamera(); // use XR camera for rendering
29563
29564			}
29565
29566			//
29567			if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );
29568
29569			currentRenderState = renderStates.get( scene, renderStateStack.length );
29570			currentRenderState.init();
29571
29572			renderStateStack.push( currentRenderState );
29573
29574			_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
29575			_frustum.setFromProjectionMatrix( _projScreenMatrix );
29576
29577			_localClippingEnabled = this.localClippingEnabled;
29578			_clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );
29579
29580			currentRenderList = renderLists.get( scene, renderListStack.length );
29581			currentRenderList.init();
29582
29583			renderListStack.push( currentRenderList );
29584
29585			projectObject( scene, camera, 0, _this.sortObjects );
29586
29587			currentRenderList.finish();
29588
29589			if ( _this.sortObjects === true ) {
29590
29591				currentRenderList.sort( _opaqueSort, _transparentSort );
29592
29593			}
29594
29595			//
29596
29597			this.info.render.frame ++;
29598
29599			if ( _clippingEnabled === true ) clipping.beginShadows();
29600
29601			const shadowsArray = currentRenderState.state.shadowsArray;
29602
29603			shadowMap.render( shadowsArray, scene, camera );
29604
29605			if ( _clippingEnabled === true ) clipping.endShadows();
29606
29607			//
29608
29609			if ( this.info.autoReset === true ) this.info.reset();
29610
29611
29612			//
29613
29614			background.render( currentRenderList, scene );
29615
29616			// render scene
29617
29618			currentRenderState.setupLights( _this._useLegacyLights );
29619
29620			if ( camera.isArrayCamera ) {
29621
29622				const cameras = camera.cameras;
29623
29624				for ( let i = 0, l = cameras.length; i < l; i ++ ) {
29625
29626					const camera2 = cameras[ i ];
29627
29628					renderScene( currentRenderList, scene, camera2, camera2.viewport );
29629
29630				}
29631
29632			} else {
29633
29634				renderScene( currentRenderList, scene, camera );
29635
29636			}
29637
29638			//
29639
29640			if ( _currentRenderTarget !== null ) {
29641
29642				// resolve multisample renderbuffers to a single-sample texture if necessary
29643
29644				textures.updateMultisampleRenderTarget( _currentRenderTarget );
29645
29646				// Generate mipmap if we're using any kind of mipmap filtering
29647
29648				textures.updateRenderTargetMipmap( _currentRenderTarget );
29649
29650			}
29651
29652			//
29653
29654			if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
29655
29656			// _gl.finish();
29657
29658			bindingStates.resetDefaultState();
29659			_currentMaterialId = - 1;
29660			_currentCamera = null;
29661
29662			renderStateStack.pop();
29663
29664			if ( renderStateStack.length > 0 ) {
29665
29666				currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
29667
29668			} else {
29669
29670				currentRenderState = null;
29671
29672			}
29673
29674			renderListStack.pop();
29675
29676			if ( renderListStack.length > 0 ) {
29677
29678				currentRenderList = renderListStack[ renderListStack.length - 1 ];
29679
29680			} else {
29681
29682				currentRenderList = null;
29683
29684			}
29685
29686		};
29687
29688		function projectObject( object, camera, groupOrder, sortObjects ) {
29689
29690			if ( object.visible === false ) return;
29691
29692			const visible = object.layers.test( camera.layers );
29693
29694			if ( visible ) {
29695
29696				if ( object.isGroup ) {
29697
29698					groupOrder = object.renderOrder;
29699
29700				} else if ( object.isLOD ) {
29701
29702					if ( object.autoUpdate === true ) object.update( camera );
29703
29704				} else if ( object.isLight ) {
29705
29706					currentRenderState.pushLight( object );
29707
29708					if ( object.castShadow ) {
29709
29710						currentRenderState.pushShadow( object );
29711
29712					}
29713
29714				} else if ( object.isSprite ) {
29715
29716					if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
29717
29718						if ( sortObjects ) {
29719
29720							_vector3.setFromMatrixPosition( object.matrixWorld )
29721								.applyMatrix4( _projScreenMatrix );
29722
29723						}
29724
29725						const geometry = objects.update( object );
29726						const material = object.material;
29727
29728						if ( material.visible ) {
29729
29730							currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29731
29732						}
29733
29734					}
29735
29736				} else if ( object.isMesh || object.isLine || object.isPoints ) {
29737
29738					if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
29739
29740						const geometry = objects.update( object );
29741						const material = object.material;
29742
29743						if ( sortObjects ) {
29744
29745							if ( object.boundingSphere !== undefined ) {
29746
29747								if ( object.boundingSphere === null ) object.computeBoundingSphere();
29748								_vector3.copy( object.boundingSphere.center );
29749
29750							} else {
29751
29752								if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
29753								_vector3.copy( geometry.boundingSphere.center );
29754
29755							}
29756
29757							_vector3
29758								.applyMatrix4( object.matrixWorld )
29759								.applyMatrix4( _projScreenMatrix );
29760
29761						}
29762
29763						if ( Array.isArray( material ) ) {
29764
29765							const groups = geometry.groups;
29766
29767							for ( let i = 0, l = groups.length; i < l; i ++ ) {
29768
29769								const group = groups[ i ];
29770								const groupMaterial = material[ group.materialIndex ];
29771
29772								if ( groupMaterial && groupMaterial.visible ) {
29773
29774									currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
29775
29776								}
29777
29778							}
29779
29780						} else if ( material.visible ) {
29781
29782							currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29783
29784						}
29785
29786					}
29787
29788				}
29789
29790			}
29791
29792			const children = object.children;
29793
29794			for ( let i = 0, l = children.length; i < l; i ++ ) {
29795
29796				projectObject( children[ i ], camera, groupOrder, sortObjects );
29797
29798			}
29799
29800		}
29801
29802		function renderScene( currentRenderList, scene, camera, viewport ) {
29803
29804			const opaqueObjects = currentRenderList.opaque;
29805			const transmissiveObjects = currentRenderList.transmissive;
29806			const transparentObjects = currentRenderList.transparent;
29807
29808			currentRenderState.setupLightsView( camera );
29809
29810			if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
29811
29812			if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );
29813
29814			if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
29815
29816			if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
29817			if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
29818			if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
29819
29820			// Ensure depth buffer writing is enabled so it can be cleared on next render
29821
29822			state.buffers.depth.setTest( true );
29823			state.buffers.depth.setMask( true );
29824			state.buffers.color.setMask( true );
29825
29826			state.setPolygonOffset( false );
29827
29828		}
29829
29830		function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {
29831
29832			const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29833
29834			if ( overrideMaterial !== null ) {
29835
29836				return;
29837
29838			}
29839
29840			const isWebGL2 = capabilities.isWebGL2;
29841
29842			if ( _transmissionRenderTarget === null ) {
29843
29844				_transmissionRenderTarget = new WebGLRenderTarget( 1, 1, {
29845					generateMipmaps: true,
29846					type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
29847					minFilter: LinearMipmapLinearFilter,
29848					samples: ( isWebGL2 ) ? 4 : 0
29849				} );
29850
29851				// debug
29852
29853				/*
29854				const geometry = new PlaneGeometry();
29855				const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
29856
29857				const mesh = new Mesh( geometry, material );
29858				scene.add( mesh );
29859				*/
29860
29861			}
29862
29863			_this.getDrawingBufferSize( _vector2 );
29864
29865			if ( isWebGL2 ) {
29866
29867				_transmissionRenderTarget.setSize( _vector2.x, _vector2.y );
29868
29869			} else {
29870
29871				_transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) );
29872
29873			}
29874
29875			//
29876
29877			const currentRenderTarget = _this.getRenderTarget();
29878			_this.setRenderTarget( _transmissionRenderTarget );
29879
29880			_this.getClearColor( _currentClearColor );
29881			_currentClearAlpha = _this.getClearAlpha();
29882			if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
29883
29884			_this.clear();
29885
29886			// Turn off the features which can affect the frag color for opaque objects pass.
29887			// Otherwise they are applied twice in opaque objects pass and transmission objects pass.
29888			const currentToneMapping = _this.toneMapping;
29889			_this.toneMapping = NoToneMapping;
29890
29891			renderObjects( opaqueObjects, scene, camera );
29892
29893			textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29894			textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29895
29896			let renderTargetNeedsUpdate = false;
29897
29898			for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
29899
29900				const renderItem = transmissiveObjects[ i ];
29901
29902				const object = renderItem.object;
29903				const geometry = renderItem.geometry;
29904				const material = renderItem.material;
29905				const group = renderItem.group;
29906
29907				if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
29908
29909					const currentSide = material.side;
29910
29911					material.side = BackSide;
29912					material.needsUpdate = true;
29913
29914					renderObject( object, scene, camera, geometry, material, group );
29915
29916					material.side = currentSide;
29917					material.needsUpdate = true;
29918
29919					renderTargetNeedsUpdate = true;
29920
29921				}
29922
29923			}
29924
29925			if ( renderTargetNeedsUpdate === true ) {
29926
29927				textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29928				textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29929
29930			}
29931
29932			_this.setRenderTarget( currentRenderTarget );
29933
29934			_this.setClearColor( _currentClearColor, _currentClearAlpha );
29935
29936			_this.toneMapping = currentToneMapping;
29937
29938		}
29939
29940		function renderObjects( renderList, scene, camera ) {
29941
29942			const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29943
29944			for ( let i = 0, l = renderList.length; i < l; i ++ ) {
29945
29946				const renderItem = renderList[ i ];
29947
29948				const object = renderItem.object;
29949				const geometry = renderItem.geometry;
29950				const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
29951				const group = renderItem.group;
29952
29953				if ( object.layers.test( camera.layers ) ) {
29954
29955					renderObject( object, scene, camera, geometry, material, group );
29956
29957				}
29958
29959			}
29960
29961		}
29962
29963		function renderObject( object, scene, camera, geometry, material, group ) {
29964
29965			object.onBeforeRender( _this, scene, camera, geometry, material, group );
29966
29967			object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
29968			object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
29969
29970			material.onBeforeRender( _this, scene, camera, geometry, object, group );
29971
29972			if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29973
29974				material.side = BackSide;
29975				material.needsUpdate = true;
29976				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29977
29978				material.side = FrontSide;
29979				material.needsUpdate = true;
29980				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29981
29982				material.side = DoubleSide;
29983
29984			} else {
29985
29986				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29987
29988			}
29989
29990			object.onAfterRender( _this, scene, camera, geometry, material, group );
29991
29992		}
29993
29994		function getProgram( material, scene, object ) {
29995
29996			if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
29997
29998			const materialProperties = properties.get( material );
29999
30000			const lights = currentRenderState.state.lights;
30001			const shadowsArray = currentRenderState.state.shadowsArray;
30002
30003			const lightsStateVersion = lights.state.version;
30004
30005			const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
30006			const programCacheKey = programCache.getProgramCacheKey( parameters );
30007
30008			let programs = materialProperties.programs;
30009
30010			// always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
30011
30012			materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
30013			materialProperties.fog = scene.fog;
30014			materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
30015
30016			if ( programs === undefined ) {
30017
30018				// new material
30019
30020				material.addEventListener( 'dispose', onMaterialDispose );
30021
30022				programs = new Map();
30023				materialProperties.programs = programs;
30024
30025			}
30026
30027			let program = programs.get( programCacheKey );
30028
30029			if ( program !== undefined ) {
30030
30031				// early out if program and light state is identical
30032
30033				if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
30034
30035					updateCommonMaterialProperties( material, parameters );
30036
30037					return program;
30038
30039				}
30040
30041			} else {
30042
30043				parameters.uniforms = programCache.getUniforms( material );
30044
30045				material.onBuild( object, parameters, _this );
30046
30047				material.onBeforeCompile( parameters, _this );
30048
30049				program = programCache.acquireProgram( parameters, programCacheKey );
30050				programs.set( programCacheKey, program );
30051
30052				materialProperties.uniforms = parameters.uniforms;
30053
30054			}
30055
30056			const uniforms = materialProperties.uniforms;
30057
30058			if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
30059
30060				uniforms.clippingPlanes = clipping.uniform;
30061
30062			}
30063
30064			updateCommonMaterialProperties( material, parameters );
30065
30066			// store the light setup it was created for
30067
30068			materialProperties.needsLights = materialNeedsLights( material );
30069			materialProperties.lightsStateVersion = lightsStateVersion;
30070
30071			if ( materialProperties.needsLights ) {
30072
30073				// wire up the material to this renderer's lighting state
30074
30075				uniforms.ambientLightColor.value = lights.state.ambient;
30076				uniforms.lightProbe.value = lights.state.probe;
30077				uniforms.directionalLights.value = lights.state.directional;
30078				uniforms.directionalLightShadows.value = lights.state.directionalShadow;
30079				uniforms.spotLights.value = lights.state.spot;
30080				uniforms.spotLightShadows.value = lights.state.spotShadow;
30081				uniforms.rectAreaLights.value = lights.state.rectArea;
30082				uniforms.ltc_1.value = lights.state.rectAreaLTC1;
30083				uniforms.ltc_2.value = lights.state.rectAreaLTC2;
30084				uniforms.pointLights.value = lights.state.point;
30085				uniforms.pointLightShadows.value = lights.state.pointShadow;
30086				uniforms.hemisphereLights.value = lights.state.hemi;
30087
30088				uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
30089				uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
30090				uniforms.spotShadowMap.value = lights.state.spotShadowMap;
30091				uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
30092				uniforms.spotLightMap.value = lights.state.spotLightMap;
30093				uniforms.pointShadowMap.value = lights.state.pointShadowMap;
30094				uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
30095				// TODO (abelnation): add area lights shadow info to uniforms
30096
30097			}
30098
30099			materialProperties.currentProgram = program;
30100			materialProperties.uniformsList = null;
30101
30102			return program;
30103
30104		}
30105
30106		function getUniformList( materialProperties ) {
30107
30108			if ( materialProperties.uniformsList === null ) {
30109
30110				const progUniforms = materialProperties.currentProgram.getUniforms();
30111				materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );
30112
30113			}
30114
30115			return materialProperties.uniformsList;
30116
30117		}
30118
30119		function updateCommonMaterialProperties( material, parameters ) {
30120
30121			const materialProperties = properties.get( material );
30122
30123			materialProperties.outputColorSpace = parameters.outputColorSpace;
30124			materialProperties.batching = parameters.batching;
30125			materialProperties.instancing = parameters.instancing;
30126			materialProperties.instancingColor = parameters.instancingColor;
30127			materialProperties.skinning = parameters.skinning;
30128			materialProperties.morphTargets = parameters.morphTargets;
30129			materialProperties.morphNormals = parameters.morphNormals;
30130			materialProperties.morphColors = parameters.morphColors;
30131			materialProperties.morphTargetsCount = parameters.morphTargetsCount;
30132			materialProperties.numClippingPlanes = parameters.numClippingPlanes;
30133			materialProperties.numIntersection = parameters.numClipIntersection;
30134			materialProperties.vertexAlphas = parameters.vertexAlphas;
30135			materialProperties.vertexTangents = parameters.vertexTangents;
30136			materialProperties.toneMapping = parameters.toneMapping;
30137
30138		}
30139
30140		function setProgram( camera, scene, geometry, material, object ) {
30141
30142			if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
30143
30144			textures.resetTextureUnits();
30145
30146			const fog = scene.fog;
30147			const environment = material.isMeshStandardMaterial ? scene.environment : null;
30148			const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );
30149			const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
30150			const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
30151			const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );
30152			const morphTargets = !! geometry.morphAttributes.position;
30153			const morphNormals = !! geometry.morphAttributes.normal;
30154			const morphColors = !! geometry.morphAttributes.color;
30155
30156			let toneMapping = NoToneMapping;
30157
30158			if ( material.toneMapped ) {
30159
30160				if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {
30161
30162					toneMapping = _this.toneMapping;
30163
30164				}
30165
30166			}
30167
30168			const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
30169			const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
30170
30171			const materialProperties = properties.get( material );
30172			const lights = currentRenderState.state.lights;
30173
30174			if ( _clippingEnabled === true ) {
30175
30176				if ( _localClippingEnabled === true || camera !== _currentCamera ) {
30177
30178					const useCache =
30179						camera === _currentCamera &&
30180						material.id === _currentMaterialId;
30181
30182					// we might want to call this function with some ClippingGroup
30183					// object instead of the material, once it becomes feasible
30184					// (#8465, #8379)
30185					clipping.setState( material, camera, useCache );
30186
30187				}
30188
30189			}
30190
30191			//
30192
30193			let needsProgramChange = false;
30194
30195			if ( material.version === materialProperties.__version ) {
30196
30197				if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
30198
30199					needsProgramChange = true;
30200
30201				} else if ( materialProperties.outputColorSpace !== colorSpace ) {
30202
30203					needsProgramChange = true;
30204
30205				} else if ( object.isBatchedMesh && materialProperties.batching === false ) {
30206
30207					needsProgramChange = true;
30208
30209				} else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {
30210
30211					needsProgramChange = true;
30212
30213				} else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
30214
30215					needsProgramChange = true;
30216
30217				} else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
30218
30219					needsProgramChange = true;
30220
30221				} else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {
30222
30223					needsProgramChange = true;
30224
30225				} else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {
30226
30227					needsProgramChange = true;
30228
30229				} else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {
30230
30231					needsProgramChange = true;
30232
30233				} else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {
30234
30235					needsProgramChange = true;
30236
30237				} else if ( materialProperties.envMap !== envMap ) {
30238
30239					needsProgramChange = true;
30240
30241				} else if ( material.fog === true && materialProperties.fog !== fog ) {
30242
30243					needsProgramChange = true;
30244
30245				} else if ( materialProperties.numClippingPlanes !== undefined &&
30246					( materialProperties.numClippingPlanes !== clipping.numPlanes ||
30247					materialProperties.numIntersection !== clipping.numIntersection ) ) {
30248
30249					needsProgramChange = true;
30250
30251				} else if ( materialProperties.vertexAlphas !== vertexAlphas ) {
30252
30253					needsProgramChange = true;
30254
30255				} else if ( materialProperties.vertexTangents !== vertexTangents ) {
30256
30257					needsProgramChange = true;
30258
30259				} else if ( materialProperties.morphTargets !== morphTargets ) {
30260
30261					needsProgramChange = true;
30262
30263				} else if ( materialProperties.morphNormals !== morphNormals ) {
30264
30265					needsProgramChange = true;
30266
30267				} else if ( materialProperties.morphColors !== morphColors ) {
30268
30269					needsProgramChange = true;
30270
30271				} else if ( materialProperties.toneMapping !== toneMapping ) {
30272
30273					needsProgramChange = true;
30274
30275				} else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) {
30276
30277					needsProgramChange = true;
30278
30279				}
30280
30281			} else {
30282
30283				needsProgramChange = true;
30284				materialProperties.__version = material.version;
30285
30286			}
30287
30288			//
30289
30290			let program = materialProperties.currentProgram;
30291
30292			if ( needsProgramChange === true ) {
30293
30294				program = getProgram( material, scene, object );
30295
30296			}
30297
30298			let refreshProgram = false;
30299			let refreshMaterial = false;
30300			let refreshLights = false;
30301
30302			const p_uniforms = program.getUniforms(),
30303				m_uniforms = materialProperties.uniforms;
30304
30305			if ( state.useProgram( program.program ) ) {
30306
30307				refreshProgram = true;
30308				refreshMaterial = true;
30309				refreshLights = true;
30310
30311			}
30312
30313			if ( material.id !== _currentMaterialId ) {
30314
30315				_currentMaterialId = material.id;
30316
30317				refreshMaterial = true;
30318
30319			}
30320
30321			if ( refreshProgram || _currentCamera !== camera ) {
30322
30323				// common camera uniforms
30324
30325				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
30326				p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
30327
30328				const uCamPos = p_uniforms.map.cameraPosition;
30329
30330				if ( uCamPos !== undefined ) {
30331
30332					uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
30333
30334				}
30335
30336				if ( capabilities.logarithmicDepthBuffer ) {
30337
30338					p_uniforms.setValue( _gl, 'logDepthBufFC',
30339						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
30340
30341				}
30342
30343				// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
30344
30345				if ( material.isMeshPhongMaterial ||
30346					material.isMeshToonMaterial ||
30347					material.isMeshLambertMaterial ||
30348					material.isMeshBasicMaterial ||
30349					material.isMeshStandardMaterial ||
30350					material.isShaderMaterial ) {
30351
30352					p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
30353
30354				}
30355
30356				if ( _currentCamera !== camera ) {
30357
30358					_currentCamera = camera;
30359
30360					// lighting uniforms depend on the camera so enforce an update
30361					// now, in case this material supports lights - or later, when
30362					// the next material that does gets activated:
30363
30364					refreshMaterial = true;		// set to true on material change
30365					refreshLights = true;		// remains set until update done
30366
30367				}
30368
30369			}
30370
30371			// skinning and morph target uniforms must be set even if material didn't change
30372			// auto-setting of texture unit for bone and morph texture must go before other textures
30373			// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
30374
30375			if ( object.isSkinnedMesh ) {
30376
30377				p_uniforms.setOptional( _gl, object, 'bindMatrix' );
30378				p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
30379
30380				const skeleton = object.skeleton;
30381
30382				if ( skeleton ) {
30383
30384					if ( capabilities.floatVertexTextures ) {
30385
30386						if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();
30387
30388						p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
30389
30390					} else {
30391
30392						console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' );
30393
30394					}
30395
30396				}
30397
30398			}
30399
30400			if ( object.isBatchedMesh ) {
30401
30402				p_uniforms.setOptional( _gl, object, 'batchingTexture' );
30403				p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );
30404
30405			}
30406
30407			const morphAttributes = geometry.morphAttributes;
30408
30409			if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
30410
30411				morphtargets.update( object, geometry, program );
30412
30413			}
30414
30415			if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
30416
30417				materialProperties.receiveShadow = object.receiveShadow;
30418				p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
30419
30420			}
30421
30422			// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
30423
30424			if ( material.isMeshGouraudMaterial && material.envMap !== null ) {
30425
30426				m_uniforms.envMap.value = envMap;
30427
30428				m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
30429
30430			}
30431
30432			if ( refreshMaterial ) {
30433
30434				p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
30435
30436				if ( materialProperties.needsLights ) {
30437
30438					// the current material requires lighting info
30439
30440					// note: all lighting uniforms are always set correctly
30441					// they simply reference the renderer's state for their
30442					// values
30443					//
30444					// use the current material's .needsUpdate flags to set
30445					// the GL state when required
30446
30447					markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
30448
30449				}
30450
30451				// refresh uniforms common to several materials
30452
30453				if ( fog && material.fog === true ) {
30454
30455					materials.refreshFogUniforms( m_uniforms, fog );
30456
30457				}
30458
30459				materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget );
30460
30461				WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
30462
30463			}
30464
30465			if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
30466
30467				WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
30468				material.uniformsNeedUpdate = false;
30469
30470			}
30471
30472			if ( material.isSpriteMaterial ) {
30473
30474				p_uniforms.setValue( _gl, 'center', object.center );
30475
30476			}
30477
30478			// common matrices
30479
30480			p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
30481			p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
30482			p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
30483
30484			// UBOs
30485
30486			if ( material.isShaderMaterial || material.isRawShaderMaterial ) {
30487
30488				const groups = material.uniformsGroups;
30489
30490				for ( let i = 0, l = groups.length; i < l; i ++ ) {
30491
30492					if ( capabilities.isWebGL2 ) {
30493
30494						const group = groups[ i ];
30495
30496						uniformsGroups.update( group, program );
30497						uniformsGroups.bind( group, program );
30498
30499					} else {
30500
30501						console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' );
30502
30503					}
30504
30505				}
30506
30507			}
30508
30509			return program;
30510
30511		}
30512
30513		// If uniforms are marked as clean, they don't need to be loaded to the GPU.
30514
30515		function markUniformsLightsNeedsUpdate( uniforms, value ) {
30516
30517			uniforms.ambientLightColor.needsUpdate = value;
30518			uniforms.lightProbe.needsUpdate = value;
30519
30520			uniforms.directionalLights.needsUpdate = value;
30521			uniforms.directionalLightShadows.needsUpdate = value;
30522			uniforms.pointLights.needsUpdate = value;
30523			uniforms.pointLightShadows.needsUpdate = value;
30524			uniforms.spotLights.needsUpdate = value;
30525			uniforms.spotLightShadows.needsUpdate = value;
30526			uniforms.rectAreaLights.needsUpdate = value;
30527			uniforms.hemisphereLights.needsUpdate = value;
30528
30529		}
30530
30531		function materialNeedsLights( material ) {
30532
30533			return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
30534				material.isMeshStandardMaterial || material.isShadowMaterial ||
30535				( material.isShaderMaterial && material.lights === true );
30536
30537		}
30538
30539		this.getActiveCubeFace = function () {
30540
30541			return _currentActiveCubeFace;
30542
30543		};
30544
30545		this.getActiveMipmapLevel = function () {
30546
30547			return _currentActiveMipmapLevel;
30548
30549		};
30550
30551		this.getRenderTarget = function () {
30552
30553			return _currentRenderTarget;
30554
30555		};
30556
30557		this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {
30558
30559			properties.get( renderTarget.texture ).__webglTexture = colorTexture;
30560			properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;
30561
30562			const renderTargetProperties = properties.get( renderTarget );
30563			renderTargetProperties.__hasExternalTextures = true;
30564
30565			if ( renderTargetProperties.__hasExternalTextures ) {
30566
30567				renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
30568
30569				if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
30570
30571					// The multisample_render_to_texture extension doesn't work properly if there
30572					// are midframe flushes and an external depth buffer. Disable use of the extension.
30573					if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {
30574
30575						console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
30576						renderTargetProperties.__useRenderToTexture = false;
30577
30578					}
30579
30580				}
30581
30582			}
30583
30584		};
30585
30586		this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {
30587
30588			const renderTargetProperties = properties.get( renderTarget );
30589			renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
30590			renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;
30591
30592		};
30593
30594		this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
30595
30596			_currentRenderTarget = renderTarget;
30597			_currentActiveCubeFace = activeCubeFace;
30598			_currentActiveMipmapLevel = activeMipmapLevel;
30599
30600			let useDefaultFramebuffer = true;
30601			let framebuffer = null;
30602			let isCube = false;
30603			let isRenderTarget3D = false;
30604
30605			if ( renderTarget ) {
30606
30607				const renderTargetProperties = properties.get( renderTarget );
30608
30609				if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {
30610
30611					// We need to make sure to rebind the framebuffer.
30612					state.bindFramebuffer( _gl.FRAMEBUFFER, null );
30613					useDefaultFramebuffer = false;
30614
30615				} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {
30616
30617					textures.setupRenderTarget( renderTarget );
30618
30619				} else if ( renderTargetProperties.__hasExternalTextures ) {
30620
30621					// Color and depth texture must be rebound in order for the swapchain to update.
30622					textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );
30623
30624				}
30625
30626				const texture = renderTarget.texture;
30627
30628				if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30629
30630					isRenderTarget3D = true;
30631
30632				}
30633
30634				const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
30635
30636				if ( renderTarget.isWebGLCubeRenderTarget ) {
30637
30638					if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {
30639
30640						framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];
30641
30642					} else {
30643
30644						framebuffer = __webglFramebuffer[ activeCubeFace ];
30645
30646					}
30647
30648					isCube = true;
30649
30650				} else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {
30651
30652					framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
30653
30654				} else {
30655
30656					if ( Array.isArray( __webglFramebuffer ) ) {
30657
30658						framebuffer = __webglFramebuffer[ activeMipmapLevel ];
30659
30660					} else {
30661
30662						framebuffer = __webglFramebuffer;
30663
30664					}
30665
30666				}
30667
30668				_currentViewport.copy( renderTarget.viewport );
30669				_currentScissor.copy( renderTarget.scissor );
30670				_currentScissorTest = renderTarget.scissorTest;
30671
30672			} else {
30673
30674				_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
30675				_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
30676				_currentScissorTest = _scissorTest;
30677
30678			}
30679
30680			const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30681
30682			if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) {
30683
30684				state.drawBuffers( renderTarget, framebuffer );
30685
30686			}
30687
30688			state.viewport( _currentViewport );
30689			state.scissor( _currentScissor );
30690			state.setScissorTest( _currentScissorTest );
30691
30692			if ( isCube ) {
30693
30694				const textureProperties = properties.get( renderTarget.texture );
30695				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
30696
30697			} else if ( isRenderTarget3D ) {
30698
30699				const textureProperties = properties.get( renderTarget.texture );
30700				const layer = activeCubeFace || 0;
30701				_gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );
30702
30703			}
30704
30705			_currentMaterialId = - 1; // reset current material to ensure correct uniform bindings
30706
30707		};
30708
30709		this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
30710
30711			if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
30712
30713				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
30714				return;
30715
30716			}
30717
30718			let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
30719
30720			if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
30721
30722				framebuffer = framebuffer[ activeCubeFaceIndex ];
30723
30724			}
30725
30726			if ( framebuffer ) {
30727
30728				state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30729
30730				try {
30731
30732					const texture = renderTarget.texture;
30733					const textureFormat = texture.format;
30734					const textureType = texture.type;
30735
30736					if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
30737
30738						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
30739						return;
30740
30741					}
30742
30743					const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
30744
30745					if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
30746						! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
30747						! halfFloatSupportedByExt ) {
30748
30749						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
30750						return;
30751
30752					}
30753
30754					// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
30755
30756					if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
30757
30758						_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
30759
30760					}
30761
30762				} finally {
30763
30764					// restore framebuffer of current render target if necessary
30765
30766					const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
30767					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30768
30769				}
30770
30771			}
30772
30773		};
30774
30775		this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
30776
30777			const levelScale = Math.pow( 2, - level );
30778			const width = Math.floor( texture.image.width * levelScale );
30779			const height = Math.floor( texture.image.height * levelScale );
30780
30781			textures.setTexture2D( texture, 0 );
30782
30783			_gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height );
30784
30785			state.unbindTexture();
30786
30787		};
30788
30789		this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
30790
30791			const width = srcTexture.image.width;
30792			const height = srcTexture.image.height;
30793			const glFormat = utils.convert( dstTexture.format );
30794			const glType = utils.convert( dstTexture.type );
30795
30796			textures.setTexture2D( dstTexture, 0 );
30797
30798			// As another texture upload may have changed pixelStorei
30799			// parameters, make sure they are correct for the dstTexture
30800			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30801			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30802			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30803
30804			if ( srcTexture.isDataTexture ) {
30805
30806				_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
30807
30808			} else {
30809
30810				if ( srcTexture.isCompressedTexture ) {
30811
30812					_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
30813
30814				} else {
30815
30816					_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
30817
30818				}
30819
30820			}
30821
30822			// Generate mipmaps only when copying level 0
30823			if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );
30824
30825			state.unbindTexture();
30826
30827		};
30828
30829		this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
30830
30831			if ( _this.isWebGL1Renderer ) {
30832
30833				console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' );
30834				return;
30835
30836			}
30837
30838			const width = sourceBox.max.x - sourceBox.min.x + 1;
30839			const height = sourceBox.max.y - sourceBox.min.y + 1;
30840			const depth = sourceBox.max.z - sourceBox.min.z + 1;
30841			const glFormat = utils.convert( dstTexture.format );
30842			const glType = utils.convert( dstTexture.type );
30843			let glTarget;
30844
30845			if ( dstTexture.isData3DTexture ) {
30846
30847				textures.setTexture3D( dstTexture, 0 );
30848				glTarget = _gl.TEXTURE_3D;
30849
30850			} else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {
30851
30852				textures.setTexture2DArray( dstTexture, 0 );
30853				glTarget = _gl.TEXTURE_2D_ARRAY;
30854
30855			} else {
30856
30857				console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );
30858				return;
30859
30860			}
30861
30862			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30863			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30864			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30865
30866			const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
30867			const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
30868			const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
30869			const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
30870			const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );
30871
30872			const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
30873
30874			_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
30875			_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
30876			_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x );
30877			_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );
30878			_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z );
30879
30880			if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {
30881
30882				_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
30883
30884			} else {
30885
30886				if ( srcTexture.isCompressedArrayTexture ) {
30887
30888					console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' );
30889					_gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
30890
30891				} else {
30892
30893					_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
30894
30895				}
30896
30897			}
30898
30899			_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen );
30900			_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight );
30901			_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels );
30902			_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows );
30903			_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages );
30904
30905			// Generate mipmaps only when copying level 0
30906			if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
30907
30908			state.unbindTexture();
30909
30910		};
30911
30912		this.initTexture = function ( texture ) {
30913
30914			if ( texture.isCubeTexture ) {
30915
30916				textures.setTextureCube( texture, 0 );
30917
30918			} else if ( texture.isData3DTexture ) {
30919
30920				textures.setTexture3D( texture, 0 );
30921
30922			} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30923
30924				textures.setTexture2DArray( texture, 0 );
30925
30926			} else {
30927
30928				textures.setTexture2D( texture, 0 );
30929
30930			}
30931
30932			state.unbindTexture();
30933
30934		};
30935
30936		this.resetState = function () {
30937
30938			_currentActiveCubeFace = 0;
30939			_currentActiveMipmapLevel = 0;
30940			_currentRenderTarget = null;
30941
30942			state.reset();
30943			bindingStates.reset();
30944
30945		};
30946
30947		if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
30948
30949			__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
30950
30951		}
30952
30953	}
30954
30955	get coordinateSystem() {
30956
30957		return WebGLCoordinateSystem;
30958
30959	}
30960
30961	get outputColorSpace() {
30962
30963		return this._outputColorSpace;
30964
30965	}
30966
30967	set outputColorSpace( colorSpace ) {
30968
30969		this._outputColorSpace = colorSpace;
30970
30971		const gl = this.getContext();
30972		gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';
30973		gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';
30974
30975	}
30976
30977	get outputEncoding() { // @deprecated, r152
30978
30979		console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30980		return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding;
30981
30982	}
30983
30984	set outputEncoding( encoding ) { // @deprecated, r152
30985
30986		console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30987		this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
30988
30989	}
30990
30991	get useLegacyLights() { // @deprecated, r155
30992
30993		console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
30994		return this._useLegacyLights;
30995
30996	}
30997
30998	set useLegacyLights( value ) { // @deprecated, r155
30999
31000		console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
31001		this._useLegacyLights = value;
31002
31003	}
31004
31005}
31006
31007class WebGL1Renderer extends WebGLRenderer {}
31008
31009WebGL1Renderer.prototype.isWebGL1Renderer = true;
31010
31011class FogExp2 {
31012
31013	constructor( color, density = 0.00025 ) {
31014
31015		this.isFogExp2 = true;
31016
31017		this.name = '';
31018
31019		this.color = new Color( color );
31020		this.density = density;
31021
31022	}
31023
31024	clone() {
31025
31026		return new FogExp2( this.color, this.density );
31027
31028	}
31029
31030	toJSON( /* meta */ ) {
31031
31032		return {
31033			type: 'FogExp2',
31034			name: this.name,
vendor: 5,247 bytes, lines 31035-31334
31035			color: this.color.getHex(),
31036			density: this.density
31037		};
31038
31039	}
31040
31041}
31042
31043class Fog {
31044
31045	constructor( color, near = 1, far = 1000 ) {
31046
31047		this.isFog = true;
31048
31049		this.name = '';
31050
31051		this.color = new Color( color );
31052
31053		this.near = near;
31054		this.far = far;
31055
31056	}
31057
31058	clone() {
31059
31060		return new Fog( this.color, this.near, this.far );
31061
31062	}
31063
31064	toJSON( /* meta */ ) {
31065
31066		return {
31067			type: 'Fog',
31068			name: this.name,
31069			color: this.color.getHex(),
31070			near: this.near,
31071			far: this.far
31072		};
31073
31074	}
31075
31076}
31077
31078class Scene extends Object3D {
31079
31080	constructor() {
31081
31082		super();
31083
31084		this.isScene = true;
31085
31086		this.type = 'Scene';
31087
31088		this.background = null;
31089		this.environment = null;
31090		this.fog = null;
31091
31092		this.backgroundBlurriness = 0;
31093		this.backgroundIntensity = 1;
31094
31095		this.overrideMaterial = null;
31096
31097		if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
31098
31099			__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
31100
31101		}
31102
31103	}
31104
31105	copy( source, recursive ) {
31106
31107		super.copy( source, recursive );
31108
31109		if ( source.background !== null ) this.background = source.background.clone();
31110		if ( source.environment !== null ) this.environment = source.environment.clone();
31111		if ( source.fog !== null ) this.fog = source.fog.clone();
31112
31113		this.backgroundBlurriness = source.backgroundBlurriness;
31114		this.backgroundIntensity = source.backgroundIntensity;
31115
31116		if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
31117
31118		this.matrixAutoUpdate = source.matrixAutoUpdate;
31119
31120		return this;
31121
31122	}
31123
31124	toJSON( meta ) {
31125
31126		const data = super.toJSON( meta );
31127
31128		if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
31129		if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness;
31130		if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity;
31131
31132		return data;
31133
31134	}
31135
31136}
31137
31138class InterleavedBuffer {
31139
31140	constructor( array, stride ) {
31141
31142		this.isInterleavedBuffer = true;
31143
31144		this.array = array;
31145		this.stride = stride;
31146		this.count = array !== undefined ? array.length / stride : 0;
31147
31148		this.usage = StaticDrawUsage;
31149		this._updateRange = { offset: 0, count: - 1 };
31150		this.updateRanges = [];
31151
31152		this.version = 0;
31153
31154		this.uuid = generateUUID();
31155
31156	}
31157
31158	onUploadCallback() {}
31159
31160	set needsUpdate( value ) {
31161
31162		if ( value === true ) this.version ++;
31163
31164	}
31165
31166	get updateRange() {
31167
31168		console.warn( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
31169		return this._updateRange;
31170
31171	}
31172
31173	setUsage( value ) {
31174
31175		this.usage = value;
31176
31177		return this;
31178
31179	}
31180
31181	addUpdateRange( start, count ) {
31182
31183		this.updateRanges.push( { start, count } );
31184
31185	}
31186
31187	clearUpdateRanges() {
31188
31189		this.updateRanges.length = 0;
31190
31191	}
31192
31193	copy( source ) {
31194
31195		this.array = new source.array.constructor( source.array );
31196		this.count = source.count;
31197		this.stride = source.stride;
31198		this.usage = source.usage;
31199
31200		return this;
31201
31202	}
31203
31204	copyAt( index1, attribute, index2 ) {
31205
31206		index1 *= this.stride;
31207		index2 *= attribute.stride;
31208
31209		for ( let i = 0, l = this.stride; i < l; i ++ ) {
31210
31211			this.array[ index1 + i ] = attribute.array[ index2 + i ];
31212
31213		}
31214
31215		return this;
31216
31217	}
31218
31219	set( value, offset = 0 ) {
31220
31221		this.array.set( value, offset );
31222
31223		return this;
31224
31225	}
31226
31227	clone( data ) {
31228
31229		if ( data.arrayBuffers === undefined ) {
31230
31231			data.arrayBuffers = {};
31232
31233		}
31234
31235		if ( this.array.buffer._uuid === undefined ) {
31236
31237			this.array.buffer._uuid = generateUUID();
31238
31239		}
31240
31241		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31242
31243			data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
31244
31245		}
31246
31247		const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
31248
31249		const ib = new this.constructor( array, this.stride );
31250		ib.setUsage( this.usage );
31251
31252		return ib;
31253
31254	}
31255
31256	onUpload( callback ) {
31257
31258		this.onUploadCallback = callback;
31259
31260		return this;
31261
31262	}
31263
31264	toJSON( data ) {
31265
31266		if ( data.arrayBuffers === undefined ) {
31267
31268			data.arrayBuffers = {};
31269
31270		}
31271
31272		// generate UUID for array buffer if necessary
31273
31274		if ( this.array.buffer._uuid === undefined ) {
31275
31276			this.array.buffer._uuid = generateUUID();
31277
31278		}
31279
31280		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31281
31282			data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );
31283
31284		}
31285
31286		//
31287
31288		return {
31289			uuid: this.uuid,
31290			buffer: this.array.buffer._uuid,
31291			type: this.array.constructor.name,
31292			stride: this.stride
31293		};
31294
31295	}
31296
31297}
31298
31299const _vector$6 = /*@__PURE__*/ new Vector3();
31300
31301class InterleavedBufferAttribute {
31302
31303	constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
31304
31305		this.isInterleavedBufferAttribute = true;
31306
31307		this.name = '';
31308
31309		this.data = interleavedBuffer;
31310		this.itemSize = itemSize;
31311		this.offset = offset;
31312
31313		this.normalized = normalized;
31314
31315	}
31316
31317	get count() {
31318
31319		return this.data.count;
31320
31321	}
31322
31323	get array() {
31324
31325		return this.data.array;
31326
31327	}
31328
31329	set needsUpdate( value ) {
31330
31331		this.data.needsUpdate = value;
31332
31333	}
31334
vendor: 17,794 bytes, lines 31335-32237
31335	applyMatrix4( m ) {
31336
31337		for ( let i = 0, l = this.data.count; i < l; i ++ ) {
31338
31339			_vector$6.fromBufferAttribute( this, i );
31340
31341			_vector$6.applyMatrix4( m );
31342
31343			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31344
31345		}
31346
31347		return this;
31348
31349	}
31350
31351	applyNormalMatrix( m ) {
31352
31353		for ( let i = 0, l = this.count; i < l; i ++ ) {
31354
31355			_vector$6.fromBufferAttribute( this, i );
31356
31357			_vector$6.applyNormalMatrix( m );
31358
31359			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31360
31361		}
31362
31363		return this;
31364
31365	}
31366
31367	transformDirection( m ) {
31368
31369		for ( let i = 0, l = this.count; i < l; i ++ ) {
31370
31371			_vector$6.fromBufferAttribute( this, i );
31372
31373			_vector$6.transformDirection( m );
31374
31375			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31376
31377		}
31378
31379		return this;
31380
31381	}
31382
31383	setX( index, x ) {
31384
31385		if ( this.normalized ) x = normalize( x, this.array );
31386
31387		this.data.array[ index * this.data.stride + this.offset ] = x;
31388
31389		return this;
31390
31391	}
31392
31393	setY( index, y ) {
31394
31395		if ( this.normalized ) y = normalize( y, this.array );
31396
31397		this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
31398
31399		return this;
31400
31401	}
31402
31403	setZ( index, z ) {
31404
31405		if ( this.normalized ) z = normalize( z, this.array );
31406
31407		this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
31408
31409		return this;
31410
31411	}
31412
31413	setW( index, w ) {
31414
31415		if ( this.normalized ) w = normalize( w, this.array );
31416
31417		this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
31418
31419		return this;
31420
31421	}
31422
31423	getX( index ) {
31424
31425		let x = this.data.array[ index * this.data.stride + this.offset ];
31426
31427		if ( this.normalized ) x = denormalize( x, this.array );
31428
31429		return x;
31430
31431	}
31432
31433	getY( index ) {
31434
31435		let y = this.data.array[ index * this.data.stride + this.offset + 1 ];
31436
31437		if ( this.normalized ) y = denormalize( y, this.array );
31438
31439		return y;
31440
31441	}
31442
31443	getZ( index ) {
31444
31445		let z = this.data.array[ index * this.data.stride + this.offset + 2 ];
31446
31447		if ( this.normalized ) z = denormalize( z, this.array );
31448
31449		return z;
31450
31451	}
31452
31453	getW( index ) {
31454
31455		let w = this.data.array[ index * this.data.stride + this.offset + 3 ];
31456
31457		if ( this.normalized ) w = denormalize( w, this.array );
31458
31459		return w;
31460
31461	}
31462
31463	setXY( index, x, y ) {
31464
31465		index = index * this.data.stride + this.offset;
31466
31467		if ( this.normalized ) {
31468
31469			x = normalize( x, this.array );
31470			y = normalize( y, this.array );
31471
31472		}
31473
31474		this.data.array[ index + 0 ] = x;
31475		this.data.array[ index + 1 ] = y;
31476
31477		return this;
31478
31479	}
31480
31481	setXYZ( index, x, y, z ) {
31482
31483		index = index * this.data.stride + this.offset;
31484
31485		if ( this.normalized ) {
31486
31487			x = normalize( x, this.array );
31488			y = normalize( y, this.array );
31489			z = normalize( z, this.array );
31490
31491		}
31492
31493		this.data.array[ index + 0 ] = x;
31494		this.data.array[ index + 1 ] = y;
31495		this.data.array[ index + 2 ] = z;
31496
31497		return this;
31498
31499	}
31500
31501	setXYZW( index, x, y, z, w ) {
31502
31503		index = index * this.data.stride + this.offset;
31504
31505		if ( this.normalized ) {
31506
31507			x = normalize( x, this.array );
31508			y = normalize( y, this.array );
31509			z = normalize( z, this.array );
31510			w = normalize( w, this.array );
31511
31512		}
31513
31514		this.data.array[ index + 0 ] = x;
31515		this.data.array[ index + 1 ] = y;
31516		this.data.array[ index + 2 ] = z;
31517		this.data.array[ index + 3 ] = w;
31518
31519		return this;
31520
31521	}
31522
31523	clone( data ) {
31524
31525		if ( data === undefined ) {
31526
31527			console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );
31528
31529			const array = [];
31530
31531			for ( let i = 0; i < this.count; i ++ ) {
31532
31533				const index = i * this.data.stride + this.offset;
31534
31535				for ( let j = 0; j < this.itemSize; j ++ ) {
31536
31537					array.push( this.data.array[ index + j ] );
31538
31539				}
31540
31541			}
31542
31543			return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
31544
31545		} else {
31546
31547			if ( data.interleavedBuffers === undefined ) {
31548
31549				data.interleavedBuffers = {};
31550
31551			}
31552
31553			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31554
31555				data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
31556
31557			}
31558
31559			return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
31560
31561		}
31562
31563	}
31564
31565	toJSON( data ) {
31566
31567		if ( data === undefined ) {
31568
31569			console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );
31570
31571			const array = [];
31572
31573			for ( let i = 0; i < this.count; i ++ ) {
31574
31575				const index = i * this.data.stride + this.offset;
31576
31577				for ( let j = 0; j < this.itemSize; j ++ ) {
31578
31579					array.push( this.data.array[ index + j ] );
31580
31581				}
31582
31583			}
31584
31585			// de-interleave data and save it as an ordinary buffer attribute for now
31586
31587			return {
31588				itemSize: this.itemSize,
31589				type: this.array.constructor.name,
31590				array: array,
31591				normalized: this.normalized
31592			};
31593
31594		} else {
31595
31596			// save as true interleaved attribute
31597
31598			if ( data.interleavedBuffers === undefined ) {
31599
31600				data.interleavedBuffers = {};
31601
31602			}
31603
31604			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31605
31606				data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
31607
31608			}
31609
31610			return {
31611				isInterleavedBufferAttribute: true,
31612				itemSize: this.itemSize,
31613				data: this.data.uuid,
31614				offset: this.offset,
31615				normalized: this.normalized
31616			};
31617
31618		}
31619
31620	}
31621
31622}
31623
31624class SpriteMaterial extends Material {
31625
31626	constructor( parameters ) {
31627
31628		super();
31629
31630		this.isSpriteMaterial = true;
31631
31632		this.type = 'SpriteMaterial';
31633
31634		this.color = new Color( 0xffffff );
31635
31636		this.map = null;
31637
31638		this.alphaMap = null;
31639
31640		this.rotation = 0;
31641
31642		this.sizeAttenuation = true;
31643
31644		this.transparent = true;
31645
31646		this.fog = true;
31647
31648		this.setValues( parameters );
31649
31650	}
31651
31652	copy( source ) {
31653
31654		super.copy( source );
31655
31656		this.color.copy( source.color );
31657
31658		this.map = source.map;
31659
31660		this.alphaMap = source.alphaMap;
31661
31662		this.rotation = source.rotation;
31663
31664		this.sizeAttenuation = source.sizeAttenuation;
31665
31666		this.fog = source.fog;
31667
31668		return this;
31669
31670	}
31671
31672}
31673
31674let _geometry;
31675
31676const _intersectPoint = /*@__PURE__*/ new Vector3();
31677const _worldScale = /*@__PURE__*/ new Vector3();
31678const _mvPosition = /*@__PURE__*/ new Vector3();
31679
31680const _alignedPosition = /*@__PURE__*/ new Vector2();
31681const _rotatedPosition = /*@__PURE__*/ new Vector2();
31682const _viewWorldMatrix = /*@__PURE__*/ new Matrix4();
31683
31684const _vA = /*@__PURE__*/ new Vector3();
31685const _vB = /*@__PURE__*/ new Vector3();
31686const _vC = /*@__PURE__*/ new Vector3();
31687
31688const _uvA = /*@__PURE__*/ new Vector2();
31689const _uvB = /*@__PURE__*/ new Vector2();
31690const _uvC = /*@__PURE__*/ new Vector2();
31691
31692class Sprite extends Object3D {
31693
31694	constructor( material = new SpriteMaterial() ) {
31695
31696		super();
31697
31698		this.isSprite = true;
31699
31700		this.type = 'Sprite';
31701
31702		if ( _geometry === undefined ) {
31703
31704			_geometry = new BufferGeometry();
31705
31706			const float32Array = new Float32Array( [
31707				- 0.5, - 0.5, 0, 0, 0,
31708				0.5, - 0.5, 0, 1, 0,
31709				0.5, 0.5, 0, 1, 1,
31710				- 0.5, 0.5, 0, 0, 1
31711			] );
31712
31713			const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
31714
31715			_geometry.setIndex( [ 0, 1, 2,	0, 2, 3 ] );
31716			_geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
31717			_geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
31718
31719		}
31720
31721		this.geometry = _geometry;
31722		this.material = material;
31723
31724		this.center = new Vector2( 0.5, 0.5 );
31725
31726	}
31727
31728	raycast( raycaster, intersects ) {
31729
31730		if ( raycaster.camera === null ) {
31731
31732			console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
31733
31734		}
31735
31736		_worldScale.setFromMatrixScale( this.matrixWorld );
31737
31738		_viewWorldMatrix.copy( raycaster.camera.matrixWorld );
31739		this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
31740
31741		_mvPosition.setFromMatrixPosition( this.modelViewMatrix );
31742
31743		if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
31744
31745			_worldScale.multiplyScalar( - _mvPosition.z );
31746
31747		}
31748
31749		const rotation = this.material.rotation;
31750		let sin, cos;
31751
31752		if ( rotation !== 0 ) {
31753
31754			cos = Math.cos( rotation );
31755			sin = Math.sin( rotation );
31756
31757		}
31758
31759		const center = this.center;
31760
31761		transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31762		transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31763		transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31764
31765		_uvA.set( 0, 0 );
31766		_uvB.set( 1, 0 );
31767		_uvC.set( 1, 1 );
31768
31769		// check first triangle
31770		let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );
31771
31772		if ( intersect === null ) {
31773
31774			// check second triangle
31775			transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31776			_uvB.set( 0, 1 );
31777
31778			intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );
31779			if ( intersect === null ) {
31780
31781				return;
31782
31783			}
31784
31785		}
31786
31787		const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
31788
31789		if ( distance < raycaster.near || distance > raycaster.far ) return;
31790
31791		intersects.push( {
31792
31793			distance: distance,
31794			point: _intersectPoint.clone(),
31795			uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),
31796			face: null,
31797			object: this
31798
31799		} );
31800
31801	}
31802
31803	copy( source, recursive ) {
31804
31805		super.copy( source, recursive );
31806
31807		if ( source.center !== undefined ) this.center.copy( source.center );
31808
31809		this.material = source.material;
31810
31811		return this;
31812
31813	}
31814
31815}
31816
31817function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
31818
31819	// compute position in camera space
31820	_alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
31821
31822	// to check if rotation is not zero
31823	if ( sin !== undefined ) {
31824
31825		_rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
31826		_rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
31827
31828	} else {
31829
31830		_rotatedPosition.copy( _alignedPosition );
31831
31832	}
31833
31834
31835	vertexPosition.copy( mvPosition );
31836	vertexPosition.x += _rotatedPosition.x;
31837	vertexPosition.y += _rotatedPosition.y;
31838
31839	// transform to world space
31840	vertexPosition.applyMatrix4( _viewWorldMatrix );
31841
31842}
31843
31844const _v1$2 = /*@__PURE__*/ new Vector3();
31845const _v2$1 = /*@__PURE__*/ new Vector3();
31846
31847class LOD extends Object3D {
31848
31849	constructor() {
31850
31851		super();
31852
31853		this._currentLevel = 0;
31854
31855		this.type = 'LOD';
31856
31857		Object.defineProperties( this, {
31858			levels: {
31859				enumerable: true,
31860				value: []
31861			},
31862			isLOD: {
31863				value: true,
31864			}
31865		} );
31866
31867		this.autoUpdate = true;
31868
31869	}
31870
31871	copy( source ) {
31872
31873		super.copy( source, false );
31874
31875		const levels = source.levels;
31876
31877		for ( let i = 0, l = levels.length; i < l; i ++ ) {
31878
31879			const level = levels[ i ];
31880
31881			this.addLevel( level.object.clone(), level.distance, level.hysteresis );
31882
31883		}
31884
31885		this.autoUpdate = source.autoUpdate;
31886
31887		return this;
31888
31889	}
31890
31891	addLevel( object, distance = 0, hysteresis = 0 ) {
31892
31893		distance = Math.abs( distance );
31894
31895		const levels = this.levels;
31896
31897		let l;
31898
31899		for ( l = 0; l < levels.length; l ++ ) {
31900
31901			if ( distance < levels[ l ].distance ) {
31902
31903				break;
31904
31905			}
31906
31907		}
31908
31909		levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );
31910
31911		this.add( object );
31912
31913		return this;
31914
31915	}
31916
31917	getCurrentLevel() {
31918
31919		return this._currentLevel;
31920
31921	}
31922
31923
31924
31925	getObjectForDistance( distance ) {
31926
31927		const levels = this.levels;
31928
31929		if ( levels.length > 0 ) {
31930
31931			let i, l;
31932
31933			for ( i = 1, l = levels.length; i < l; i ++ ) {
31934
31935				let levelDistance = levels[ i ].distance;
31936
31937				if ( levels[ i ].object.visible ) {
31938
31939					levelDistance -= levelDistance * levels[ i ].hysteresis;
31940
31941				}
31942
31943				if ( distance < levelDistance ) {
31944
31945
31946					break;
31947
31948				}
31949
31950			}
31951
31952			return levels[ i - 1 ].object;
31953
31954		}
31955
31956		return null;
31957
31958	}
31959
31960	raycast( raycaster, intersects ) {
31961
31962		const levels = this.levels;
31963
31964		if ( levels.length > 0 ) {
31965
31966			_v1$2.setFromMatrixPosition( this.matrixWorld );
31967
31968			const distance = raycaster.ray.origin.distanceTo( _v1$2 );
31969
31970			this.getObjectForDistance( distance ).raycast( raycaster, intersects );
31971
31972		}
31973
31974	}
31975
31976	update( camera ) {
31977
31978		const levels = this.levels;
31979
31980		if ( levels.length > 1 ) {
31981
31982			_v1$2.setFromMatrixPosition( camera.matrixWorld );
31983			_v2$1.setFromMatrixPosition( this.matrixWorld );
31984
31985			const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom;
31986
31987			levels[ 0 ].object.visible = true;
31988
31989			let i, l;
31990
31991			for ( i = 1, l = levels.length; i < l; i ++ ) {
31992
31993				let levelDistance = levels[ i ].distance;
31994
31995				if ( levels[ i ].object.visible ) {
31996
31997					levelDistance -= levelDistance * levels[ i ].hysteresis;
31998
31999				}
32000
32001				if ( distance >= levelDistance ) {
32002
32003					levels[ i - 1 ].object.visible = false;
32004					levels[ i ].object.visible = true;
32005
32006				} else {
32007
32008					break;
32009
32010				}
32011
32012			}
32013
32014			this._currentLevel = i - 1;
32015
32016			for ( ; i < l; i ++ ) {
32017
32018				levels[ i ].object.visible = false;
32019
32020			}
32021
32022		}
32023
32024	}
32025
32026	toJSON( meta ) {
32027
32028		const data = super.toJSON( meta );
32029
32030		if ( this.autoUpdate === false ) data.object.autoUpdate = false;
32031
32032		data.object.levels = [];
32033
32034		const levels = this.levels;
32035
32036		for ( let i = 0, l = levels.length; i < l; i ++ ) {
32037
32038			const level = levels[ i ];
32039
32040			data.object.levels.push( {
32041				object: level.object.uuid,
32042				distance: level.distance,
32043				hysteresis: level.hysteresis
32044			} );
32045
32046		}
32047
32048		return data;
32049
32050	}
32051
32052}
32053
32054const _basePosition = /*@__PURE__*/ new Vector3();
32055
32056const _skinIndex = /*@__PURE__*/ new Vector4();
32057const _skinWeight = /*@__PURE__*/ new Vector4();
32058
32059const _vector3 = /*@__PURE__*/ new Vector3();
32060const _matrix4 = /*@__PURE__*/ new Matrix4();
32061const _vertex = /*@__PURE__*/ new Vector3();
32062
32063const _sphere$4 = /*@__PURE__*/ new Sphere();
32064const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();
32065const _ray$2 = /*@__PURE__*/ new Ray();
32066
32067class SkinnedMesh extends Mesh {
32068
32069	constructor( geometry, material ) {
32070
32071		super( geometry, material );
32072
32073		this.isSkinnedMesh = true;
32074
32075		this.type = 'SkinnedMesh';
32076
32077		this.bindMode = AttachedBindMode;
32078		this.bindMatrix = new Matrix4();
32079		this.bindMatrixInverse = new Matrix4();
32080
32081		this.boundingBox = null;
32082		this.boundingSphere = null;
32083
32084	}
32085
32086	computeBoundingBox() {
32087
32088		const geometry = this.geometry;
32089
32090		if ( this.boundingBox === null ) {
32091
32092			this.boundingBox = new Box3();
32093
32094		}
32095
32096		this.boundingBox.makeEmpty();
32097
32098		const positionAttribute = geometry.getAttribute( 'position' );
32099
32100		for ( let i = 0; i < positionAttribute.count; i ++ ) {
32101
32102			this.getVertexPosition( i, _vertex );
32103			this.boundingBox.expandByPoint( _vertex );
32104
32105		}
32106
32107	}
32108
32109	computeBoundingSphere() {
32110
32111		const geometry = this.geometry;
32112
32113		if ( this.boundingSphere === null ) {
32114
32115			this.boundingSphere = new Sphere();
32116
32117		}
32118
32119		this.boundingSphere.makeEmpty();
32120
32121		const positionAttribute = geometry.getAttribute( 'position' );
32122
32123		for ( let i = 0; i < positionAttribute.count; i ++ ) {
32124
32125			this.getVertexPosition( i, _vertex );
32126			this.boundingSphere.expandByPoint( _vertex );
32127
32128		}
32129
32130	}
32131
32132	copy( source, recursive ) {
32133
32134		super.copy( source, recursive );
32135
32136		this.bindMode = source.bindMode;
32137		this.bindMatrix.copy( source.bindMatrix );
32138		this.bindMatrixInverse.copy( source.bindMatrixInverse );
32139
32140		this.skeleton = source.skeleton;
32141
32142		if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32143		if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32144
32145		return this;
32146
32147	}
32148
32149	raycast( raycaster, intersects ) {
32150
32151		const material = this.material;
32152		const matrixWorld = this.matrixWorld;
32153
32154		if ( material === undefined ) return;
32155
32156		// test with bounding sphere in world space
32157
32158		if ( this.boundingSphere === null ) this.computeBoundingSphere();
32159
32160		_sphere$4.copy( this.boundingSphere );
32161		_sphere$4.applyMatrix4( matrixWorld );
32162
32163		if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return;
32164
32165		// convert ray to local space of skinned mesh
32166
32167		_inverseMatrix$2.copy( matrixWorld ).invert();
32168		_ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
32169
32170		// test with bounding box in local space
32171
32172		if ( this.boundingBox !== null ) {
32173
32174			if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return;
32175
32176		}
32177
32178		// test for intersections with geometry
32179
32180		this._computeIntersections( raycaster, intersects, _ray$2 );
32181
32182	}
32183
32184	getVertexPosition( index, target ) {
32185
32186		super.getVertexPosition( index, target );
32187
32188		this.applyBoneTransform( index, target );
32189
32190		return target;
32191
32192	}
32193
32194	bind( skeleton, bindMatrix ) {
32195
32196		this.skeleton = skeleton;
32197
32198		if ( bindMatrix === undefined ) {
32199
32200			this.updateMatrixWorld( true );
32201
32202			this.skeleton.calculateInverses();
32203
32204			bindMatrix = this.matrixWorld;
32205
32206		}
32207
32208		this.bindMatrix.copy( bindMatrix );
32209		this.bindMatrixInverse.copy( bindMatrix ).invert();
32210
32211	}
32212
32213	pose() {
32214
32215		this.skeleton.pose();
32216
32217	}
32218
32219	normalizeSkinWeights() {
32220
32221		const vector = new Vector4();
32222
32223		const skinWeight = this.geometry.attributes.skinWeight;
32224
32225		for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
32226
32227			vector.fromBufferAttribute( skinWeight, i );
32228
32229			const scale = 1.0 / vector.manhattanLength();
32230
32231			if ( scale !== Infinity ) {
32232
32233				vector.multiplyScalar( scale );
32234
32235			} else {
32236
32237				vector.set( 1, 0, 0, 0 );
vendor: 12,048 bytes, lines 32237-32832
32237 // do something reasonable
32238
32239			}
32240
32241			skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
32242
32243		}
32244
32245	}
32246
32247	updateMatrixWorld( force ) {
32248
32249		super.updateMatrixWorld( force );
32250
32251		if ( this.bindMode === AttachedBindMode ) {
32252
32253			this.bindMatrixInverse.copy( this.matrixWorld ).invert();
32254
32255		} else if ( this.bindMode === DetachedBindMode ) {
32256
32257			this.bindMatrixInverse.copy( this.bindMatrix ).invert();
32258
32259		} else {
32260
32261			console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
32262
32263		}
32264
32265	}
32266
32267	applyBoneTransform( index, vector ) {
32268
32269		const skeleton = this.skeleton;
32270		const geometry = this.geometry;
32271
32272		_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
32273		_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
32274
32275		_basePosition.copy( vector ).applyMatrix4( this.bindMatrix );
32276
32277		vector.set( 0, 0, 0 );
32278
32279		for ( let i = 0; i < 4; i ++ ) {
32280
32281			const weight = _skinWeight.getComponent( i );
32282
32283			if ( weight !== 0 ) {
32284
32285				const boneIndex = _skinIndex.getComponent( i );
32286
32287				_matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
32288
32289				vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );
32290
32291			}
32292
32293		}
32294
32295		return vector.applyMatrix4( this.bindMatrixInverse );
32296
32297	}
32298
32299	boneTransform( index, vector ) { // @deprecated, r151
32300
32301		console.warn( 'THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151.' );
32302		return this.applyBoneTransform( index, vector );
32303
32304	}
32305
32306
32307}
32308
32309class Bone extends Object3D {
32310
32311	constructor() {
32312
32313		super();
32314
32315		this.isBone = true;
32316
32317		this.type = 'Bone';
32318
32319	}
32320
32321}
32322
32323class DataTexture extends Texture {
32324
32325	constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) {
32326
32327		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
32328
32329		this.isDataTexture = true;
32330
32331		this.image = { data: data, width: width, height: height };
32332
32333		this.generateMipmaps = false;
32334		this.flipY = false;
32335		this.unpackAlignment = 1;
32336
32337	}
32338
32339}
32340
32341const _offsetMatrix = /*@__PURE__*/ new Matrix4();
32342const _identityMatrix$1 = /*@__PURE__*/ new Matrix4();
32343
32344class Skeleton {
32345
32346	constructor( bones = [], boneInverses = [] ) {
32347
32348		this.uuid = generateUUID();
32349
32350		this.bones = bones.slice( 0 );
32351		this.boneInverses = boneInverses;
32352		this.boneMatrices = null;
32353
32354		this.boneTexture = null;
32355
32356		this.init();
32357
32358	}
32359
32360	init() {
32361
32362		const bones = this.bones;
32363		const boneInverses = this.boneInverses;
32364
32365		this.boneMatrices = new Float32Array( bones.length * 16 );
32366
32367		// calculate inverse bone matrices if necessary
32368
32369		if ( boneInverses.length === 0 ) {
32370
32371			this.calculateInverses();
32372
32373		} else {
32374
32375			// handle special case
32376
32377			if ( bones.length !== boneInverses.length ) {
32378
32379				console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
32380
32381				this.boneInverses = [];
32382
32383				for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32384
32385					this.boneInverses.push( new Matrix4() );
32386
32387				}
32388
32389			}
32390
32391		}
32392
32393	}
32394
32395	calculateInverses() {
32396
32397		this.boneInverses.length = 0;
32398
32399		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32400
32401			const inverse = new Matrix4();
32402
32403			if ( this.bones[ i ] ) {
32404
32405				inverse.copy( this.bones[ i ].matrixWorld ).invert();
32406
32407			}
32408
32409			this.boneInverses.push( inverse );
32410
32411		}
32412
32413	}
32414
32415	pose() {
32416
32417		// recover the bind-time world matrices
32418
32419		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32420
32421			const bone = this.bones[ i ];
32422
32423			if ( bone ) {
32424
32425				bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
32426
32427			}
32428
32429		}
32430
32431		// compute the local matrices, positions, rotations and scales
32432
32433		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32434
32435			const bone = this.bones[ i ];
32436
32437			if ( bone ) {
32438
32439				if ( bone.parent && bone.parent.isBone ) {
32440
32441					bone.matrix.copy( bone.parent.matrixWorld ).invert();
32442					bone.matrix.multiply( bone.matrixWorld );
32443
32444				} else {
32445
32446					bone.matrix.copy( bone.matrixWorld );
32447
32448				}
32449
32450				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
32451
32452			}
32453
32454		}
32455
32456	}
32457
32458	update() {
32459
32460		const bones = this.bones;
32461		const boneInverses = this.boneInverses;
32462		const boneMatrices = this.boneMatrices;
32463		const boneTexture = this.boneTexture;
32464
32465		// flatten bone matrices to array
32466
32467		for ( let i = 0, il = bones.length; i < il; i ++ ) {
32468
32469			// compute the offset between the current and the original transform
32470
32471			const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1;
32472
32473			_offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
32474			_offsetMatrix.toArray( boneMatrices, i * 16 );
32475
32476		}
32477
32478		if ( boneTexture !== null ) {
32479
32480			boneTexture.needsUpdate = true;
32481
32482		}
32483
32484	}
32485
32486	clone() {
32487
32488		return new Skeleton( this.bones, this.boneInverses );
32489
32490	}
32491
32492	computeBoneTexture() {
32493
32494		// layout (1 matrix = 4 pixels)
32495		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
32496		//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
32497		//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
32498		//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
32499		//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
32500
32501		let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
32502		size = Math.ceil( size / 4 ) * 4;
32503		size = Math.max( size, 4 );
32504
32505		const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
32506		boneMatrices.set( this.boneMatrices ); // copy current values
32507
32508		const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
32509		boneTexture.needsUpdate = true;
32510
32511		this.boneMatrices = boneMatrices;
32512		this.boneTexture = boneTexture;
32513
32514		return this;
32515
32516	}
32517
32518	getBoneByName( name ) {
32519
32520		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32521
32522			const bone = this.bones[ i ];
32523
32524			if ( bone.name === name ) {
32525
32526				return bone;
32527
32528			}
32529
32530		}
32531
32532		return undefined;
32533
32534	}
32535
32536	dispose( ) {
32537
32538		if ( this.boneTexture !== null ) {
32539
32540			this.boneTexture.dispose();
32541
32542			this.boneTexture = null;
32543
32544		}
32545
32546	}
32547
32548	fromJSON( json, bones ) {
32549
32550		this.uuid = json.uuid;
32551
32552		for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
32553
32554			const uuid = json.bones[ i ];
32555			let bone = bones[ uuid ];
32556
32557			if ( bone === undefined ) {
32558
32559				console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
32560				bone = new Bone();
32561
32562			}
32563
32564			this.bones.push( bone );
32565			this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
32566
32567		}
32568
32569		this.init();
32570
32571		return this;
32572
32573	}
32574
32575	toJSON() {
32576
32577		const data = {
32578			metadata: {
32579				version: 4.6,
32580				type: 'Skeleton',
32581				generator: 'Skeleton.toJSON'
32582			},
32583			bones: [],
32584			boneInverses: []
32585		};
32586
32587		data.uuid = this.uuid;
32588
32589		const bones = this.bones;
32590		const boneInverses = this.boneInverses;
32591
32592		for ( let i = 0, l = bones.length; i < l; i ++ ) {
32593
32594			const bone = bones[ i ];
32595			data.bones.push( bone.uuid );
32596
32597			const boneInverse = boneInverses[ i ];
32598			data.boneInverses.push( boneInverse.toArray() );
32599
32600		}
32601
32602		return data;
32603
32604	}
32605
32606}
32607
32608class InstancedBufferAttribute extends BufferAttribute {
32609
32610	constructor( array, itemSize, normalized, meshPerAttribute = 1 ) {
32611
32612		super( array, itemSize, normalized );
32613
32614		this.isInstancedBufferAttribute = true;
32615
32616		this.meshPerAttribute = meshPerAttribute;
32617
32618	}
32619
32620	copy( source ) {
32621
32622		super.copy( source );
32623
32624		this.meshPerAttribute = source.meshPerAttribute;
32625
32626		return this;
32627
32628	}
32629
32630	toJSON() {
32631
32632		const data = super.toJSON();
32633
32634		data.meshPerAttribute = this.meshPerAttribute;
32635
32636		data.isInstancedBufferAttribute = true;
32637
32638		return data;
32639
32640	}
32641
32642}
32643
32644const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();
32645const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();
32646
32647const _instanceIntersects = [];
32648
32649const _box3 = /*@__PURE__*/ new Box3();
32650const _identity = /*@__PURE__*/ new Matrix4();
32651const _mesh$1 = /*@__PURE__*/ new Mesh();
32652const _sphere$3 = /*@__PURE__*/ new Sphere();
32653
32654class InstancedMesh extends Mesh {
32655
32656	constructor( geometry, material, count ) {
32657
32658		super( geometry, material );
32659
32660		this.isInstancedMesh = true;
32661
32662		this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );
32663		this.instanceColor = null;
32664
32665		this.count = count;
32666
32667		this.boundingBox = null;
32668		this.boundingSphere = null;
32669
32670		for ( let i = 0; i < count; i ++ ) {
32671
32672			this.setMatrixAt( i, _identity );
32673
32674		}
32675
32676	}
32677
32678	computeBoundingBox() {
32679
32680		const geometry = this.geometry;
32681		const count = this.count;
32682
32683		if ( this.boundingBox === null ) {
32684
32685			this.boundingBox = new Box3();
32686
32687		}
32688
32689		if ( geometry.boundingBox === null ) {
32690
32691			geometry.computeBoundingBox();
32692
32693		}
32694
32695		this.boundingBox.makeEmpty();
32696
32697		for ( let i = 0; i < count; i ++ ) {
32698
32699			this.getMatrixAt( i, _instanceLocalMatrix );
32700
32701			_box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );
32702
32703			this.boundingBox.union( _box3 );
32704
32705		}
32706
32707	}
32708
32709	computeBoundingSphere() {
32710
32711		const geometry = this.geometry;
32712		const count = this.count;
32713
32714		if ( this.boundingSphere === null ) {
32715
32716			this.boundingSphere = new Sphere();
32717
32718		}
32719
32720		if ( geometry.boundingSphere === null ) {
32721
32722			geometry.computeBoundingSphere();
32723
32724		}
32725
32726		this.boundingSphere.makeEmpty();
32727
32728		for ( let i = 0; i < count; i ++ ) {
32729
32730			this.getMatrixAt( i, _instanceLocalMatrix );
32731
32732			_sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );
32733
32734			this.boundingSphere.union( _sphere$3 );
32735
32736		}
32737
32738	}
32739
32740	copy( source, recursive ) {
32741
32742		super.copy( source, recursive );
32743
32744		this.instanceMatrix.copy( source.instanceMatrix );
32745
32746		if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
32747
32748		this.count = source.count;
32749
32750		if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32751		if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32752
32753		return this;
32754
32755	}
32756
32757	getColorAt( index, color ) {
32758
32759		color.fromArray( this.instanceColor.array, index * 3 );
32760
32761	}
32762
32763	getMatrixAt( index, matrix ) {
32764
32765		matrix.fromArray( this.instanceMatrix.array, index * 16 );
32766
32767	}
32768
32769	raycast( raycaster, intersects ) {
32770
32771		const matrixWorld = this.matrixWorld;
32772		const raycastTimes = this.count;
32773
32774		_mesh$1.geometry = this.geometry;
32775		_mesh$1.material = this.material;
32776
32777		if ( _mesh$1.material === undefined ) return;
32778
32779		// test with bounding sphere first
32780
32781		if ( this.boundingSphere === null ) this.computeBoundingSphere();
32782
32783		_sphere$3.copy( this.boundingSphere );
32784		_sphere$3.applyMatrix4( matrixWorld );
32785
32786		if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
32787
32788		// now test each instance
32789
32790		for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
32791
32792			// calculate the world matrix for each instance
32793
32794			this.getMatrixAt( instanceId, _instanceLocalMatrix );
32795
32796			_instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
32797
32798			// the mesh represents this single instance
32799
32800			_mesh$1.matrixWorld = _instanceWorldMatrix;
32801
32802			_mesh$1.raycast( raycaster, _instanceIntersects );
32803
32804			// process the result of raycast
32805
32806			for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
32807
32808				const intersect = _instanceIntersects[ i ];
32809				intersect.instanceId = instanceId;
32810				intersect.object = this;
32811				intersects.push( intersect );
32812
32813			}
32814
32815			_instanceIntersects.length = 0;
32816
32817		}
32818
32819	}
32820
32821	setColorAt( index, color ) {
32822
32823		if ( this.instanceColor === null ) {
32824
32825			this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 );
32826
32827		}
32828
32829		color.toArray( this.instanceColor.array, index * 3 );
32830
32831	}
32832
32833	setMatrixAt( index, matrix ) {
32834
32835		matrix.toArray( this.instanceMatrix.array, index * 16 );
32836
32837	}
32838
32839	updateMorphTargets() {
32840
32841	}
32842
32843	dispose() {
32844
32845		this.dispatchEvent( { type: 'dispose' } );
32846
32847	}
32848
32849}
32850
32851function sortOpaque( a, b ) {
32852
32853	return a.z - b.z;
32854
32855}
32856
32857function sortTransparent( a, b ) {
32858
32859	return b.z - a.z;
32860
32861}
32862
32863class MultiDrawRenderList {
32864
32865	constructor() {
32866
32867		this.index = 0;
32868		this.pool = [];
32869		this.list = [];
32870
32871	}
32872
32873	push( drawRange, z ) {
32874
32875		const pool = this.pool;
32876		const list = this.list;
32877		if ( this.index >= pool.length ) {
32878
32879			pool.push( {
32880
32881				start: - 1,
32882				count: - 1,
32883				z: - 1,
32884
32885			} );
32886
32887		}
32888
32889		const item = pool[ this.index ];
32890		list.push( item );
32891		this.index ++;
32892
32893		item.start = drawRange.start;
32894		item.count = drawRange.count;
32895		item.z = z;
32896
32897	}
32898
32899	reset() {
32900
32901		this.list.length = 0;
32902		this.index = 0;
32903
32904	}
32905
32906}
32907
32908const ID_ATTR_NAME = 'batchId';
32909const _matrix = /*@__PURE__*/ new Matrix4();
32910const _invMatrixWorld = /*@__PURE__*/ new Matrix4();
32911const _identityMatrix = /*@__PURE__*/ new Matrix4();
32912const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4();
32913const _frustum = /*@__PURE__*/ new Frustum();
32914const _box$1 = /*@__PURE__*/ new Box3();
32915const _sphere$2 = /*@__PURE__*/ new Sphere();
32916const _vector$5 = /*@__PURE__*/ new Vector3();
32917const _renderList = /*@__PURE__*/ new MultiDrawRenderList();
32918const _mesh = /*@__PURE__*/ new Mesh();
32919const _batchIntersects = [];
32920
32921// @TODO: SkinnedMesh support?
32922// @TODO: geometry.groups support?
32923// @TODO: geometry.drawRange support?
32924// @TODO: geometry.morphAttributes support?
32925// @TODO: Support uniform parameter per geometry
32926// @TODO: Add an "optimize" function to pack geometry and remove data gaps
32927
32928// copies data from attribute "src" into "target" starting at "targetOffset"
32929function copyAttributeData( src, target, targetOffset = 0 ) {
32930
32931	const itemSize = target.itemSize;
32932	if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {
32933
32934		// use the component getters and setters if the array data cannot
32935		// be copied directly
32936		const vertexCount = src.count;
32937		for ( let i = 0; i < vertexCount; i ++ ) {
32938
32939			for ( let c = 0; c < itemSize; c ++ ) {
32940
32941				target.setComponent( i + targetOffset, c, src.getComponent( i, c ) );
32942
32943			}
32944
32945		}
32946
32947	} else {
32948
32949		// faster copy approach using typed array set function
32950		target.array.set( src.array, targetOffset * itemSize );
32951
32952	}
32953
32954	target.needsUpdate = true;
32955
32956}
32957
32958class BatchedMesh extends Mesh {
32959
32960	get maxGeometryCount() {
32961
32962		return this._maxGeometryCount;
32963
32964	}
32965
32966	constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {
32967
32968		super( new BufferGeometry(), material );
32969
32970		this.isBatchedMesh = true;
32971		this.perObjectFrustumCulled = true;
32972		this.sortObjects = true;
32973		this.boundingBox = null;
32974		this.boundingSphere = null;
32975		this.customSort = null;
32976
32977		this._drawRanges = [];
32978		this._reservedRanges = [];
32979
32980		this._visibility = [];
32981		this._active = [];
32982		this._bounds = [];
32983
32984		this._maxGeometryCount = maxGeometryCount;
32985		this._maxVertexCount = maxVertexCount;
32986		this._maxIndexCount = maxIndexCount;
32987
32988		this._geometryInitialized = false;
32989		this._geometryCount = 0;
32990		this._multiDrawCounts = new Int32Array( maxGeometryCount );
32991		this._multiDrawStarts = new Int32Array( maxGeometryCount );
32992		this._multiDrawCount = 0;
32993		this._visibilityChanged = true;
32994
32995		// Local matrix per geometry by using data texture
32996		this._matricesTexture = null;
32997
32998		this._initMatricesTexture();
32999
33000	}
33001
33002	_initMatricesTexture() {
33003
33004		// layout (1 matrix = 4 pixels)
33005		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
33006		//  with  8x8  pixel texture max   16 matrices * 4 pixels =  (8 * 8)
33007		//       16x16 pixel texture max   64 matrices * 4 pixels = (16 * 16)
33008		//       32x32 pixel texture max  256 matrices * 4 pixels = (32 * 32)
33009		//       64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)
33010
33011		let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
33012		size = Math.ceil( size / 4 ) * 4;
33013		size = Math.max( size, 4 );
33014
33015		const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
33016		const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );
33017
33018		this._matricesTexture = matricesTexture;
33019
33020	}
33021
33022	_initializeGeometry( reference ) {
33023
33024		const geometry = this.geometry;
33025		const maxVertexCount = this._maxVertexCount;
33026		const maxGeometryCount = this._maxGeometryCount;
33027		const maxIndexCount = this._maxIndexCount;
33028		if ( this._geometryInitialized === false ) {
33029
33030			for ( const attributeName in reference.attributes ) {
33031
33032				const srcAttribute = reference.getAttribute( attributeName );
33033				const { array, itemSize, normalized } = srcAttribute;
33034
33035				const dstArray = new array.constructor( maxVertexCount * itemSize );
33036				const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized );
33037				dstAttribute.setUsage( srcAttribute.usage );
33038
33039				geometry.setAttribute( attributeName, dstAttribute );
33040
33041			}
33042
33043			if ( reference.getIndex() !== null ) {
33044
33045				const indexArray = maxVertexCount > 65536
33046					? new Uint32Array( maxIndexCount )
33047					: new Uint16Array( maxIndexCount );
33048
33049				geometry.setIndex( new BufferAttribute( indexArray, 1 ) );
33050
33051			}
33052
33053			const idArray = maxGeometryCount > 65536
33054				? new Uint32Array( maxVertexCount )
33055				: new Uint16Array( maxVertexCount );
33056			geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );
33057
33058			this._geometryInitialized = true;
33059
33060		}
33061
33062	}
33063
33064	// Make sure the geometry is compatible with the existing combined geometry atributes
33065	_validateGeometry( geometry ) {
33066
33067		// check that the geometry doesn't have a version of our reserved id attribute
33068		if ( geometry.getAttribute( ID_ATTR_NAME ) ) {
33069
33070			throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` );
33071
33072		}
33073
33074		// check to ensure the geometries are using consistent attributes and indices
33075		const batchGeometry = this.geometry;
33076		if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {
33077
33078			throw new Error( 'BatchedMesh: All geometries must consistently have "index".' );
33079
33080		}
33081
33082		for ( const attributeName in batchGeometry.attributes ) {
33083
33084			if ( attributeName === ID_ATTR_NAME ) {
33085
33086				continue;
33087
33088			}
33089
33090			if ( ! geometry.hasAttribute( attributeName ) ) {
33091
33092				throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );
33093
33094			}
33095
33096			const srcAttribute = geometry.getAttribute( attributeName );
33097			const dstAttribute = batchGeometry.getAttribute( attributeName );
33098			if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {
33099
33100				throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );
33101
33102			}
33103
33104		}
33105
33106	}
33107
33108	setCustomSort( func ) {
33109
33110		this.customSort = func;
33111		return this;
33112
33113	}
33114
33115	computeBoundingBox() {
33116
33117		if ( this.boundingBox === null ) {
33118
33119			this.boundingBox = new Box3();
33120
33121		}
33122
33123		const geometryCount = this._geometryCount;
33124		const boundingBox = this.boundingBox;
33125		const active = this._active;
33126
33127		boundingBox.makeEmpty();
33128		for ( let i = 0; i < geometryCount; i ++ ) {
33129
33130			if ( active[ i ] === false ) continue;
33131
33132			this.getMatrixAt( i, _matrix );
33133			this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix );
33134			boundingBox.union( _box$1 );
33135
33136		}
33137
33138	}
33139
33140	computeBoundingSphere() {
33141
33142		if ( this.boundingSphere === null ) {
33143
33144			this.boundingSphere = new Sphere();
33145
33146		}
33147
33148		const geometryCount = this._geometryCount;
33149		const boundingSphere = this.boundingSphere;
33150		const active = this._active;
33151
33152		boundingSphere.makeEmpty();
33153		for ( let i = 0; i < geometryCount; i ++ ) {
33154
33155			if ( active[ i ] === false ) continue;
33156
33157			this.getMatrixAt( i, _matrix );
33158			this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33159			boundingSphere.union( _sphere$2 );
33160
33161		}
33162
33163	}
33164
33165	addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {
33166
33167		this._initializeGeometry( geometry );
33168
33169		this._validateGeometry( geometry );
33170
33171		// ensure we're not over geometry
33172		if ( this._geometryCount >= this._maxGeometryCount ) {
33173
33174			throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33175
33176		}
33177
33178		// get the necessary range fo the geometry
33179		const reservedRange = {
33180			vertexStart: - 1,
33181			vertexCount: - 1,
33182			indexStart: - 1,
33183			indexCount: - 1,
33184		};
33185
33186		let lastRange = null;
33187		const reservedRanges = this._reservedRanges;
33188		const drawRanges = this._drawRanges;
33189		const bounds = this._bounds;
33190		if ( this._geometryCount !== 0 ) {
33191
33192			lastRange = reservedRanges[ reservedRanges.length - 1 ];
33193
33194		}
33195
33196		if ( vertexCount === - 1 ) {
33197
33198			reservedRange.vertexCount = geometry.getAttribute( 'position' ).count;
33199
33200		} else {
33201
33202			reservedRange.vertexCount = vertexCount;
33203
33204		}
33205
33206		if ( lastRange === null ) {
33207
33208			reservedRange.vertexStart = 0;
33209
33210		} else {
33211
33212			reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;
33213
33214		}
33215
33216		const index = geometry.getIndex();
33217		const hasIndex = index !== null;
33218		if ( hasIndex ) {
33219
33220			if ( indexCount	=== - 1 ) {
33221
33222				reservedRange.indexCount = index.count;
33223
33224			} else {
33225
33226				reservedRange.indexCount = indexCount;
33227
33228			}
33229
33230			if ( lastRange === null ) {
33231
33232				reservedRange.indexStart = 0;
33233
33234			} else {
33235
33236				reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;
33237
33238			}
33239
33240		}
33241
33242		if (
33243			reservedRange.indexStart !== - 1 &&
33244			reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||
33245			reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount
33246		) {
33247
33248			throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );
33249
33250		}
33251
33252		const visibility = this._visibility;
33253		const active = this._active;
33254		const matricesTexture = this._matricesTexture;
33255		const matricesArray = this._matricesTexture.image.data;
33256
33257		// push new visibility states
33258		visibility.push( true );
33259		active.push( true );
33260
33261		// update id
33262		const geometryId = this._geometryCount;
33263		this._geometryCount ++;
33264
33265		// initialize matrix information
33266		_identityMatrix.toArray( matricesArray, geometryId * 16 );
33267		matricesTexture.needsUpdate = true;
33268
33269		// add the reserved range and draw range objects
33270		reservedRanges.push( reservedRange );
33271		drawRanges.push( {
33272			start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,
33273			count: - 1
33274		} );
33275		bounds.push( {
33276			boxInitialized: false,
33277			box: new Box3(),
33278
33279			sphereInitialized: false,
33280			sphere: new Sphere()
33281		} );
33282
33283		// set the id for the geometry
33284		const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME );
33285		for ( let i = 0; i < reservedRange.vertexCount; i ++ ) {
33286
33287			idAttribute.setX( reservedRange.vertexStart + i, geometryId );
33288
33289		}
33290
33291		idAttribute.needsUpdate = true;
33292
33293		// update the geometry
33294		this.setGeometryAt( geometryId, geometry );
33295
33296		return geometryId;
33297
33298	}
33299
33300	setGeometryAt( id, geometry ) {
33301
33302		if ( id >= this._geometryCount ) {
33303
33304			throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33305
33306		}
33307
33308		this._validateGeometry( geometry );
33309
33310		const batchGeometry = this.geometry;
33311		const hasIndex = batchGeometry.getIndex() !== null;
33312		const dstIndex = batchGeometry.getIndex();
33313		const srcIndex = geometry.getIndex();
33314		const reservedRange = this._reservedRanges[ id ];
33315		if (
33316			hasIndex &&
33317			srcIndex.count > reservedRange.indexCount ||
33318			geometry.attributes.position.count > reservedRange.vertexCount
33319		) {
33320
33321			throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );
33322
33323		}
33324
33325		// copy geometry over
33326		const vertexStart = reservedRange.vertexStart;
33327		const vertexCount = reservedRange.vertexCount;
33328		for ( const attributeName in batchGeometry.attributes ) {
33329
33330			if ( attributeName === ID_ATTR_NAME ) {
33331
33332				continue;
33333
33334			}
33335
33336			// copy attribute data
33337			const srcAttribute = geometry.getAttribute( attributeName );
33338			const dstAttribute = batchGeometry.getAttribute( attributeName );
33339			copyAttributeData( srcAttribute, dstAttribute, vertexStart );
33340
33341			// fill the rest in with zeroes
33342			const itemSize = srcAttribute.itemSize;
33343			for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {
33344
33345				const index = vertexStart + i;
33346				for ( let c = 0; c < itemSize; c ++ ) {
33347
33348					dstAttribute.setComponent( index, c, 0 );
33349
33350				}
33351
33352			}
33353
33354			dstAttribute.needsUpdate = true;
33355
33356		}
33357
33358		// copy index
33359		if ( hasIndex ) {
33360
33361			const indexStart = reservedRange.indexStart;
33362
33363			// copy index data over
33364			for ( let i = 0; i < srcIndex.count; i ++ ) {
33365
33366				dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );
33367
33368			}
33369
33370			// fill the rest in with zeroes
33371			for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {
33372
33373				dstIndex.setX( indexStart + i, vertexStart );
33374
33375			}
33376
33377			dstIndex.needsUpdate = true;
33378
33379		}
33380
33381		// store the bounding boxes
33382		const bound = this._bounds[ id ];
33383		if ( geometry.boundingBox !== null ) {
33384
33385			bound.box.copy( geometry.boundingBox );
33386			bound.boxInitialized = true;
33387
33388		} else {
33389
33390			bound.boxInitialized = false;
33391
33392		}
33393
33394		if ( geometry.boundingSphere !== null ) {
33395
33396			bound.sphere.copy( geometry.boundingSphere );
33397			bound.sphereInitialized = true;
33398
33399		} else {
33400
33401			bound.sphereInitialized = false;
33402
33403		}
33404
33405		// set drawRange count
33406		const drawRange = this._drawRanges[ id ];
33407		const posAttr = geometry.getAttribute( 'position' );
33408		drawRange.count = hasIndex ? srcIndex.count : posAttr.count;
33409		this._visibilityChanged = true;
33410
33411		return id;
33412
33413	}
33414
33415	deleteGeometry( geometryId ) {
33416
33417		// Note: User needs to call optimize() afterward to pack the data.
33418
33419		const active = this._active;
33420		if ( geometryId >= active.length || active[ geometryId ] === false ) {
33421
33422			return this;
33423
33424		}
33425
33426		active[ geometryId ] = false;
33427		this._visibilityChanged = true;
33428
33429		return this;
33430
33431	}
33432
33433	// get bounding box and compute it if it doesn't exist
33434	getBoundingBoxAt( id, target ) {
33435
33436		const active = this._active;
33437		if ( active[ id ] === false ) {
33438
33439			return this;
33440
33441		}
33442
33443		// compute bounding box
33444		const bound = this._bounds[ id ];
33445		const box = bound.box;
33446		const geometry = this.geometry;
33447		if ( bound.boxInitialized === false ) {
33448
33449			box.makeEmpty();
33450
33451			const index = geometry.index;
33452			const position = geometry.attributes.position;
33453			const drawRange = this._drawRanges[ id ];
33454			for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33455
33456				let iv = i;
33457				if ( index ) {
33458
33459					iv = index.getX( iv );
33460
33461				}
33462
33463				box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) );
33464
33465			}
33466
33467			bound.boxInitialized = true;
33468
33469		}
33470
33471		target.copy( box );
33472		return target;
33473
33474	}
33475
33476	// get bounding sphere and compute it if it doesn't exist
33477	getBoundingSphereAt( id, target ) {
33478
33479		const active = this._active;
33480		if ( active[ id ] === false ) {
33481
33482			return this;
33483
33484		}
33485
33486		// compute bounding sphere
33487		const bound = this._bounds[ id ];
33488		const sphere = bound.sphere;
33489		const geometry = this.geometry;
33490		if ( bound.sphereInitialized === false ) {
33491
33492			sphere.makeEmpty();
33493
33494			this.getBoundingBoxAt( id, _box$1 );
33495			_box$1.getCenter( sphere.center );
33496
33497			const index = geometry.index;
33498			const position = geometry.attributes.position;
33499			const drawRange = this._drawRanges[ id ];
33500
33501			let maxRadiusSq = 0;
33502			for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33503
33504				let iv = i;
33505				if ( index ) {
33506
33507					iv = index.getX( iv );
33508
33509				}
33510
33511				_vector$5.fromBufferAttribute( position, iv );
33512				maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) );
33513
33514			}
33515
33516			sphere.radius = Math.sqrt( maxRadiusSq );
33517			bound.sphereInitialized = true;
33518
33519		}
33520
33521		target.copy( sphere );
33522		return target;
33523
33524	}
33525
33526	setMatrixAt( geometryId, matrix ) {
33527
33528		// @TODO: Map geometryId to index of the arrays because
33529		//        optimize() can make geometryId mismatch the index
33530
33531		const active = this._active;
33532		const matricesTexture = this._matricesTexture;
33533		const matricesArray = this._matricesTexture.image.data;
33534		const geometryCount = this._geometryCount;
33535		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33536
33537			return this;
33538
33539		}
33540
33541		matrix.toArray( matricesArray, geometryId * 16 );
33542		matricesTexture.needsUpdate = true;
33543
33544		return this;
33545
33546	}
33547
33548	getMatrixAt( geometryId, matrix ) {
33549
33550		const active = this._active;
33551		const matricesArray = this._matricesTexture.image.data;
33552		const geometryCount = this._geometryCount;
33553		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33554
33555			return null;
33556
33557		}
33558
33559		return matrix.fromArray( matricesArray, geometryId * 16 );
33560
33561	}
33562
33563	setVisibleAt( geometryId, value ) {
33564
33565		const visibility = this._visibility;
33566		const active = this._active;
33567		const geometryCount = this._geometryCount;
33568
33569		// if the geometry is out of range, not active, or visibility state
33570		// does not change then return early
33571		if (
33572			geometryId >= geometryCount ||
33573			active[ geometryId ] === false ||
33574			visibility[ geometryId ] === value
33575		) {
33576
33577			return this;
33578
33579		}
33580
33581		visibility[ geometryId ] = value;
33582		this._visibilityChanged = true;
33583
33584		return this;
33585
33586	}
33587
33588	getVisibleAt( geometryId ) {
33589
33590		const visibility = this._visibility;
33591		const active = this._active;
33592		const geometryCount = this._geometryCount;
33593
33594		// return early if the geometry is out of range or not active
33595		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33596
33597			return false;
33598
33599		}
33600
33601		return visibility[ geometryId ];
33602
33603	}
33604
33605	raycast( raycaster, intersects ) {
33606
33607		const visibility = this._visibility;
33608		const active = this._active;
33609		const drawRanges = this._drawRanges;
33610		const geometryCount = this._geometryCount;
33611		const matrixWorld = this.matrixWorld;
33612		const batchGeometry = this.geometry;
33613
33614		// iterate over each geometry
33615		_mesh.material = this.material;
33616		_mesh.geometry.index = batchGeometry.index;
33617		_mesh.geometry.attributes = batchGeometry.attributes;
33618		if ( _mesh.geometry.boundingBox === null ) {
33619
33620			_mesh.geometry.boundingBox = new Box3();
33621
33622		}
33623
33624		if ( _mesh.geometry.boundingSphere === null ) {
33625
33626			_mesh.geometry.boundingSphere = new Sphere();
33627
33628		}
33629
33630		for ( let i = 0; i < geometryCount; i ++ ) {
33631
33632			if ( ! visibility[ i ] || ! active[ i ] ) {
33633
33634				continue;
33635
33636			}
33637
33638			const drawRange = drawRanges[ i ];
33639			_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );
33640
33641			// ge the intersects
33642			this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );
33643			this.getBoundingBoxAt( i, _mesh.geometry.boundingBox );
33644			this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere );
33645			_mesh.raycast( raycaster, _batchIntersects );
33646
33647			// add batch id to the intersects
33648			for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {
33649
33650				const intersect = _batchIntersects[ j ];
33651				intersect.object = this;
33652				intersect.batchId = i;
33653				intersects.push( intersect );
33654
33655			}
33656
33657			_batchIntersects.length = 0;
33658
33659		}
33660
33661		_mesh.material = null;
33662		_mesh.geometry.index = null;
33663		_mesh.geometry.attributes = {};
33664		_mesh.geometry.setDrawRange( 0, Infinity );
33665
33666	}
33667
33668	copy( source ) {
33669
33670		super.copy( source );
33671
33672		this.geometry = source.geometry.clone();
33673		this.perObjectFrustumCulled = source.perObjectFrustumCulled;
33674		this.sortObjects = source.sortObjects;
33675		this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
33676		this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
33677
33678		this._drawRanges = source._drawRanges.map( range => ( { ...range } ) );
33679		this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );
33680
33681		this._visibility = source._visibility.slice();
33682		this._active = source._active.slice();
33683		this._bounds = source._bounds.map( bound => ( {
33684			boxInitialized: bound.boxInitialized,
33685			box: bound.box.clone(),
33686
33687			sphereInitialized: bound.sphereInitialized,
33688			sphere: bound.sphere.clone()
33689		} ) );
33690
33691		this._maxGeometryCount = source._maxGeometryCount;
33692		this._maxVertexCount = source._maxVertexCount;
33693		this._maxIndexCount = source._maxIndexCount;
33694
33695		this._geometryInitialized = source._geometryInitialized;
33696		this._geometryCount = source._geometryCount;
33697		this._multiDrawCounts = source._multiDrawCounts.slice();
33698		this._multiDrawStarts = source._multiDrawStarts.slice();
33699
33700		this._matricesTexture = source._matricesTexture.clone();
33701		this._matricesTexture.image.data = this._matricesTexture.image.slice();
33702
33703		return this;
33704
33705	}
33706
33707	dispose() {
33708
33709		// Assuming the geometry is not shared with other meshes
33710		this.geometry.dispose();
33711
33712		this._matricesTexture.dispose();
33713		this._matricesTexture = null;
33714		return this;
33715
33716	}
33717
33718	onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {
33719
33720		// if visibility has not changed and frustum culling and object sorting is not required
33721		// then skip iterating over all items
33722		if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {
33723
33724			return;
33725
33726		}
33727
33728		// the indexed version of the multi draw function requires specifying the start
33729		// offset in bytes.
33730		const index = geometry.getIndex();
33731		const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;
33732
33733		const visibility = this._visibility;
33734		const multiDrawStarts = this._multiDrawStarts;
33735		const multiDrawCounts = this._multiDrawCounts;
33736		const drawRanges = this._drawRanges;
33737		const perObjectFrustumCulled = this.perObjectFrustumCulled;
33738
33739		// prepare the frustum in the local frame
33740		if ( perObjectFrustumCulled ) {
33741
33742			_projScreenMatrix$2
33743				.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )
33744				.multiply( this.matrixWorld );
33745			_frustum.setFromProjectionMatrix(
33746				_projScreenMatrix$2,
33747				renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem
33748			);
33749
33750		}
33751
33752		let count = 0;
33753		if ( this.sortObjects ) {
33754
33755			// get the camera position in the local frame
33756			_invMatrixWorld.copy( this.matrixWorld ).invert();
33757			_vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );
33758
33759			for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33760
33761				if ( visibility[ i ] ) {
33762
33763					// get the bounds in world space
33764					this.getMatrixAt( i, _matrix );
33765					this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33766
33767					// determine whether the batched geometry is within the frustum
33768					let culled = false;
33769					if ( perObjectFrustumCulled ) {
33770
33771						culled = ! _frustum.intersectsSphere( _sphere$2 );
33772
33773					}
33774
33775					if ( ! culled ) {
33776
33777						// get the distance from camera used for sorting
33778						const z = _vector$5.distanceTo( _sphere$2.center );
33779						_renderList.push( drawRanges[ i ], z );
33780
33781					}
33782
33783				}
33784
33785			}
33786
33787			// Sort the draw ranges and prep for rendering
33788			const list = _renderList.list;
33789			const customSort = this.customSort;
33790			if ( customSort === null ) {
33791
33792				list.sort( material.transparent ? sortTransparent : sortOpaque );
33793
33794			} else {
33795
33796				customSort.call( this, list, camera );
33797
33798			}
33799
33800			for ( let i = 0, l = list.length; i < l; i ++ ) {
33801
33802				const item = list[ i ];
33803				multiDrawStarts[ count ] = item.start * bytesPerElement;
33804				multiDrawCounts[ count ] = item.count;
33805				count ++;
33806
33807			}
33808
33809			_renderList.reset();
33810
33811		} else {
33812
33813			for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33814
33815				if ( visibility[ i ] ) {
33816
33817					// determine whether the batched geometry is within the frustum
33818					let culled = false;
33819					if ( perObjectFrustumCulled ) {
33820
33821						// get the bounds in world space
33822						this.getMatrixAt( i, _matrix );
33823						this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33824						culled = ! _frustum.intersectsSphere( _sphere$2 );
33825
33826					}
33827
33828					if ( ! culled ) {
33829
33830						const range = drawRanges[ i ];
33831						multiDrawStarts[ count ] = range.start * bytesPerElement;
33832						multiDrawCounts[ count ] = range.count;
33833						count ++;
33834
33835					}
33836
33837				}
33838
33839			}
33840
33841		}
33842
33843		this._multiDrawCount = count;
33844		this._visibilityChanged = false;
33845
33846	}
33847
33848	onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {
33849
33850		this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );
33851
33852	}
33853
33854}
33855
33856class LineBasicMaterial extends Material {
33857
33858	constructor( parameters ) {
33859
33860		super();
33861
33862		this.isLineBasicMaterial = true;
33863
33864		this.type = 'LineBasicMaterial';
33865
33866		this.color = new Color( 0xffffff );
33867
33868		this.map = null;
33869
33870		this.linewidth = 1;
33871		this.linecap = 'round';
33872		this.linejoin = 'round';
33873
33874		this.fog = true;
33875
33876		this.setValues( parameters );
33877
33878	}
33879
33880
33881	copy( source ) {
33882
33883		super.copy( source );
33884
33885		this.color.copy( source.color );
33886
33887		this.map = source.map;
33888
33889		this.linewidth = source.linewidth;
33890		this.linecap = source.linecap;
33891		this.linejoin = source.linejoin;
33892
vendor: 6,071 bytes, lines 33893-34136
33893		this.fog = source.fog;
33894
33895		return this;
33896
33897	}
33898
33899}
33900
33901const _start$1 = /*@__PURE__*/ new Vector3();
33902const _end$1 = /*@__PURE__*/ new Vector3();
33903const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();
33904const _ray$1 = /*@__PURE__*/ new Ray();
33905const _sphere$1 = /*@__PURE__*/ new Sphere();
33906
33907class Line extends Object3D {
33908
33909	constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
33910
33911		super();
33912
33913		this.isLine = true;
33914
33915		this.type = 'Line';
33916
33917		this.geometry = geometry;
33918		this.material = material;
33919
33920		this.updateMorphTargets();
33921
33922	}
33923
33924	copy( source, recursive ) {
33925
33926		super.copy( source, recursive );
33927
33928		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
33929		this.geometry = source.geometry;
33930
33931		return this;
33932
33933	}
33934
33935	computeLineDistances() {
33936
33937		const geometry = this.geometry;
33938
33939		// we assume non-indexed geometry
33940
33941		if ( geometry.index === null ) {
33942
33943			const positionAttribute = geometry.attributes.position;
33944			const lineDistances = [ 0 ];
33945
33946			for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
33947
33948				_start$1.fromBufferAttribute( positionAttribute, i - 1 );
33949				_end$1.fromBufferAttribute( positionAttribute, i );
33950
33951				lineDistances[ i ] = lineDistances[ i - 1 ];
33952				lineDistances[ i ] += _start$1.distanceTo( _end$1 );
33953
33954			}
33955
33956			geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
33957
33958		} else {
33959
33960			console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
33961
33962		}
33963
33964		return this;
33965
33966	}
33967
33968	raycast( raycaster, intersects ) {
33969
33970		const geometry = this.geometry;
33971		const matrixWorld = this.matrixWorld;
33972		const threshold = raycaster.params.Line.threshold;
33973		const drawRange = geometry.drawRange;
33974
33975		// Checking boundingSphere distance to ray
33976
33977		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
33978
33979		_sphere$1.copy( geometry.boundingSphere );
33980		_sphere$1.applyMatrix4( matrixWorld );
33981		_sphere$1.radius += threshold;
33982
33983		if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;
33984
33985		//
33986
33987		_inverseMatrix$1.copy( matrixWorld ).invert();
33988		_ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
33989
33990		const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
33991		const localThresholdSq = localThreshold * localThreshold;
33992
33993		const vStart = new Vector3();
33994		const vEnd = new Vector3();
33995		const interSegment = new Vector3();
33996		const interRay = new Vector3();
33997		const step = this.isLineSegments ? 2 : 1;
33998
33999		const index = geometry.index;
34000		const attributes = geometry.attributes;
34001		const positionAttribute = attributes.position;
34002
34003		if ( index !== null ) {
34004
34005			const start = Math.max( 0, drawRange.start );
34006			const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
34007
34008			for ( let i = start, l = end - 1; i < l; i += step ) {
34009
34010				const a = index.getX( i );
34011				const b = index.getX( i + 1 );
34012
34013				vStart.fromBufferAttribute( positionAttribute, a );
34014				vEnd.fromBufferAttribute( positionAttribute, b );
34015
34016				const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34017
34018				if ( distSq > localThresholdSq ) continue;
34019
34020				interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34021
34022				const distance = raycaster.ray.origin.distanceTo( interRay );
34023
34024				if ( distance < raycaster.near || distance > raycaster.far ) continue;
34025
34026				intersects.push( {
34027
34028					distance: distance,
34029					// What do we want? intersection point on the ray or on the segment??
34030					// point: raycaster.ray.at( distance ),
34031					point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34032					index: i,
34033					face: null,
34034					faceIndex: null,
34035					object: this
34036
34037				} );
34038
34039			}
34040
34041		} else {
34042
34043			const start = Math.max( 0, drawRange.start );
34044			const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34045
34046			for ( let i = start, l = end - 1; i < l; i += step ) {
34047
34048				vStart.fromBufferAttribute( positionAttribute, i );
34049				vEnd.fromBufferAttribute( positionAttribute, i + 1 );
34050
34051				const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34052
34053				if ( distSq > localThresholdSq ) continue;
34054
34055				interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34056
34057				const distance = raycaster.ray.origin.distanceTo( interRay );
34058
34059				if ( distance < raycaster.near || distance > raycaster.far ) continue;
34060
34061				intersects.push( {
34062
34063					distance: distance,
34064					// What do we want? intersection point on the ray or on the segment??
34065					// point: raycaster.ray.at( distance ),
34066					point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34067					index: i,
34068					face: null,
34069					faceIndex: null,
34070					object: this
34071
34072				} );
34073
34074			}
34075
34076		}
34077
34078	}
34079
34080	updateMorphTargets() {
34081
34082		const geometry = this.geometry;
34083
34084		const morphAttributes = geometry.morphAttributes;
34085		const keys = Object.keys( morphAttributes );
34086
34087		if ( keys.length > 0 ) {
34088
34089			const morphAttribute = morphAttributes[ keys[ 0 ] ];
34090
34091			if ( morphAttribute !== undefined ) {
34092
34093				this.morphTargetInfluences = [];
34094				this.morphTargetDictionary = {};
34095
34096				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34097
34098					const name = morphAttribute[ m ].name || String( m );
34099
34100					this.morphTargetInfluences.push( 0 );
34101					this.morphTargetDictionary[ name ] = m;
34102
34103				}
34104
34105			}
34106
34107		}
34108
34109	}
34110
34111}
34112
34113const _start = /*@__PURE__*/ new Vector3();
34114const _end = /*@__PURE__*/ new Vector3();
34115
34116class LineSegments extends Line {
34117
34118	constructor( geometry, material ) {
34119
34120		super( geometry, material );
34121
34122		this.isLineSegments = true;
34123
34124		this.type = 'LineSegments';
34125
34126	}
34127
34128	computeLineDistances() {
34129
34130		const geometry = this.geometry;
34131
34132		// we assume non-indexed geometry
34133
34134		if ( geometry.index === null ) {
34135
34136			const positionAttribute = geometry.attributes.position;
vendor: 10,680 bytes, lines 34137-34647
34137			const lineDistances = [];
34138
34139			for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
34140
34141				_start.fromBufferAttribute( positionAttribute, i );
34142				_end.fromBufferAttribute( positionAttribute, i + 1 );
34143
34144				lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
34145				lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );
34146
34147			}
34148
34149			geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
34150
34151		} else {
34152
34153			console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
34154
34155		}
34156
34157		return this;
34158
34159	}
34160
34161}
34162
34163class LineLoop extends Line {
34164
34165	constructor( geometry, material ) {
34166
34167		super( geometry, material );
34168
34169		this.isLineLoop = true;
34170
34171		this.type = 'LineLoop';
34172
34173	}
34174
34175}
34176
34177class PointsMaterial extends Material {
34178
34179	constructor( parameters ) {
34180
34181		super();
34182
34183		this.isPointsMaterial = true;
34184
34185		this.type = 'PointsMaterial';
34186
34187		this.color = new Color( 0xffffff );
34188
34189		this.map = null;
34190
34191		this.alphaMap = null;
34192
34193		this.size = 1;
34194		this.sizeAttenuation = true;
34195
34196		this.fog = true;
34197
34198		this.setValues( parameters );
34199
34200	}
34201
34202	copy( source ) {
34203
34204		super.copy( source );
34205
34206		this.color.copy( source.color );
34207
34208		this.map = source.map;
34209
34210		this.alphaMap = source.alphaMap;
34211
34212		this.size = source.size;
34213		this.sizeAttenuation = source.sizeAttenuation;
34214
34215		this.fog = source.fog;
34216
34217		return this;
34218
34219	}
34220
34221}
34222
34223const _inverseMatrix = /*@__PURE__*/ new Matrix4();
34224const _ray = /*@__PURE__*/ new Ray();
34225const _sphere = /*@__PURE__*/ new Sphere();
34226const _position$2 = /*@__PURE__*/ new Vector3();
34227
34228class Points extends Object3D {
34229
34230	constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
34231
34232		super();
34233
34234		this.isPoints = true;
34235
34236		this.type = 'Points';
34237
34238		this.geometry = geometry;
34239		this.material = material;
34240
34241		this.updateMorphTargets();
34242
34243	}
34244
34245	copy( source, recursive ) {
34246
34247		super.copy( source, recursive );
34248
34249		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
34250		this.geometry = source.geometry;
34251
34252		return this;
34253
34254	}
34255
34256	raycast( raycaster, intersects ) {
34257
34258		const geometry = this.geometry;
34259		const matrixWorld = this.matrixWorld;
34260		const threshold = raycaster.params.Points.threshold;
34261		const drawRange = geometry.drawRange;
34262
34263		// Checking boundingSphere distance to ray
34264
34265		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
34266
34267		_sphere.copy( geometry.boundingSphere );
34268		_sphere.applyMatrix4( matrixWorld );
34269		_sphere.radius += threshold;
34270
34271		if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
34272
34273		//
34274
34275		_inverseMatrix.copy( matrixWorld ).invert();
34276		_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
34277
34278		const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
34279		const localThresholdSq = localThreshold * localThreshold;
34280
34281		const index = geometry.index;
34282		const attributes = geometry.attributes;
34283		const positionAttribute = attributes.position;
34284
34285		if ( index !== null ) {
34286
34287			const start = Math.max( 0, drawRange.start );
34288			const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
34289
34290			for ( let i = start, il = end; i < il; i ++ ) {
34291
34292				const a = index.getX( i );
34293
34294				_position$2.fromBufferAttribute( positionAttribute, a );
34295
34296				testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
34297
34298			}
34299
34300		} else {
34301
34302			const start = Math.max( 0, drawRange.start );
34303			const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34304
34305			for ( let i = start, l = end; i < l; i ++ ) {
34306
34307				_position$2.fromBufferAttribute( positionAttribute, i );
34308
34309				testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
34310
34311			}
34312
34313		}
34314
34315	}
34316
34317	updateMorphTargets() {
34318
34319		const geometry = this.geometry;
34320
34321		const morphAttributes = geometry.morphAttributes;
34322		const keys = Object.keys( morphAttributes );
34323
34324		if ( keys.length > 0 ) {
34325
34326			const morphAttribute = morphAttributes[ keys[ 0 ] ];
34327
34328			if ( morphAttribute !== undefined ) {
34329
34330				this.morphTargetInfluences = [];
34331				this.morphTargetDictionary = {};
34332
34333				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34334
34335					const name = morphAttribute[ m ].name || String( m );
34336
34337					this.morphTargetInfluences.push( 0 );
34338					this.morphTargetDictionary[ name ] = m;
34339
34340				}
34341
34342			}
34343
34344		}
34345
34346	}
34347
34348}
34349
34350function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
34351
34352	const rayPointDistanceSq = _ray.distanceSqToPoint( point );
34353
34354	if ( rayPointDistanceSq < localThresholdSq ) {
34355
34356		const intersectPoint = new Vector3();
34357
34358		_ray.closestPointToPoint( point, intersectPoint );
34359		intersectPoint.applyMatrix4( matrixWorld );
34360
34361		const distance = raycaster.ray.origin.distanceTo( intersectPoint );
34362
34363		if ( distance < raycaster.near || distance > raycaster.far ) return;
34364
34365		intersects.push( {
34366
34367			distance: distance,
34368			distanceToRay: Math.sqrt( rayPointDistanceSq ),
34369			point: intersectPoint,
34370			index: index,
34371			face: null,
34372			object: object
34373
34374		} );
34375
34376	}
34377
34378}
34379
34380class VideoTexture extends Texture {
34381
34382	constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
34383
34384		super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
34385
34386		this.isVideoTexture = true;
34387
34388		this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
34389		this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
34390
34391		this.generateMipmaps = false;
34392
34393		const scope = this;
34394
34395		function updateVideo() {
34396
34397			scope.needsUpdate = true;
34398			video.requestVideoFrameCallback( updateVideo );
34399
34400		}
34401
34402		if ( 'requestVideoFrameCallback' in video ) {
34403
34404			video.requestVideoFrameCallback( updateVideo );
34405
34406		}
34407
34408	}
34409
34410	clone() {
34411
34412		return new this.constructor( this.image ).copy( this );
34413
34414	}
34415
34416	update() {
34417
34418		const video = this.image;
34419		const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
34420
34421		if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
34422
34423			this.needsUpdate = true;
34424
34425		}
34426
34427	}
34428
34429}
34430
34431class FramebufferTexture extends Texture {
34432
34433	constructor( width, height ) {
34434
34435		super( { width, height } );
34436
34437		this.isFramebufferTexture = true;
34438
34439		this.magFilter = NearestFilter;
34440		this.minFilter = NearestFilter;
34441
34442		this.generateMipmaps = false;
34443
34444		this.needsUpdate = true;
34445
34446	}
34447
34448}
34449
34450class CompressedTexture extends Texture {
34451
34452	constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) {
34453
34454		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
34455
34456		this.isCompressedTexture = true;
34457
34458		this.image = { width: width, height: height };
34459		this.mipmaps = mipmaps;
34460
34461		// no flipping for cube textures
34462		// (also flipping doesn't work for compressed textures )
34463
34464		this.flipY = false;
34465
34466		// can't generate mipmaps for compressed textures
34467		// mips must be embedded in DDS files
34468
34469		this.generateMipmaps = false;
34470
34471	}
34472
34473}
34474
34475class CompressedArrayTexture extends CompressedTexture {
34476
34477	constructor( mipmaps, width, height, depth, format, type ) {
34478
34479		super( mipmaps, width, height, format, type );
34480
34481		this.isCompressedArrayTexture = true;
34482		this.image.depth = depth;
34483		this.wrapR = ClampToEdgeWrapping;
34484
34485	}
34486
34487}
34488
34489class CompressedCubeTexture extends CompressedTexture {
34490
34491	constructor( images, format, type ) {
34492
34493		super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );
34494
34495		this.isCompressedCubeTexture = true;
34496		this.isCubeTexture = true;
34497
34498		this.image = images;
34499
34500	}
34501
34502}
34503
34504class CanvasTexture extends Texture {
34505
34506	constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
34507
34508		super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
34509
34510		this.isCanvasTexture = true;
34511
34512		this.needsUpdate = true;
34513
34514	}
34515
34516}
34517
34518/**
34519 * Extensible curve object.
34520 *
34521 * Some common of curve methods:
34522 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
34523 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
34524 * .getPoints(), .getSpacedPoints()
34525 * .getLength()
34526 * .updateArcLengths()
34527 *
34528 * This following curves inherit from THREE.Curve:
34529 *
34530 * -- 2D curves --
34531 * THREE.ArcCurve
34532 * THREE.CubicBezierCurve
34533 * THREE.EllipseCurve
34534 * THREE.LineCurve
34535 * THREE.QuadraticBezierCurve
34536 * THREE.SplineCurve
34537 *
34538 * -- 3D curves --
34539 * THREE.CatmullRomCurve3
34540 * THREE.CubicBezierCurve3
34541 * THREE.LineCurve3
34542 * THREE.QuadraticBezierCurve3
34543 *
34544 * A series of curves can be represented as a THREE.CurvePath.
34545 *
34546 **/
34547
34548class Curve {
34549
34550	constructor() {
34551
34552		this.type = 'Curve';
34553
34554		this.arcLengthDivisions = 200;
34555
34556	}
34557
34558	// Virtual base class method to overwrite and implement in subclasses
34559	//	- t [0 .. 1]
34560
34561	getPoint( /* t, optionalTarget */ ) {
34562
34563		console.warn( 'THREE.Curve: .getPoint() not implemented.' );
34564		return null;
34565
34566	}
34567
34568	// Get point at relative position in curve according to arc length
34569	// - u [0 .. 1]
34570
34571	getPointAt( u, optionalTarget ) {
34572
34573		const t = this.getUtoTmapping( u );
34574		return this.getPoint( t, optionalTarget );
34575
34576	}
34577
34578	// Get sequence of points using getPoint( t )
34579
34580	getPoints( divisions = 5 ) {
34581
34582		const points = [];
34583
34584		for ( let d = 0; d <= divisions; d ++ ) {
34585
34586			points.push( this.getPoint( d / divisions ) );
34587
34588		}
34589
34590		return points;
34591
34592	}
34593
34594	// Get sequence of points using getPointAt( u )
34595
34596	getSpacedPoints( divisions = 5 ) {
34597
34598		const points = [];
34599
34600		for ( let d = 0; d <= divisions; d ++ ) {
34601
34602			points.push( this.getPointAt( d / divisions ) );
34603
34604		}
34605
34606		return points;
34607
34608	}
34609
34610	// Get total curve arc length
34611
34612	getLength() {
34613
34614		const lengths = this.getLengths();
34615		return lengths[ lengths.length - 1 ];
34616
34617	}
34618
34619	// Get list of cumulative segment lengths
34620
34621	getLengths( divisions = this.arcLengthDivisions ) {
34622
34623		if ( this.cacheArcLengths &&
34624			( this.cacheArcLengths.length === divisions + 1 ) &&
34625			! this.needsUpdate ) {
34626
34627			return this.cacheArcLengths;
34628
34629		}
34630
34631		this.needsUpdate = false;
34632
34633		const cache = [];
34634		let current, last = this.getPoint( 0 );
34635		let sum = 0;
34636
34637		cache.push( 0 );
34638
34639		for ( let p = 1; p <= divisions; p ++ ) {
34640
34641			current = this.getPoint( p / divisions );
34642			sum += current.distanceTo( last );
34643			cache.push( sum );
34644			last = current;
34645
34646		}
34647
vendor: 7,167 bytes, lines 34648-34998
34648		this.cacheArcLengths = cache;
34649
34650		return cache; // { sums: cache, sum: sum }; Sum is in the last element.
34651
34652	}
34653
34654	updateArcLengths() {
34655
34656		this.needsUpdate = true;
34657		this.getLengths();
34658
34659	}
34660
34661	// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
34662
34663	getUtoTmapping( u, distance ) {
34664
34665		const arcLengths = this.getLengths();
34666
34667		let i = 0;
34668		const il = arcLengths.length;
34669
34670		let targetArcLength; // The targeted u distance value to get
34671
34672		if ( distance ) {
34673
34674			targetArcLength = distance;
34675
34676		} else {
34677
34678			targetArcLength = u * arcLengths[ il - 1 ];
34679
34680		}
34681
34682		// binary search for the index with largest value smaller than target u distance
34683
34684		let low = 0, high = il - 1, comparison;
34685
34686		while ( low <= high ) {
34687
34688			i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
34689
34690			comparison = arcLengths[ i ] - targetArcLength;
34691
34692			if ( comparison < 0 ) {
34693
34694				low = i + 1;
34695
34696			} else if ( comparison > 0 ) {
34697
34698				high = i - 1;
34699
34700			} else {
34701
34702				high = i;
34703				break;
34704
34705				// DONE
34706
34707			}
34708
34709		}
34710
34711		i = high;
34712
34713		if ( arcLengths[ i ] === targetArcLength ) {
34714
34715			return i / ( il - 1 );
34716
34717		}
34718
34719		// we could get finer grain at lengths, or use simple interpolation between two points
34720
34721		const lengthBefore = arcLengths[ i ];
34722		const lengthAfter = arcLengths[ i + 1 ];
34723
34724		const segmentLength = lengthAfter - lengthBefore;
34725
34726		// determine where we are between the 'before' and 'after' points
34727
34728		const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
34729
34730		// add that fractional amount to t
34731
34732		const t = ( i + segmentFraction ) / ( il - 1 );
34733
34734		return t;
34735
34736	}
34737
34738	// Returns a unit vector tangent at t
34739	// In case any sub curve does not implement its tangent derivation,
34740	// 2 points a small delta apart will be used to find its gradient
34741	// which seems to give a reasonable approximation
34742
34743	getTangent( t, optionalTarget ) {
34744
34745		const delta = 0.0001;
34746		let t1 = t - delta;
34747		let t2 = t + delta;
34748
34749		// Capping in case of danger
34750
34751		if ( t1 < 0 ) t1 = 0;
34752		if ( t2 > 1 ) t2 = 1;
34753
34754		const pt1 = this.getPoint( t1 );
34755		const pt2 = this.getPoint( t2 );
34756
34757		const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
34758
34759		tangent.copy( pt2 ).sub( pt1 ).normalize();
34760
34761		return tangent;
34762
34763	}
34764
34765	getTangentAt( u, optionalTarget ) {
34766
34767		const t = this.getUtoTmapping( u );
34768		return this.getTangent( t, optionalTarget );
34769
34770	}
34771
34772	computeFrenetFrames( segments, closed ) {
34773
34774		// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
34775
34776		const normal = new Vector3();
34777
34778		const tangents = [];
34779		const normals = [];
34780		const binormals = [];
34781
34782		const vec = new Vector3();
34783		const mat = new Matrix4();
34784
34785		// compute the tangent vectors for each segment on the curve
34786
34787		for ( let i = 0; i <= segments; i ++ ) {
34788
34789			const u = i / segments;
34790
34791			tangents[ i ] = this.getTangentAt( u, new Vector3() );
34792
34793		}
34794
34795		// select an initial normal vector perpendicular to the first tangent vector,
34796		// and in the direction of the minimum tangent xyz component
34797
34798		normals[ 0 ] = new Vector3();
34799		binormals[ 0 ] = new Vector3();
34800		let min = Number.MAX_VALUE;
34801		const tx = Math.abs( tangents[ 0 ].x );
34802		const ty = Math.abs( tangents[ 0 ].y );
34803		const tz = Math.abs( tangents[ 0 ].z );
34804
34805		if ( tx <= min ) {
34806
34807			min = tx;
34808			normal.set( 1, 0, 0 );
34809
34810		}
34811
34812		if ( ty <= min ) {
34813
34814			min = ty;
34815			normal.set( 0, 1, 0 );
34816
34817		}
34818
34819		if ( tz <= min ) {
34820
34821			normal.set( 0, 0, 1 );
34822
34823		}
34824
34825		vec.crossVectors( tangents[ 0 ], normal ).normalize();
34826
34827		normals[ 0 ].crossVectors( tangents[ 0 ], vec );
34828		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
34829
34830
34831		// compute the slowly-varying normal and binormal vectors for each segment on the curve
34832
34833		for ( let i = 1; i <= segments; i ++ ) {
34834
34835			normals[ i ] = normals[ i - 1 ].clone();
34836
34837			binormals[ i ] = binormals[ i - 1 ].clone();
34838
34839			vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
34840
34841			if ( vec.length() > Number.EPSILON ) {
34842
34843				vec.normalize();
34844
34845				const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
34846
34847				normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
34848
34849			}
34850
34851			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34852
34853		}
34854
34855		// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
34856
34857		if ( closed === true ) {
34858
34859			let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
34860			theta /= segments;
34861
34862			if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
34863
34864				theta = - theta;
34865
34866			}
34867
34868			for ( let i = 1; i <= segments; i ++ ) {
34869
34870				// twist a little...
34871				normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
34872				binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34873
34874			}
34875
34876		}
34877
34878		return {
34879			tangents: tangents,
34880			normals: normals,
34881			binormals: binormals
34882		};
34883
34884	}
34885
34886	clone() {
34887
34888		return new this.constructor().copy( this );
34889
34890	}
34891
34892	copy( source ) {
34893
34894		this.arcLengthDivisions = source.arcLengthDivisions;
34895
34896		return this;
34897
34898	}
34899
34900	toJSON() {
34901
34902		const data = {
34903			metadata: {
34904				version: 4.6,
34905				type: 'Curve',
34906				generator: 'Curve.toJSON'
34907			}
34908		};
34909
34910		data.arcLengthDivisions = this.arcLengthDivisions;
34911		data.type = this.type;
34912
34913		return data;
34914
34915	}
34916
34917	fromJSON( json ) {
34918
34919		this.arcLengthDivisions = json.arcLengthDivisions;
34920
34921		return this;
34922
34923	}
34924
34925}
34926
34927class EllipseCurve extends Curve {
34928
34929	constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
34930
34931		super();
34932
34933		this.isEllipseCurve = true;
34934
34935		this.type = 'EllipseCurve';
34936
34937		this.aX = aX;
34938		this.aY = aY;
34939
34940		this.xRadius = xRadius;
34941		this.yRadius = yRadius;
34942
34943		this.aStartAngle = aStartAngle;
34944		this.aEndAngle = aEndAngle;
34945
34946		this.aClockwise = aClockwise;
34947
34948		this.aRotation = aRotation;
34949
34950	}
34951
34952	getPoint( t, optionalTarget ) {
34953
34954		const point = optionalTarget || new Vector2();
34955
34956		const twoPi = Math.PI * 2;
34957		let deltaAngle = this.aEndAngle - this.aStartAngle;
34958		const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
34959
34960		// ensures that deltaAngle is 0 .. 2 PI
34961		while ( deltaAngle < 0 ) deltaAngle += twoPi;
34962		while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
34963
34964		if ( deltaAngle < Number.EPSILON ) {
34965
34966			if ( samePoints ) {
34967
34968				deltaAngle = 0;
34969
34970			} else {
34971
34972				deltaAngle = twoPi;
34973
34974			}
34975
34976		}
34977
34978		if ( this.aClockwise === true && ! samePoints ) {
34979
34980			if ( deltaAngle === twoPi ) {
34981
34982				deltaAngle = - twoPi;
34983
34984			} else {
34985
34986				deltaAngle = deltaAngle - twoPi;
34987
34988			}
34989
34990		}
34991
34992		const angle = this.aStartAngle + t * deltaAngle;
34993		let x = this.aX + this.xRadius * Math.cos( angle );
34994		let y = this.aY + this.yRadius * Math.sin( angle );
34995
34996		if ( this.aRotation !== 0 ) {
34997
34998			const cos = Math.cos( this.aRotation );
vendor: 32,499 bytes, lines 34999-36739
34999			const sin = Math.sin( this.aRotation );
35000
35001			const tx = x - this.aX;
35002			const ty = y - this.aY;
35003
35004			// Rotate the point about the center of the ellipse.
35005			x = tx * cos - ty * sin + this.aX;
35006			y = tx * sin + ty * cos + this.aY;
35007
35008		}
35009
35010		return point.set( x, y );
35011
35012	}
35013
35014	copy( source ) {
35015
35016		super.copy( source );
35017
35018		this.aX = source.aX;
35019		this.aY = source.aY;
35020
35021		this.xRadius = source.xRadius;
35022		this.yRadius = source.yRadius;
35023
35024		this.aStartAngle = source.aStartAngle;
35025		this.aEndAngle = source.aEndAngle;
35026
35027		this.aClockwise = source.aClockwise;
35028
35029		this.aRotation = source.aRotation;
35030
35031		return this;
35032
35033	}
35034
35035	toJSON() {
35036
35037		const data = super.toJSON();
35038
35039		data.aX = this.aX;
35040		data.aY = this.aY;
35041
35042		data.xRadius = this.xRadius;
35043		data.yRadius = this.yRadius;
35044
35045		data.aStartAngle = this.aStartAngle;
35046		data.aEndAngle = this.aEndAngle;
35047
35048		data.aClockwise = this.aClockwise;
35049
35050		data.aRotation = this.aRotation;
35051
35052		return data;
35053
35054	}
35055
35056	fromJSON( json ) {
35057
35058		super.fromJSON( json );
35059
35060		this.aX = json.aX;
35061		this.aY = json.aY;
35062
35063		this.xRadius = json.xRadius;
35064		this.yRadius = json.yRadius;
35065
35066		this.aStartAngle = json.aStartAngle;
35067		this.aEndAngle = json.aEndAngle;
35068
35069		this.aClockwise = json.aClockwise;
35070
35071		this.aRotation = json.aRotation;
35072
35073		return this;
35074
35075	}
35076
35077}
35078
35079class ArcCurve extends EllipseCurve {
35080
35081	constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35082
35083		super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
35084
35085		this.isArcCurve = true;
35086
35087		this.type = 'ArcCurve';
35088
35089	}
35090
35091}
35092
35093/**
35094 * Centripetal CatmullRom Curve - which is useful for avoiding
35095 * cusps and self-intersections in non-uniform catmull rom curves.
35096 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
35097 *
35098 * curve.type accepts centripetal(default), chordal and catmullrom
35099 * curve.tension is used for catmullrom which defaults to 0.5
35100 */
35101
35102
35103/*
35104Based on an optimized c++ solution in
35105 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
35106 - http://ideone.com/NoEbVM
35107
35108This CubicPoly class could be used for reusing some variables and calculations,
35109but for three.js curve use, it could be possible inlined and flatten into a single function call
35110which can be placed in CurveUtils.
35111*/
35112
35113function CubicPoly() {
35114
35115	let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
35116
35117	/*
35118	 * Compute coefficients for a cubic polynomial
35119	 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
35120	 * such that
35121	 *   p(0) = x0, p(1) = x1
35122	 *  and
35123	 *   p'(0) = t0, p'(1) = t1.
35124	 */
35125	function init( x0, x1, t0, t1 ) {
35126
35127		c0 = x0;
35128		c1 = t0;
35129		c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
35130		c3 = 2 * x0 - 2 * x1 + t0 + t1;
35131
35132	}
35133
35134	return {
35135
35136		initCatmullRom: function ( x0, x1, x2, x3, tension ) {
35137
35138			init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
35139
35140		},
35141
35142		initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
35143
35144			// compute tangents when parameterized in [t1,t2]
35145			let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
35146			let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
35147
35148			// rescale tangents for parametrization in [0,1]
35149			t1 *= dt1;
35150			t2 *= dt1;
35151
35152			init( x1, x2, t1, t2 );
35153
35154		},
35155
35156		calc: function ( t ) {
35157
35158			const t2 = t * t;
35159			const t3 = t2 * t;
35160			return c0 + c1 * t + c2 * t2 + c3 * t3;
35161
35162		}
35163
35164	};
35165
35166}
35167
35168//
35169
35170const tmp = /*@__PURE__*/ new Vector3();
35171const px = /*@__PURE__*/ new CubicPoly();
35172const py = /*@__PURE__*/ new CubicPoly();
35173const pz = /*@__PURE__*/ new CubicPoly();
35174
35175class CatmullRomCurve3 extends Curve {
35176
35177	constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
35178
35179		super();
35180
35181		this.isCatmullRomCurve3 = true;
35182
35183		this.type = 'CatmullRomCurve3';
35184
35185		this.points = points;
35186		this.closed = closed;
35187		this.curveType = curveType;
35188		this.tension = tension;
35189
35190	}
35191
35192	getPoint( t, optionalTarget = new Vector3() ) {
35193
35194		const point = optionalTarget;
35195
35196		const points = this.points;
35197		const l = points.length;
35198
35199		const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
35200		let intPoint = Math.floor( p );
35201		let weight = p - intPoint;
35202
35203		if ( this.closed ) {
35204
35205			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
35206
35207		} else if ( weight === 0 && intPoint === l - 1 ) {
35208
35209			intPoint = l - 2;
35210			weight = 1;
35211
35212		}
35213
35214		let p0, p3; // 4 points (p1 & p2 defined below)
35215
35216		if ( this.closed || intPoint > 0 ) {
35217
35218			p0 = points[ ( intPoint - 1 ) % l ];
35219
35220		} else {
35221
35222			// extrapolate first point
35223			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
35224			p0 = tmp;
35225
35226		}
35227
35228		const p1 = points[ intPoint % l ];
35229		const p2 = points[ ( intPoint + 1 ) % l ];
35230
35231		if ( this.closed || intPoint + 2 < l ) {
35232
35233			p3 = points[ ( intPoint + 2 ) % l ];
35234
35235		} else {
35236
35237			// extrapolate last point
35238			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
35239			p3 = tmp;
35240
35241		}
35242
35243		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
35244
35245			// init Centripetal / Chordal Catmull-Rom
35246			const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
35247			let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
35248			let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
35249			let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
35250
35251			// safety check for repeated points
35252			if ( dt1 < 1e-4 ) dt1 = 1.0;
35253			if ( dt0 < 1e-4 ) dt0 = dt1;
35254			if ( dt2 < 1e-4 ) dt2 = dt1;
35255
35256			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
35257			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
35258			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
35259
35260		} else if ( this.curveType === 'catmullrom' ) {
35261
35262			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
35263			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
35264			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
35265
35266		}
35267
35268		point.set(
35269			px.calc( weight ),
35270			py.calc( weight ),
35271			pz.calc( weight )
35272		);
35273
35274		return point;
35275
35276	}
35277
35278	copy( source ) {
35279
35280		super.copy( source );
35281
35282		this.points = [];
35283
35284		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35285
35286			const point = source.points[ i ];
35287
35288			this.points.push( point.clone() );
35289
35290		}
35291
35292		this.closed = source.closed;
35293		this.curveType = source.curveType;
35294		this.tension = source.tension;
35295
35296		return this;
35297
35298	}
35299
35300	toJSON() {
35301
35302		const data = super.toJSON();
35303
35304		data.points = [];
35305
35306		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35307
35308			const point = this.points[ i ];
35309			data.points.push( point.toArray() );
35310
35311		}
35312
35313		data.closed = this.closed;
35314		data.curveType = this.curveType;
35315		data.tension = this.tension;
35316
35317		return data;
35318
35319	}
35320
35321	fromJSON( json ) {
35322
35323		super.fromJSON( json );
35324
35325		this.points = [];
35326
35327		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35328
35329			const point = json.points[ i ];
35330			this.points.push( new Vector3().fromArray( point ) );
35331
35332		}
35333
35334		this.closed = json.closed;
35335		this.curveType = json.curveType;
35336		this.tension = json.tension;
35337
35338		return this;
35339
35340	}
35341
35342}
35343
35344/**
35345 * Bezier Curves formulas obtained from
35346 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
35347 */
35348
35349function CatmullRom( t, p0, p1, p2, p3 ) {
35350
35351	const v0 = ( p2 - p0 ) * 0.5;
35352	const v1 = ( p3 - p1 ) * 0.5;
35353	const t2 = t * t;
35354	const t3 = t * t2;
35355	return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
35356
35357}
35358
35359//
35360
35361function QuadraticBezierP0( t, p ) {
35362
35363	const k = 1 - t;
35364	return k * k * p;
35365
35366}
35367
35368function QuadraticBezierP1( t, p ) {
35369
35370	return 2 * ( 1 - t ) * t * p;
35371
35372}
35373
35374function QuadraticBezierP2( t, p ) {
35375
35376	return t * t * p;
35377
35378}
35379
35380function QuadraticBezier( t, p0, p1, p2 ) {
35381
35382	return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
35383		QuadraticBezierP2( t, p2 );
35384
35385}
35386
35387//
35388
35389function CubicBezierP0( t, p ) {
35390
35391	const k = 1 - t;
35392	return k * k * k * p;
35393
35394}
35395
35396function CubicBezierP1( t, p ) {
35397
35398	const k = 1 - t;
35399	return 3 * k * k * t * p;
35400
35401}
35402
35403function CubicBezierP2( t, p ) {
35404
35405	return 3 * ( 1 - t ) * t * t * p;
35406
35407}
35408
35409function CubicBezierP3( t, p ) {
35410
35411	return t * t * t * p;
35412
35413}
35414
35415function CubicBezier( t, p0, p1, p2, p3 ) {
35416
35417	return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
35418		CubicBezierP3( t, p3 );
35419
35420}
35421
35422class CubicBezierCurve extends Curve {
35423
35424	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
35425
35426		super();
35427
35428		this.isCubicBezierCurve = true;
35429
35430		this.type = 'CubicBezierCurve';
35431
35432		this.v0 = v0;
35433		this.v1 = v1;
35434		this.v2 = v2;
35435		this.v3 = v3;
35436
35437	}
35438
35439	getPoint( t, optionalTarget = new Vector2() ) {
35440
35441		const point = optionalTarget;
35442
35443		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35444
35445		point.set(
35446			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35447			CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
35448		);
35449
35450		return point;
35451
35452	}
35453
35454	copy( source ) {
35455
35456		super.copy( source );
35457
35458		this.v0.copy( source.v0 );
35459		this.v1.copy( source.v1 );
35460		this.v2.copy( source.v2 );
35461		this.v3.copy( source.v3 );
35462
35463		return this;
35464
35465	}
35466
35467	toJSON() {
35468
35469		const data = super.toJSON();
35470
35471		data.v0 = this.v0.toArray();
35472		data.v1 = this.v1.toArray();
35473		data.v2 = this.v2.toArray();
35474		data.v3 = this.v3.toArray();
35475
35476		return data;
35477
35478	}
35479
35480	fromJSON( json ) {
35481
35482		super.fromJSON( json );
35483
35484		this.v0.fromArray( json.v0 );
35485		this.v1.fromArray( json.v1 );
35486		this.v2.fromArray( json.v2 );
35487		this.v3.fromArray( json.v3 );
35488
35489		return this;
35490
35491	}
35492
35493}
35494
35495class CubicBezierCurve3 extends Curve {
35496
35497	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
35498
35499		super();
35500
35501		this.isCubicBezierCurve3 = true;
35502
35503		this.type = 'CubicBezierCurve3';
35504
35505		this.v0 = v0;
35506		this.v1 = v1;
35507		this.v2 = v2;
35508		this.v3 = v3;
35509
35510	}
35511
35512	getPoint( t, optionalTarget = new Vector3() ) {
35513
35514		const point = optionalTarget;
35515
35516		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35517
35518		point.set(
35519			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35520			CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
35521			CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
35522		);
35523
35524		return point;
35525
35526	}
35527
35528	copy( source ) {
35529
35530		super.copy( source );
35531
35532		this.v0.copy( source.v0 );
35533		this.v1.copy( source.v1 );
35534		this.v2.copy( source.v2 );
35535		this.v3.copy( source.v3 );
35536
35537		return this;
35538
35539	}
35540
35541	toJSON() {
35542
35543		const data = super.toJSON();
35544
35545		data.v0 = this.v0.toArray();
35546		data.v1 = this.v1.toArray();
35547		data.v2 = this.v2.toArray();
35548		data.v3 = this.v3.toArray();
35549
35550		return data;
35551
35552	}
35553
35554	fromJSON( json ) {
35555
35556		super.fromJSON( json );
35557
35558		this.v0.fromArray( json.v0 );
35559		this.v1.fromArray( json.v1 );
35560		this.v2.fromArray( json.v2 );
35561		this.v3.fromArray( json.v3 );
35562
35563		return this;
35564
35565	}
35566
35567}
35568
35569class LineCurve extends Curve {
35570
35571	constructor( v1 = new Vector2(), v2 = new Vector2() ) {
35572
35573		super();
35574
35575		this.isLineCurve = true;
35576
35577		this.type = 'LineCurve';
35578
35579		this.v1 = v1;
35580		this.v2 = v2;
35581
35582	}
35583
35584	getPoint( t, optionalTarget = new Vector2() ) {
35585
35586		const point = optionalTarget;
35587
35588		if ( t === 1 ) {
35589
35590			point.copy( this.v2 );
35591
35592		} else {
35593
35594			point.copy( this.v2 ).sub( this.v1 );
35595			point.multiplyScalar( t ).add( this.v1 );
35596
35597		}
35598
35599		return point;
35600
35601	}
35602
35603	// Line curve is linear, so we can overwrite default getPointAt
35604	getPointAt( u, optionalTarget ) {
35605
35606		return this.getPoint( u, optionalTarget );
35607
35608	}
35609
35610	getTangent( t, optionalTarget = new Vector2() ) {
35611
35612		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35613
35614	}
35615
35616	getTangentAt( u, optionalTarget ) {
35617
35618		return this.getTangent( u, optionalTarget );
35619
35620	}
35621
35622	copy( source ) {
35623
35624		super.copy( source );
35625
35626		this.v1.copy( source.v1 );
35627		this.v2.copy( source.v2 );
35628
35629		return this;
35630
35631	}
35632
35633	toJSON() {
35634
35635		const data = super.toJSON();
35636
35637		data.v1 = this.v1.toArray();
35638		data.v2 = this.v2.toArray();
35639
35640		return data;
35641
35642	}
35643
35644	fromJSON( json ) {
35645
35646		super.fromJSON( json );
35647
35648		this.v1.fromArray( json.v1 );
35649		this.v2.fromArray( json.v2 );
35650
35651		return this;
35652
35653	}
35654
35655}
35656
35657class LineCurve3 extends Curve {
35658
35659	constructor( v1 = new Vector3(), v2 = new Vector3() ) {
35660
35661		super();
35662
35663		this.isLineCurve3 = true;
35664
35665		this.type = 'LineCurve3';
35666
35667		this.v1 = v1;
35668		this.v2 = v2;
35669
35670	}
35671
35672	getPoint( t, optionalTarget = new Vector3() ) {
35673
35674		const point = optionalTarget;
35675
35676		if ( t === 1 ) {
35677
35678			point.copy( this.v2 );
35679
35680		} else {
35681
35682			point.copy( this.v2 ).sub( this.v1 );
35683			point.multiplyScalar( t ).add( this.v1 );
35684
35685		}
35686
35687		return point;
35688
35689	}
35690
35691	// Line curve is linear, so we can overwrite default getPointAt
35692	getPointAt( u, optionalTarget ) {
35693
35694		return this.getPoint( u, optionalTarget );
35695
35696	}
35697
35698	getTangent( t, optionalTarget = new Vector3() ) {
35699
35700		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35701
35702	}
35703
35704	getTangentAt( u, optionalTarget ) {
35705
35706		return this.getTangent( u, optionalTarget );
35707
35708	}
35709
35710	copy( source ) {
35711
35712		super.copy( source );
35713
35714		this.v1.copy( source.v1 );
35715		this.v2.copy( source.v2 );
35716
35717		return this;
35718
35719	}
35720
35721	toJSON() {
35722
35723		const data = super.toJSON();
35724
35725		data.v1 = this.v1.toArray();
35726		data.v2 = this.v2.toArray();
35727
35728		return data;
35729
35730	}
35731
35732	fromJSON( json ) {
35733
35734		super.fromJSON( json );
35735
35736		this.v1.fromArray( json.v1 );
35737		this.v2.fromArray( json.v2 );
35738
35739		return this;
35740
35741	}
35742
35743}
35744
35745class QuadraticBezierCurve extends Curve {
35746
35747	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
35748
35749		super();
35750
35751		this.isQuadraticBezierCurve = true;
35752
35753		this.type = 'QuadraticBezierCurve';
35754
35755		this.v0 = v0;
35756		this.v1 = v1;
35757		this.v2 = v2;
35758
35759	}
35760
35761	getPoint( t, optionalTarget = new Vector2() ) {
35762
35763		const point = optionalTarget;
35764
35765		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35766
35767		point.set(
35768			QuadraticBezier( t, v0.x, v1.x, v2.x ),
35769			QuadraticBezier( t, v0.y, v1.y, v2.y )
35770		);
35771
35772		return point;
35773
35774	}
35775
35776	copy( source ) {
35777
35778		super.copy( source );
35779
35780		this.v0.copy( source.v0 );
35781		this.v1.copy( source.v1 );
35782		this.v2.copy( source.v2 );
35783
35784		return this;
35785
35786	}
35787
35788	toJSON() {
35789
35790		const data = super.toJSON();
35791
35792		data.v0 = this.v0.toArray();
35793		data.v1 = this.v1.toArray();
35794		data.v2 = this.v2.toArray();
35795
35796		return data;
35797
35798	}
35799
35800	fromJSON( json ) {
35801
35802		super.fromJSON( json );
35803
35804		this.v0.fromArray( json.v0 );
35805		this.v1.fromArray( json.v1 );
35806		this.v2.fromArray( json.v2 );
35807
35808		return this;
35809
35810	}
35811
35812}
35813
35814class QuadraticBezierCurve3 extends Curve {
35815
35816	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
35817
35818		super();
35819
35820		this.isQuadraticBezierCurve3 = true;
35821
35822		this.type = 'QuadraticBezierCurve3';
35823
35824		this.v0 = v0;
35825		this.v1 = v1;
35826		this.v2 = v2;
35827
35828	}
35829
35830	getPoint( t, optionalTarget = new Vector3() ) {
35831
35832		const point = optionalTarget;
35833
35834		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35835
35836		point.set(
35837			QuadraticBezier( t, v0.x, v1.x, v2.x ),
35838			QuadraticBezier( t, v0.y, v1.y, v2.y ),
35839			QuadraticBezier( t, v0.z, v1.z, v2.z )
35840		);
35841
35842		return point;
35843
35844	}
35845
35846	copy( source ) {
35847
35848		super.copy( source );
35849
35850		this.v0.copy( source.v0 );
35851		this.v1.copy( source.v1 );
35852		this.v2.copy( source.v2 );
35853
35854		return this;
35855
35856	}
35857
35858	toJSON() {
35859
35860		const data = super.toJSON();
35861
35862		data.v0 = this.v0.toArray();
35863		data.v1 = this.v1.toArray();
35864		data.v2 = this.v2.toArray();
35865
35866		return data;
35867
35868	}
35869
35870	fromJSON( json ) {
35871
35872		super.fromJSON( json );
35873
35874		this.v0.fromArray( json.v0 );
35875		this.v1.fromArray( json.v1 );
35876		this.v2.fromArray( json.v2 );
35877
35878		return this;
35879
35880	}
35881
35882}
35883
35884class SplineCurve extends Curve {
35885
35886	constructor( points = [] ) {
35887
35888		super();
35889
35890		this.isSplineCurve = true;
35891
35892		this.type = 'SplineCurve';
35893
35894		this.points = points;
35895
35896	}
35897
35898	getPoint( t, optionalTarget = new Vector2() ) {
35899
35900		const point = optionalTarget;
35901
35902		const points = this.points;
35903		const p = ( points.length - 1 ) * t;
35904
35905		const intPoint = Math.floor( p );
35906		const weight = p - intPoint;
35907
35908		const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
35909		const p1 = points[ intPoint ];
35910		const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
35911		const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
35912
35913		point.set(
35914			CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
35915			CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
35916		);
35917
35918		return point;
35919
35920	}
35921
35922	copy( source ) {
35923
35924		super.copy( source );
35925
35926		this.points = [];
35927
35928		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35929
35930			const point = source.points[ i ];
35931
35932			this.points.push( point.clone() );
35933
35934		}
35935
35936		return this;
35937
35938	}
35939
35940	toJSON() {
35941
35942		const data = super.toJSON();
35943
35944		data.points = [];
35945
35946		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35947
35948			const point = this.points[ i ];
35949			data.points.push( point.toArray() );
35950
35951		}
35952
35953		return data;
35954
35955	}
35956
35957	fromJSON( json ) {
35958
35959		super.fromJSON( json );
35960
35961		this.points = [];
35962
35963		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35964
35965			const point = json.points[ i ];
35966			this.points.push( new Vector2().fromArray( point ) );
35967
35968		}
35969
35970		return this;
35971
35972	}
35973
35974}
35975
35976var Curves = /*#__PURE__*/Object.freeze({
35977	__proto__: null,
35978	ArcCurve: ArcCurve,
35979	CatmullRomCurve3: CatmullRomCurve3,
35980	CubicBezierCurve: CubicBezierCurve,
35981	CubicBezierCurve3: CubicBezierCurve3,
35982	EllipseCurve: EllipseCurve,
35983	LineCurve: LineCurve,
35984	LineCurve3: LineCurve3,
35985	QuadraticBezierCurve: QuadraticBezierCurve,
35986	QuadraticBezierCurve3: QuadraticBezierCurve3,
35987	SplineCurve: SplineCurve
35988});
35989
35990/**************************************************************
35991 *	Curved Path - a curve path is simply a array of connected
35992 *  curves, but retains the api of a curve
35993 **************************************************************/
35994
35995class CurvePath extends Curve {
35996
35997	constructor() {
35998
35999		super();
36000
36001		this.type = 'CurvePath';
36002
36003		this.curves = [];
36004		this.autoClose = false; // Automatically closes the path
36005
36006	}
36007
36008	add( curve ) {
36009
36010		this.curves.push( curve );
36011
36012	}
36013
36014	closePath() {
36015
36016		// Add a line curve if start and end of lines are not connected
36017		const startPoint = this.curves[ 0 ].getPoint( 0 );
36018		const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
36019
36020		if ( ! startPoint.equals( endPoint ) ) {
36021
36022			const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
36023			this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
36024
36025		}
36026
36027		return this;
36028
36029	}
36030
36031	// To get accurate point with reference to
36032	// entire path distance at time t,
36033	// following has to be done:
36034
36035	// 1. Length of each sub path have to be known
36036	// 2. Locate and identify type of curve
36037	// 3. Get t for the curve
36038	// 4. Return curve.getPointAt(t')
36039
36040	getPoint( t, optionalTarget ) {
36041
36042		const d = t * this.getLength();
36043		const curveLengths = this.getCurveLengths();
36044		let i = 0;
36045
36046		// To think about boundaries points.
36047
36048		while ( i < curveLengths.length ) {
36049
36050			if ( curveLengths[ i ] >= d ) {
36051
36052				const diff = curveLengths[ i ] - d;
36053				const curve = this.curves[ i ];
36054
36055				const segmentLength = curve.getLength();
36056				const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
36057
36058				return curve.getPointAt( u, optionalTarget );
36059
36060			}
36061
36062			i ++;
36063
36064		}
36065
36066		return null;
36067
36068		// loop where sum != 0, sum > d , sum+1 <d
36069
36070	}
36071
36072	// We cannot use the default THREE.Curve getPoint() with getLength() because in
36073	// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
36074	// getPoint() depends on getLength
36075
36076	getLength() {
36077
36078		const lens = this.getCurveLengths();
36079		return lens[ lens.length - 1 ];
36080
36081	}
36082
36083	// cacheLengths must be recalculated.
36084	updateArcLengths() {
36085
36086		this.needsUpdate = true;
36087		this.cacheLengths = null;
36088		this.getCurveLengths();
36089
36090	}
36091
36092	// Compute lengths and cache them
36093	// We cannot overwrite getLengths() because UtoT mapping uses it.
36094
36095	getCurveLengths() {
36096
36097		// We use cache values if curves and cache array are same length
36098
36099		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
36100
36101			return this.cacheLengths;
36102
36103		}
36104
36105		// Get length of sub-curve
36106		// Push sums into cached array
36107
36108		const lengths = [];
36109		let sums = 0;
36110
36111		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36112
36113			sums += this.curves[ i ].getLength();
36114			lengths.push( sums );
36115
36116		}
36117
36118		this.cacheLengths = lengths;
36119
36120		return lengths;
36121
36122	}
36123
36124	getSpacedPoints( divisions = 40 ) {
36125
36126		const points = [];
36127
36128		for ( let i = 0; i <= divisions; i ++ ) {
36129
36130			points.push( this.getPoint( i / divisions ) );
36131
36132		}
36133
36134		if ( this.autoClose ) {
36135
36136			points.push( points[ 0 ] );
36137
36138		}
36139
36140		return points;
36141
36142	}
36143
36144	getPoints( divisions = 12 ) {
36145
36146		const points = [];
36147		let last;
36148
36149		for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
36150
36151			const curve = curves[ i ];
36152			const resolution = curve.isEllipseCurve ? divisions * 2
36153				: ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
36154					: curve.isSplineCurve ? divisions * curve.points.length
36155						: divisions;
36156
36157			const pts = curve.getPoints( resolution );
36158
36159			for ( let j = 0; j < pts.length; j ++ ) {
36160
36161				const point = pts[ j ];
36162
36163				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
36164
36165				points.push( point );
36166				last = point;
36167
36168			}
36169
36170		}
36171
36172		if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
36173
36174			points.push( points[ 0 ] );
36175
36176		}
36177
36178		return points;
36179
36180	}
36181
36182	copy( source ) {
36183
36184		super.copy( source );
36185
36186		this.curves = [];
36187
36188		for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
36189
36190			const curve = source.curves[ i ];
36191
36192			this.curves.push( curve.clone() );
36193
36194		}
36195
36196		this.autoClose = source.autoClose;
36197
36198		return this;
36199
36200	}
36201
36202	toJSON() {
36203
36204		const data = super.toJSON();
36205
36206		data.autoClose = this.autoClose;
36207		data.curves = [];
36208
36209		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36210
36211			const curve = this.curves[ i ];
36212			data.curves.push( curve.toJSON() );
36213
36214		}
36215
36216		return data;
36217
36218	}
36219
36220	fromJSON( json ) {
36221
36222		super.fromJSON( json );
36223
36224		this.autoClose = json.autoClose;
36225		this.curves = [];
36226
36227		for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
36228
36229			const curve = json.curves[ i ];
36230			this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
36231
36232		}
36233
36234		return this;
36235
36236	}
36237
36238}
36239
36240class Path extends CurvePath {
36241
36242	constructor( points ) {
36243
36244		super();
36245
36246		this.type = 'Path';
36247
36248		this.currentPoint = new Vector2();
36249
36250		if ( points ) {
36251
36252			this.setFromPoints( points );
36253
36254		}
36255
36256	}
36257
36258	setFromPoints( points ) {
36259
36260		this.moveTo( points[ 0 ].x, points[ 0 ].y );
36261
36262		for ( let i = 1, l = points.length; i < l; i ++ ) {
36263
36264			this.lineTo( points[ i ].x, points[ i ].y );
36265
36266		}
36267
36268		return this;
36269
36270	}
36271
36272	moveTo( x, y ) {
36273
36274		this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
36275
36276		return this;
36277
36278	}
36279
36280	lineTo( x, y ) {
36281
36282		const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
36283		this.curves.push( curve );
36284
36285		this.currentPoint.set( x, y );
36286
36287		return this;
36288
36289	}
36290
36291	quadraticCurveTo( aCPx, aCPy, aX, aY ) {
36292
36293		const curve = new QuadraticBezierCurve(
36294			this.currentPoint.clone(),
36295			new Vector2( aCPx, aCPy ),
36296			new Vector2( aX, aY )
36297		);
36298
36299		this.curves.push( curve );
36300
36301		this.currentPoint.set( aX, aY );
36302
36303		return this;
36304
36305	}
36306
36307	bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
36308
36309		const curve = new CubicBezierCurve(
36310			this.currentPoint.clone(),
36311			new Vector2( aCP1x, aCP1y ),
36312			new Vector2( aCP2x, aCP2y ),
36313			new Vector2( aX, aY )
36314		);
36315
36316		this.curves.push( curve );
36317
36318		this.currentPoint.set( aX, aY );
36319
36320		return this;
36321
36322	}
36323
36324	splineThru( pts /*Array of Vector*/ ) {
36325
36326		const npts = [ this.currentPoint.clone() ].concat( pts );
36327
36328		const curve = new SplineCurve( npts );
36329		this.curves.push( curve );
36330
36331		this.currentPoint.copy( pts[ pts.length - 1 ] );
36332
36333		return this;
36334
36335	}
36336
36337	arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36338
36339		const x0 = this.currentPoint.x;
36340		const y0 = this.currentPoint.y;
36341
36342		this.absarc( aX + x0, aY + y0, aRadius,
36343			aStartAngle, aEndAngle, aClockwise );
36344
36345		return this;
36346
36347	}
36348
36349	absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36350
36351		this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
36352
36353		return this;
36354
36355	}
36356
36357	ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36358
36359		const x0 = this.currentPoint.x;
36360		const y0 = this.currentPoint.y;
36361
36362		this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36363
36364		return this;
36365
36366	}
36367
36368	absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36369
36370		const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36371
36372		if ( this.curves.length > 0 ) {
36373
36374			// if a previous curve is present, attempt to join
36375			const firstPoint = curve.getPoint( 0 );
36376
36377			if ( ! firstPoint.equals( this.currentPoint ) ) {
36378
36379				this.lineTo( firstPoint.x, firstPoint.y );
36380
36381			}
36382
36383		}
36384
36385		this.curves.push( curve );
36386
36387		const lastPoint = curve.getPoint( 1 );
36388		this.currentPoint.copy( lastPoint );
36389
36390		return this;
36391
36392	}
36393
36394	copy( source ) {
36395
36396		super.copy( source );
36397
36398		this.currentPoint.copy( source.currentPoint );
36399
36400		return this;
36401
36402	}
36403
36404	toJSON() {
36405
36406		const data = super.toJSON();
36407
36408		data.currentPoint = this.currentPoint.toArray();
36409
36410		return data;
36411
36412	}
36413
36414	fromJSON( json ) {
36415
36416		super.fromJSON( json );
36417
36418		this.currentPoint.fromArray( json.currentPoint );
36419
36420		return this;
36421
36422	}
36423
36424}
36425
36426class LatheGeometry extends BufferGeometry {
36427
36428	constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {
36429
36430		super();
36431
36432		this.type = 'LatheGeometry';
36433
36434		this.parameters = {
36435			points: points,
36436			segments: segments,
36437			phiStart: phiStart,
36438			phiLength: phiLength
36439		};
36440
36441		segments = Math.floor( segments );
36442
36443		// clamp phiLength so it's in range of [ 0, 2PI ]
36444
36445		phiLength = clamp( phiLength, 0, Math.PI * 2 );
36446
36447		// buffers
36448
36449		const indices = [];
36450		const vertices = [];
36451		const uvs = [];
36452		const initNormals = [];
36453		const normals = [];
36454
36455		// helper variables
36456
36457		const inverseSegments = 1.0 / segments;
36458		const vertex = new Vector3();
36459		const uv = new Vector2();
36460		const normal = new Vector3();
36461		const curNormal = new Vector3();
36462		const prevNormal = new Vector3();
36463		let dx = 0;
36464		let dy = 0;
36465
36466		// pre-compute normals for initial "meridian"
36467
36468		for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36469
36470			switch ( j ) {
36471
36472				case 0:				// special handling for 1st vertex on path
36473
36474					dx = points[ j + 1 ].x - points[ j ].x;
36475					dy = points[ j + 1 ].y - points[ j ].y;
36476
36477					normal.x = dy * 1.0;
36478					normal.y = - dx;
36479					normal.z = dy * 0.0;
36480
36481					prevNormal.copy( normal );
36482
36483					normal.normalize();
36484
36485					initNormals.push( normal.x, normal.y, normal.z );
36486
36487					break;
36488
36489				case ( points.length - 1 ):	// special handling for last Vertex on path
36490
36491					initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z );
36492
36493					break;
36494
36495				default:			// default handling for all vertices in between
36496
36497					dx = points[ j + 1 ].x - points[ j ].x;
36498					dy = points[ j + 1 ].y - points[ j ].y;
36499
36500					normal.x = dy * 1.0;
36501					normal.y = - dx;
36502					normal.z = dy * 0.0;
36503
36504					curNormal.copy( normal );
36505
36506					normal.x += prevNormal.x;
36507					normal.y += prevNormal.y;
36508					normal.z += prevNormal.z;
36509
36510					normal.normalize();
36511
36512					initNormals.push( normal.x, normal.y, normal.z );
36513
36514					prevNormal.copy( curNormal );
36515
36516			}
36517
36518		}
36519
36520		// generate vertices, uvs and normals
36521
36522		for ( let i = 0; i <= segments; i ++ ) {
36523
36524			const phi = phiStart + i * inverseSegments * phiLength;
36525
36526			const sin = Math.sin( phi );
36527			const cos = Math.cos( phi );
36528
36529			for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36530
36531				// vertex
36532
36533				vertex.x = points[ j ].x * sin;
36534				vertex.y = points[ j ].y;
36535				vertex.z = points[ j ].x * cos;
36536
36537				vertices.push( vertex.x, vertex.y, vertex.z );
36538
36539				// uv
36540
36541				uv.x = i / segments;
36542				uv.y = j / ( points.length - 1 );
36543
36544				uvs.push( uv.x, uv.y );
36545
36546				// normal
36547
36548				const x = initNormals[ 3 * j + 0 ] * sin;
36549				const y = initNormals[ 3 * j + 1 ];
36550				const z = initNormals[ 3 * j + 0 ] * cos;
36551
36552				normals.push( x, y, z );
36553
36554			}
36555
36556		}
36557
36558		// indices
36559
36560		for ( let i = 0; i < segments; i ++ ) {
36561
36562			for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
36563
36564				const base = j + i * points.length;
36565
36566				const a = base;
36567				const b = base + points.length;
36568				const c = base + points.length + 1;
36569				const d = base + 1;
36570
36571				// faces
36572
36573				indices.push( a, b, d );
36574				indices.push( c, d, b );
36575
36576			}
36577
36578		}
36579
36580		// build geometry
36581
36582		this.setIndex( indices );
36583		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36584		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36585		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36586
36587	}
36588
36589	copy( source ) {
36590
36591		super.copy( source );
36592
36593		this.parameters = Object.assign( {}, source.parameters );
36594
36595		return this;
36596
36597	}
36598
36599	static fromJSON( data ) {
36600
36601		return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength );
36602
36603	}
36604
36605}
36606
36607class CapsuleGeometry extends LatheGeometry {
36608
36609	constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) {
36610
36611		const path = new Path();
36612		path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );
36613		path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );
36614
36615		super( path.getPoints( capSegments ), radialSegments );
36616
36617		this.type = 'CapsuleGeometry';
36618
36619		this.parameters = {
36620			radius: radius,
36621			length: length,
36622			capSegments: capSegments,
36623			radialSegments: radialSegments,
36624		};
36625
36626	}
36627
36628	static fromJSON( data ) {
36629
36630		return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments );
36631
36632	}
36633
36634}
36635
36636class CircleGeometry extends BufferGeometry {
36637
36638	constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36639
36640		super();
36641
36642		this.type = 'CircleGeometry';
36643
36644		this.parameters = {
36645			radius: radius,
36646			segments: segments,
36647			thetaStart: thetaStart,
36648			thetaLength: thetaLength
36649		};
36650
36651		segments = Math.max( 3, segments );
36652
36653		// buffers
36654
36655		const indices = [];
36656		const vertices = [];
36657		const normals = [];
36658		const uvs = [];
36659
36660		// helper variables
36661
36662		const vertex = new Vector3();
36663		const uv = new Vector2();
36664
36665		// center point
36666
36667		vertices.push( 0, 0, 0 );
36668		normals.push( 0, 0, 1 );
36669		uvs.push( 0.5, 0.5 );
36670
36671		for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
36672
36673			const segment = thetaStart + s / segments * thetaLength;
36674
36675			// vertex
36676
36677			vertex.x = radius * Math.cos( segment );
36678			vertex.y = radius * Math.sin( segment );
36679
36680			vertices.push( vertex.x, vertex.y, vertex.z );
36681
36682			// normal
36683
36684			normals.push( 0, 0, 1 );
36685
36686			// uvs
36687
36688			uv.x = ( vertices[ i ] / radius + 1 ) / 2;
36689			uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
36690
36691			uvs.push( uv.x, uv.y );
36692
36693		}
36694
36695		// indices
36696
36697		for ( let i = 1; i <= segments; i ++ ) {
36698
36699			indices.push( i, i + 1, 0 );
36700
36701		}
36702
36703		// build geometry
36704
36705		this.setIndex( indices );
36706		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36707		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36708		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36709
36710	}
36711
36712	copy( source ) {
36713
36714		super.copy( source );
36715
36716		this.parameters = Object.assign( {}, source.parameters );
36717
36718		return this;
36719
36720	}
36721
36722	static fromJSON( data ) {
36723
36724		return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );
36725
36726	}
36727
36728}
36729
36730class CylinderGeometry extends BufferGeometry {
36731
36732	constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36733
36734		super();
36735
36736		this.type = 'CylinderGeometry';
36737
36738		this.parameters = {
36739			radiusTop: radiusTop,
vendor: 4,238 bytes, lines 36740-36932
36740			radiusBottom: radiusBottom,
36741			height: height,
36742			radialSegments: radialSegments,
36743			heightSegments: heightSegments,
36744			openEnded: openEnded,
36745			thetaStart: thetaStart,
36746			thetaLength: thetaLength
36747		};
36748
36749		const scope = this;
36750
36751		radialSegments = Math.floor( radialSegments );
36752		heightSegments = Math.floor( heightSegments );
36753
36754		// buffers
36755
36756		const indices = [];
36757		const vertices = [];
36758		const normals = [];
36759		const uvs = [];
36760
36761		// helper variables
36762
36763		let index = 0;
36764		const indexArray = [];
36765		const halfHeight = height / 2;
36766		let groupStart = 0;
36767
36768		// generate geometry
36769
36770		generateTorso();
36771
36772		if ( openEnded === false ) {
36773
36774			if ( radiusTop > 0 ) generateCap( true );
36775			if ( radiusBottom > 0 ) generateCap( false );
36776
36777		}
36778
36779		// build geometry
36780
36781		this.setIndex( indices );
36782		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36783		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36784		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36785
36786		function generateTorso() {
36787
36788			const normal = new Vector3();
36789			const vertex = new Vector3();
36790
36791			let groupCount = 0;
36792
36793			// this will be used to calculate the normal
36794			const slope = ( radiusBottom - radiusTop ) / height;
36795
36796			// generate vertices, normals and uvs
36797
36798			for ( let y = 0; y <= heightSegments; y ++ ) {
36799
36800				const indexRow = [];
36801
36802				const v = y / heightSegments;
36803
36804				// calculate the radius of the current row
36805
36806				const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
36807
36808				for ( let x = 0; x <= radialSegments; x ++ ) {
36809
36810					const u = x / radialSegments;
36811
36812					const theta = u * thetaLength + thetaStart;
36813
36814					const sinTheta = Math.sin( theta );
36815					const cosTheta = Math.cos( theta );
36816
36817					// vertex
36818
36819					vertex.x = radius * sinTheta;
36820					vertex.y = - v * height + halfHeight;
36821					vertex.z = radius * cosTheta;
36822					vertices.push( vertex.x, vertex.y, vertex.z );
36823
36824					// normal
36825
36826					normal.set( sinTheta, slope, cosTheta ).normalize();
36827					normals.push( normal.x, normal.y, normal.z );
36828
36829					// uv
36830
36831					uvs.push( u, 1 - v );
36832
36833					// save index of vertex in respective row
36834
36835					indexRow.push( index ++ );
36836
36837				}
36838
36839				// now save vertices of the row in our index array
36840
36841				indexArray.push( indexRow );
36842
36843			}
36844
36845			// generate indices
36846
36847			for ( let x = 0; x < radialSegments; x ++ ) {
36848
36849				for ( let y = 0; y < heightSegments; y ++ ) {
36850
36851					// we use the index array to access the correct indices
36852
36853					const a = indexArray[ y ][ x ];
36854					const b = indexArray[ y + 1 ][ x ];
36855					const c = indexArray[ y + 1 ][ x + 1 ];
36856					const d = indexArray[ y ][ x + 1 ];
36857
36858					// faces
36859
36860					indices.push( a, b, d );
36861					indices.push( b, c, d );
36862
36863					// update group counter
36864
36865					groupCount += 6;
36866
36867				}
36868
36869			}
36870
36871			// add a group to the geometry. this will ensure multi material support
36872
36873			scope.addGroup( groupStart, groupCount, 0 );
36874
36875			// calculate new start value for groups
36876
36877			groupStart += groupCount;
36878
36879		}
36880
36881		function generateCap( top ) {
36882
36883			// save the index of the first center vertex
36884			const centerIndexStart = index;
36885
36886			const uv = new Vector2();
36887			const vertex = new Vector3();
36888
36889			let groupCount = 0;
36890
36891			const radius = ( top === true ) ? radiusTop : radiusBottom;
36892			const sign = ( top === true ) ? 1 : - 1;
36893
36894			// first we generate the center vertex data of the cap.
36895			// because the geometry needs one set of uvs per face,
36896			// we must generate a center vertex per face/segment
36897
36898			for ( let x = 1; x <= radialSegments; x ++ ) {
36899
36900				// vertex
36901
36902				vertices.push( 0, halfHeight * sign, 0 );
36903
36904				// normal
36905
36906				normals.push( 0, sign, 0 );
36907
36908				// uv
36909
36910				uvs.push( 0.5, 0.5 );
36911
36912				// increase index
36913
36914				index ++;
36915
36916			}
36917
36918			// save the index of the last center vertex
36919			const centerIndexEnd = index;
36920
36921			// now we generate the surrounding vertices, normals and uvs
36922
36923			for ( let x = 0; x <= radialSegments; x ++ ) {
36924
36925				const u = x / radialSegments;
36926				const theta = u * thetaLength + thetaStart;
36927
36928				const cosTheta = Math.cos( theta );
36929				const sinTheta = Math.sin( theta );
36930
36931				// vertex
36932
vendor: 16,849 bytes, lines 36933-37712
36933				vertex.x = radius * sinTheta;
36934				vertex.y = halfHeight * sign;
36935				vertex.z = radius * cosTheta;
36936				vertices.push( vertex.x, vertex.y, vertex.z );
36937
36938				// normal
36939
36940				normals.push( 0, sign, 0 );
36941
36942				// uv
36943
36944				uv.x = ( cosTheta * 0.5 ) + 0.5;
36945				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
36946				uvs.push( uv.x, uv.y );
36947
36948				// increase index
36949
36950				index ++;
36951
36952			}
36953
36954			// generate indices
36955
36956			for ( let x = 0; x < radialSegments; x ++ ) {
36957
36958				const c = centerIndexStart + x;
36959				const i = centerIndexEnd + x;
36960
36961				if ( top === true ) {
36962
36963					// face top
36964
36965					indices.push( i, i + 1, c );
36966
36967				} else {
36968
36969					// face bottom
36970
36971					indices.push( i + 1, i, c );
36972
36973				}
36974
36975				groupCount += 3;
36976
36977			}
36978
36979			// add a group to the geometry. this will ensure multi material support
36980
36981			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
36982
36983			// calculate new start value for groups
36984
36985			groupStart += groupCount;
36986
36987		}
36988
36989	}
36990
36991	copy( source ) {
36992
36993		super.copy( source );
36994
36995		this.parameters = Object.assign( {}, source.parameters );
36996
36997		return this;
36998
36999	}
37000
37001	static fromJSON( data ) {
37002
37003		return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
37004
37005	}
37006
37007}
37008
37009class ConeGeometry extends CylinderGeometry {
37010
37011	constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
37012
37013		super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
37014
37015		this.type = 'ConeGeometry';
37016
37017		this.parameters = {
37018			radius: radius,
37019			height: height,
37020			radialSegments: radialSegments,
37021			heightSegments: heightSegments,
37022			openEnded: openEnded,
37023			thetaStart: thetaStart,
37024			thetaLength: thetaLength
37025		};
37026
37027	}
37028
37029	static fromJSON( data ) {
37030
37031		return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
37032
37033	}
37034
37035}
37036
37037class PolyhedronGeometry extends BufferGeometry {
37038
37039	constructor( vertices = [], indices = [], radius = 1, detail = 0 ) {
37040
37041		super();
37042
37043		this.type = 'PolyhedronGeometry';
37044
37045		this.parameters = {
37046			vertices: vertices,
37047			indices: indices,
37048			radius: radius,
37049			detail: detail
37050		};
37051
37052		// default buffer data
37053
37054		const vertexBuffer = [];
37055		const uvBuffer = [];
37056
37057		// the subdivision creates the vertex buffer data
37058
37059		subdivide( detail );
37060
37061		// all vertices should lie on a conceptual sphere with a given radius
37062
37063		applyRadius( radius );
37064
37065		// finally, create the uv data
37066
37067		generateUVs();
37068
37069		// build non-indexed geometry
37070
37071		this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
37072		this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
37073		this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
37074
37075		if ( detail === 0 ) {
37076
37077			this.computeVertexNormals(); // flat normals
37078
37079		} else {
37080
37081			this.normalizeNormals(); // smooth normals
37082
37083		}
37084
37085		// helper functions
37086
37087		function subdivide( detail ) {
37088
37089			const a = new Vector3();
37090			const b = new Vector3();
37091			const c = new Vector3();
37092
37093			// iterate over all faces and apply a subdivision with the given detail value
37094
37095			for ( let i = 0; i < indices.length; i += 3 ) {
37096
37097				// get the vertices of the face
37098
37099				getVertexByIndex( indices[ i + 0 ], a );
37100				getVertexByIndex( indices[ i + 1 ], b );
37101				getVertexByIndex( indices[ i + 2 ], c );
37102
37103				// perform subdivision
37104
37105				subdivideFace( a, b, c, detail );
37106
37107			}
37108
37109		}
37110
37111		function subdivideFace( a, b, c, detail ) {
37112
37113			const cols = detail + 1;
37114
37115			// we use this multidimensional array as a data structure for creating the subdivision
37116
37117			const v = [];
37118
37119			// construct all of the vertices for this subdivision
37120
37121			for ( let i = 0; i <= cols; i ++ ) {
37122
37123				v[ i ] = [];
37124
37125				const aj = a.clone().lerp( c, i / cols );
37126				const bj = b.clone().lerp( c, i / cols );
37127
37128				const rows = cols - i;
37129
37130				for ( let j = 0; j <= rows; j ++ ) {
37131
37132					if ( j === 0 && i === cols ) {
37133
37134						v[ i ][ j ] = aj;
37135
37136					} else {
37137
37138						v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
37139
37140					}
37141
37142				}
37143
37144			}
37145
37146			// construct all of the faces
37147
37148			for ( let i = 0; i < cols; i ++ ) {
37149
37150				for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
37151
37152					const k = Math.floor( j / 2 );
37153
37154					if ( j % 2 === 0 ) {
37155
37156						pushVertex( v[ i ][ k + 1 ] );
37157						pushVertex( v[ i + 1 ][ k ] );
37158						pushVertex( v[ i ][ k ] );
37159
37160					} else {
37161
37162						pushVertex( v[ i ][ k + 1 ] );
37163						pushVertex( v[ i + 1 ][ k + 1 ] );
37164						pushVertex( v[ i + 1 ][ k ] );
37165
37166					}
37167
37168				}
37169
37170			}
37171
37172		}
37173
37174		function applyRadius( radius ) {
37175
37176			const vertex = new Vector3();
37177
37178			// iterate over the entire buffer and apply the radius to each vertex
37179
37180			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37181
37182				vertex.x = vertexBuffer[ i + 0 ];
37183				vertex.y = vertexBuffer[ i + 1 ];
37184				vertex.z = vertexBuffer[ i + 2 ];
37185
37186				vertex.normalize().multiplyScalar( radius );
37187
37188				vertexBuffer[ i + 0 ] = vertex.x;
37189				vertexBuffer[ i + 1 ] = vertex.y;
37190				vertexBuffer[ i + 2 ] = vertex.z;
37191
37192			}
37193
37194		}
37195
37196		function generateUVs() {
37197
37198			const vertex = new Vector3();
37199
37200			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37201
37202				vertex.x = vertexBuffer[ i + 0 ];
37203				vertex.y = vertexBuffer[ i + 1 ];
37204				vertex.z = vertexBuffer[ i + 2 ];
37205
37206				const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
37207				const v = inclination( vertex ) / Math.PI + 0.5;
37208				uvBuffer.push( u, 1 - v );
37209
37210			}
37211
37212			correctUVs();
37213
37214			correctSeam();
37215
37216		}
37217
37218		function correctSeam() {
37219
37220			// handle case when face straddles the seam, see #3269
37221
37222			for ( let i = 0; i < uvBuffer.length; i += 6 ) {
37223
37224				// uv data of a single face
37225
37226				const x0 = uvBuffer[ i + 0 ];
37227				const x1 = uvBuffer[ i + 2 ];
37228				const x2 = uvBuffer[ i + 4 ];
37229
37230				const max = Math.max( x0, x1, x2 );
37231				const min = Math.min( x0, x1, x2 );
37232
37233				// 0.9 is somewhat arbitrary
37234
37235				if ( max > 0.9 && min < 0.1 ) {
37236
37237					if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
37238					if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
37239					if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
37240
37241				}
37242
37243			}
37244
37245		}
37246
37247		function pushVertex( vertex ) {
37248
37249			vertexBuffer.push( vertex.x, vertex.y, vertex.z );
37250
37251		}
37252
37253		function getVertexByIndex( index, vertex ) {
37254
37255			const stride = index * 3;
37256
37257			vertex.x = vertices[ stride + 0 ];
37258			vertex.y = vertices[ stride + 1 ];
37259			vertex.z = vertices[ stride + 2 ];
37260
37261		}
37262
37263		function correctUVs() {
37264
37265			const a = new Vector3();
37266			const b = new Vector3();
37267			const c = new Vector3();
37268
37269			const centroid = new Vector3();
37270
37271			const uvA = new Vector2();
37272			const uvB = new Vector2();
37273			const uvC = new Vector2();
37274
37275			for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
37276
37277				a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
37278				b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
37279				c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
37280
37281				uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
37282				uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
37283				uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
37284
37285				centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
37286
37287				const azi = azimuth( centroid );
37288
37289				correctUV( uvA, j + 0, a, azi );
37290				correctUV( uvB, j + 2, b, azi );
37291				correctUV( uvC, j + 4, c, azi );
37292
37293			}
37294
37295		}
37296
37297		function correctUV( uv, stride, vector, azimuth ) {
37298
37299			if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
37300
37301				uvBuffer[ stride ] = uv.x - 1;
37302
37303			}
37304
37305			if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
37306
37307				uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
37308
37309			}
37310
37311		}
37312
37313		// Angle around the Y axis, counter-clockwise when looking from above.
37314
37315		function azimuth( vector ) {
37316
37317			return Math.atan2( vector.z, - vector.x );
37318
37319		}
37320
37321
37322		// Angle above the XZ plane.
37323
37324		function inclination( vector ) {
37325
37326			return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
37327
37328		}
37329
37330	}
37331
37332	copy( source ) {
37333
37334		super.copy( source );
37335
37336		this.parameters = Object.assign( {}, source.parameters );
37337
37338		return this;
37339
37340	}
37341
37342	static fromJSON( data ) {
37343
37344		return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details );
37345
37346	}
37347
37348}
37349
37350class DodecahedronGeometry extends PolyhedronGeometry {
37351
37352	constructor( radius = 1, detail = 0 ) {
37353
37354		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
37355		const r = 1 / t;
37356
37357		const vertices = [
37358
37359			// (±1, ±1, ±1)
37360			- 1, - 1, - 1,	- 1, - 1, 1,
37361			- 1, 1, - 1, - 1, 1, 1,
37362			1, - 1, - 1, 1, - 1, 1,
37363			1, 1, - 1, 1, 1, 1,
37364
37365			// (0, ±1/φ, ±φ)
37366			0, - r, - t, 0, - r, t,
37367			0, r, - t, 0, r, t,
37368
37369			// (±1/φ, ±φ, 0)
37370			- r, - t, 0, - r, t, 0,
37371			r, - t, 0, r, t, 0,
37372
37373			// (±φ, 0, ±1/φ)
37374			- t, 0, - r, t, 0, - r,
37375			- t, 0, r, t, 0, r
37376		];
37377
37378		const indices = [
37379			3, 11, 7, 	3, 7, 15, 	3, 15, 13,
37380			7, 19, 17, 	7, 17, 6, 	7, 6, 15,
37381			17, 4, 8, 	17, 8, 10, 	17, 10, 6,
37382			8, 0, 16, 	8, 16, 2, 	8, 2, 10,
37383			0, 12, 1, 	0, 1, 18, 	0, 18, 16,
37384			6, 10, 2, 	6, 2, 13, 	6, 13, 15,
37385			2, 16, 18, 	2, 18, 3, 	2, 3, 13,
37386			18, 1, 9, 	18, 9, 11, 	18, 11, 3,
37387			4, 14, 12, 	4, 12, 0, 	4, 0, 8,
37388			11, 9, 5, 	11, 5, 19, 	11, 19, 7,
37389			19, 5, 14, 	19, 14, 4, 	19, 4, 17,
37390			1, 12, 14, 	1, 14, 5, 	1, 5, 9
37391		];
37392
37393		super( vertices, indices, radius, detail );
37394
37395		this.type = 'DodecahedronGeometry';
37396
37397		this.parameters = {
37398			radius: radius,
37399			detail: detail
37400		};
37401
37402	}
37403
37404	static fromJSON( data ) {
37405
37406		return new DodecahedronGeometry( data.radius, data.detail );
37407
37408	}
37409
37410}
37411
37412const _v0 = /*@__PURE__*/ new Vector3();
37413const _v1$1 = /*@__PURE__*/ new Vector3();
37414const _normal = /*@__PURE__*/ new Vector3();
37415const _triangle = /*@__PURE__*/ new Triangle();
37416
37417class EdgesGeometry extends BufferGeometry {
37418
37419	constructor( geometry = null, thresholdAngle = 1 ) {
37420
37421		super();
37422
37423		this.type = 'EdgesGeometry';
37424
37425		this.parameters = {
37426			geometry: geometry,
37427			thresholdAngle: thresholdAngle
37428		};
37429
37430		if ( geometry !== null ) {
37431
37432			const precisionPoints = 4;
37433			const precision = Math.pow( 10, precisionPoints );
37434			const thresholdDot = Math.cos( DEG2RAD * thresholdAngle );
37435
37436			const indexAttr = geometry.getIndex();
37437			const positionAttr = geometry.getAttribute( 'position' );
37438			const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
37439
37440			const indexArr = [ 0, 0, 0 ];
37441			const vertKeys = [ 'a', 'b', 'c' ];
37442			const hashes = new Array( 3 );
37443
37444			const edgeData = {};
37445			const vertices = [];
37446			for ( let i = 0; i < indexCount; i += 3 ) {
37447
37448				if ( indexAttr ) {
37449
37450					indexArr[ 0 ] = indexAttr.getX( i );
37451					indexArr[ 1 ] = indexAttr.getX( i + 1 );
37452					indexArr[ 2 ] = indexAttr.getX( i + 2 );
37453
37454				} else {
37455
37456					indexArr[ 0 ] = i;
37457					indexArr[ 1 ] = i + 1;
37458					indexArr[ 2 ] = i + 2;
37459
37460				}
37461
37462				const { a, b, c } = _triangle;
37463				a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
37464				b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
37465				c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
37466				_triangle.getNormal( _normal );
37467
37468				// create hashes for the edge from the vertices
37469				hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
37470				hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
37471				hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
37472
37473				// skip degenerate triangles
37474				if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
37475
37476					continue;
37477
37478				}
37479
37480				// iterate over every edge
37481				for ( let j = 0; j < 3; j ++ ) {
37482
37483					// get the first and next vertex making up the edge
37484					const jNext = ( j + 1 ) % 3;
37485					const vecHash0 = hashes[ j ];
37486					const vecHash1 = hashes[ jNext ];
37487					const v0 = _triangle[ vertKeys[ j ] ];
37488					const v1 = _triangle[ vertKeys[ jNext ] ];
37489
37490					const hash = `${ vecHash0 }_${ vecHash1 }`;
37491					const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
37492
37493					if ( reverseHash in edgeData && edgeData[ reverseHash ] ) {
37494
37495						// if we found a sibling edge add it into the vertex array if
37496						// it meets the angle threshold and delete the edge from the map.
37497						if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
37498
37499							vertices.push( v0.x, v0.y, v0.z );
37500							vertices.push( v1.x, v1.y, v1.z );
37501
37502						}
37503
37504						edgeData[ reverseHash ] = null;
37505
37506					} else if ( ! ( hash in edgeData ) ) {
37507
37508						// if we've already got an edge here then skip adding a new one
37509						edgeData[ hash ] = {
37510
37511							index0: indexArr[ j ],
37512							index1: indexArr[ jNext ],
37513							normal: _normal.clone(),
37514
37515						};
37516
37517					}
37518
37519				}
37520
37521			}
37522
37523			// iterate over all remaining, unmatched edges and add them to the vertex array
37524			for ( const key in edgeData ) {
37525
37526				if ( edgeData[ key ] ) {
37527
37528					const { index0, index1 } = edgeData[ key ];
37529					_v0.fromBufferAttribute( positionAttr, index0 );
37530					_v1$1.fromBufferAttribute( positionAttr, index1 );
37531
37532					vertices.push( _v0.x, _v0.y, _v0.z );
37533					vertices.push( _v1$1.x, _v1$1.y, _v1$1.z );
37534
37535				}
37536
37537			}
37538
37539			this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
37540
37541		}
37542
37543	}
37544
37545	copy( source ) {
37546
37547		super.copy( source );
37548
37549		this.parameters = Object.assign( {}, source.parameters );
37550
37551		return this;
37552
37553	}
37554
37555}
37556
37557class Shape extends Path {
37558
37559	constructor( points ) {
37560
37561		super( points );
37562
37563		this.uuid = generateUUID();
37564
37565		this.type = 'Shape';
37566
37567		this.holes = [];
37568
37569	}
37570
37571	getPointsHoles( divisions ) {
37572
37573		const holesPts = [];
37574
37575		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37576
37577			holesPts[ i ] = this.holes[ i ].getPoints( divisions );
37578
37579		}
37580
37581		return holesPts;
37582
37583	}
37584
37585	// get points of shape and holes (keypoints based on segments parameter)
37586
37587	extractPoints( divisions ) {
37588
37589		return {
37590
37591			shape: this.getPoints( divisions ),
37592			holes: this.getPointsHoles( divisions )
37593
37594		};
37595
37596	}
37597
37598	copy( source ) {
37599
37600		super.copy( source );
37601
37602		this.holes = [];
37603
37604		for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
37605
37606			const hole = source.holes[ i ];
37607
37608			this.holes.push( hole.clone() );
37609
37610		}
37611
37612		return this;
37613
37614	}
37615
37616	toJSON() {
37617
37618		const data = super.toJSON();
37619
37620		data.uuid = this.uuid;
37621		data.holes = [];
37622
37623		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37624
37625			const hole = this.holes[ i ];
37626			data.holes.push( hole.toJSON() );
37627
37628		}
37629
37630		return data;
37631
37632	}
37633
37634
37635	fromJSON( json ) {
37636
37637		super.fromJSON( json );
37638
37639		this.uuid = json.uuid;
37640		this.holes = [];
37641
37642		for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
37643
37644			const hole = json.holes[ i ];
37645			this.holes.push( new Path().fromJSON( hole ) );
37646
37647		}
37648
37649		return this;
37650
37651	}
37652
37653}
37654
37655/**
37656 * Port from https://github.com/mapbox/earcut (v2.2.4)
37657 */
37658
37659const Earcut = {
37660
37661	triangulate: function ( data, holeIndices, dim = 2 ) {
37662
37663		const hasHoles = holeIndices && holeIndices.length;
37664		const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
37665		let outerNode = linkedList( data, 0, outerLen, dim, true );
37666		const triangles = [];
37667
37668		if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
37669
37670		let minX, minY, maxX, maxY, x, y, invSize;
37671
37672		if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
37673
37674		// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
37675		if ( data.length > 80 * dim ) {
37676
37677			minX = maxX = data[ 0 ];
37678			minY = maxY = data[ 1 ];
37679
37680			for ( let i = dim; i < outerLen; i += dim ) {
37681
37682				x = data[ i ];
37683				y = data[ i + 1 ];
37684				if ( x < minX ) minX = x;
37685				if ( y < minY ) minY = y;
37686				if ( x > maxX ) maxX = x;
37687				if ( y > maxY ) maxY = y;
37688
37689			}
37690
37691			// minX, minY and invSize are later used to transform coords into integers for z-order calculation
37692			invSize = Math.max( maxX - minX, maxY - minY );
37693			invSize = invSize !== 0 ? 32767 / invSize : 0;
37694
37695		}
37696
37697		earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );
37698
37699		return triangles;
37700
37701	}
37702
37703};
37704
37705// create a circular doubly linked list from polygon points in the specified winding order
37706function linkedList( data, start, end, dim, clockwise ) {
37707
37708	let i, last;
37709
37710	if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
37711
37712		for ( i = start; i < end;
vendor: 13,306 bytes, lines 37712-38276
37712 i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37713
37714	} else {
37715
37716		for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37717
37718	}
37719
37720	if ( last && equals( last, last.next ) ) {
37721
37722		removeNode( last );
37723		last = last.next;
37724
37725	}
37726
37727	return last;
37728
37729}
37730
37731// eliminate colinear or duplicate points
37732function filterPoints( start, end ) {
37733
37734	if ( ! start ) return start;
37735	if ( ! end ) end = start;
37736
37737	let p = start,
37738		again;
37739	do {
37740
37741		again = false;
37742
37743		if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
37744
37745			removeNode( p );
37746			p = end = p.prev;
37747			if ( p === p.next ) break;
37748			again = true;
37749
37750		} else {
37751
37752			p = p.next;
37753
37754		}
37755
37756	} while ( again || p !== end );
37757
37758	return end;
37759
37760}
37761
37762// main ear slicing loop which triangulates a polygon (given as a linked list)
37763function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
37764
37765	if ( ! ear ) return;
37766
37767	// interlink polygon nodes in z-order
37768	if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
37769
37770	let stop = ear,
37771		prev, next;
37772
37773	// iterate through ears, slicing them one by one
37774	while ( ear.prev !== ear.next ) {
37775
37776		prev = ear.prev;
37777		next = ear.next;
37778
37779		if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
37780
37781			// cut off the triangle
37782			triangles.push( prev.i / dim | 0 );
37783			triangles.push( ear.i / dim | 0 );
37784			triangles.push( next.i / dim | 0 );
37785
37786			removeNode( ear );
37787
37788			// skipping the next vertex leads to less sliver triangles
37789			ear = next.next;
37790			stop = next.next;
37791
37792			continue;
37793
37794		}
37795
37796		ear = next;
37797
37798		// if we looped through the whole remaining polygon and can't find any more ears
37799		if ( ear === stop ) {
37800
37801			// try filtering points and slicing again
37802			if ( ! pass ) {
37803
37804				earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
37805
37806				// if this didn't work, try curing all small self-intersections locally
37807
37808			} else if ( pass === 1 ) {
37809
37810				ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
37811				earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
37812
37813				// as a last resort, try splitting the remaining polygon into two
37814
37815			} else if ( pass === 2 ) {
37816
37817				splitEarcut( ear, triangles, dim, minX, minY, invSize );
37818
37819			}
37820
37821			break;
37822
37823		}
37824
37825	}
37826
37827}
37828
37829// check whether a polygon node forms a valid ear with adjacent nodes
37830function isEar( ear ) {
37831
37832	const a = ear.prev,
37833		b = ear,
37834		c = ear.next;
37835
37836	if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37837
37838	// now make sure we don't have other points inside the potential ear
37839	const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37840
37841	// triangle bbox; min & max are calculated like this for speed
37842	const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37843		y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37844		x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37845		y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37846
37847	let p = c.next;
37848	while ( p !== a ) {
37849
37850		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
37851			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
37852			area( p.prev, p, p.next ) >= 0 ) return false;
37853		p = p.next;
37854
37855	}
37856
37857	return true;
37858
37859}
37860
37861function isEarHashed( ear, minX, minY, invSize ) {
37862
37863	const a = ear.prev,
37864		b = ear,
37865		c = ear.next;
37866
37867	if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37868
37869	const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37870
37871	// triangle bbox; min & max are calculated like this for speed
37872	const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37873		y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37874		x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37875		y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37876
37877	// z-order range for the current triangle bbox;
37878	const minZ = zOrder( x0, y0, minX, minY, invSize ),
37879		maxZ = zOrder( x1, y1, minX, minY, invSize );
37880
37881	let p = ear.prevZ,
37882		n = ear.nextZ;
37883
37884	// look for points inside the triangle in both directions
37885	while ( p && p.z >= minZ && n && n.z <= maxZ ) {
37886
37887		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37888			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37889		p = p.prevZ;
37890
37891		if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37892			pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37893		n = n.nextZ;
37894
37895	}
37896
37897	// look for remaining points in decreasing z-order
37898	while ( p && p.z >= minZ ) {
37899
37900		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37901			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37902		p = p.prevZ;
37903
37904	}
37905
37906	// look for remaining points in increasing z-order
37907	while ( n && n.z <= maxZ ) {
37908
37909		if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37910			pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37911		n = n.nextZ;
37912
37913	}
37914
37915	return true;
37916
37917}
37918
37919// go through all polygon nodes and cure small local self-intersections
37920function cureLocalIntersections( start, triangles, dim ) {
37921
37922	let p = start;
37923	do {
37924
37925		const a = p.prev,
37926			b = p.next.next;
37927
37928		if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
37929
37930			triangles.push( a.i / dim | 0 );
37931			triangles.push( p.i / dim | 0 );
37932			triangles.push( b.i / dim | 0 );
37933
37934			// remove two nodes involved
37935			removeNode( p );
37936			removeNode( p.next );
37937
37938			p = start = b;
37939
37940		}
37941
37942		p = p.next;
37943
37944	} while ( p !== start );
37945
37946	return filterPoints( p );
37947
37948}
37949
37950// try splitting polygon into two and triangulate them independently
37951function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
37952
37953	// look for a valid diagonal that divides the polygon into two
37954	let a = start;
37955	do {
37956
37957		let b = a.next.next;
37958		while ( b !== a.prev ) {
37959
37960			if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
37961
37962				// split the polygon in two by the diagonal
37963				let c = splitPolygon( a, b );
37964
37965				// filter colinear points around the cuts
37966				a = filterPoints( a, a.next );
37967				c = filterPoints( c, c.next );
37968
37969				// run earcut on each half
37970				earcutLinked( a, triangles, dim, minX, minY, invSize, 0 );
37971				earcutLinked( c, triangles, dim, minX, minY, invSize, 0 );
37972				return;
37973
37974			}
37975
37976			b = b.next;
37977
37978		}
37979
37980		a = a.next;
37981
37982	} while ( a !== start );
37983
37984}
37985
37986// link every hole into the outer loop, producing a single-ring polygon without holes
37987function eliminateHoles( data, holeIndices, outerNode, dim ) {
37988
37989	const queue = [];
37990	let i, len, start, end, list;
37991
37992	for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
37993
37994		start = holeIndices[ i ] * dim;
37995		end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
37996		list = linkedList( data, start, end, dim, false );
37997		if ( list === list.next ) list.steiner = true;
37998		queue.push( getLeftmost( list ) );
37999
38000	}
38001
38002	queue.sort( compareX );
38003
38004	// process holes from left to right
38005	for ( i = 0; i < queue.length; i ++ ) {
38006
38007		outerNode = eliminateHole( queue[ i ], outerNode );
38008
38009	}
38010
38011	return outerNode;
38012
38013}
38014
38015function compareX( a, b ) {
38016
38017	return a.x - b.x;
38018
38019}
38020
38021// find a bridge between vertices that connects hole with an outer ring and link it
38022function eliminateHole( hole, outerNode ) {
38023
38024	const bridge = findHoleBridge( hole, outerNode );
38025	if ( ! bridge ) {
38026
38027		return outerNode;
38028
38029	}
38030
38031	const bridgeReverse = splitPolygon( bridge, hole );
38032
38033	// filter collinear points around the cuts
38034	filterPoints( bridgeReverse, bridgeReverse.next );
38035	return filterPoints( bridge, bridge.next );
38036
38037}
38038
38039// David Eberly's algorithm for finding a bridge between hole and outer polygon
38040function findHoleBridge( hole, outerNode ) {
38041
38042	let p = outerNode,
38043		qx = - Infinity,
38044		m;
38045
38046	const hx = hole.x, hy = hole.y;
38047
38048	// find a segment intersected by a ray from the hole's leftmost point to the left;
38049	// segment's endpoint with lesser x will be potential connection point
38050	do {
38051
38052		if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
38053
38054			const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
38055			if ( x <= hx && x > qx ) {
38056
38057				qx = x;
38058				m = p.x < p.next.x ? p : p.next;
38059				if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint
38060
38061			}
38062
38063		}
38064
38065		p = p.next;
38066
38067	} while ( p !== outerNode );
38068
38069	if ( ! m ) return null;
38070
38071	// look for points inside the triangle of hole point, segment intersection and endpoint;
38072	// if there are no points found, we have a valid connection;
38073	// otherwise choose the point of the minimum angle with the ray as connection point
38074
38075	const stop = m,
38076		mx = m.x,
38077		my = m.y;
38078	let tanMin = Infinity, tan;
38079
38080	p = m;
38081
38082	do {
38083
38084		if ( hx >= p.x && p.x >= mx && hx !== p.x &&
38085				pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
38086
38087			tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
38088
38089			if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
38090
38091				m = p;
38092				tanMin = tan;
38093
38094			}
38095
38096		}
38097
38098		p = p.next;
38099
38100	} while ( p !== stop );
38101
38102	return m;
38103
38104}
38105
38106// whether sector in vertex m contains sector in vertex p in the same coordinates
38107function sectorContainsSector( m, p ) {
38108
38109	return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
38110
38111}
38112
38113// interlink polygon nodes in z-order
38114function indexCurve( start, minX, minY, invSize ) {
38115
38116	let p = start;
38117	do {
38118
38119		if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
38120		p.prevZ = p.prev;
38121		p.nextZ = p.next;
38122		p = p.next;
38123
38124	} while ( p !== start );
38125
38126	p.prevZ.nextZ = null;
38127	p.prevZ = null;
38128
38129	sortLinked( p );
38130
38131}
38132
38133// Simon Tatham's linked list merge sort algorithm
38134// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
38135function sortLinked( list ) {
38136
38137	let i, p, q, e, tail, numMerges, pSize, qSize,
38138		inSize = 1;
38139
38140	do {
38141
38142		p = list;
38143		list = null;
38144		tail = null;
38145		numMerges = 0;
38146
38147		while ( p ) {
38148
38149			numMerges ++;
38150			q = p;
38151			pSize = 0;
38152			for ( i = 0; i < inSize; i ++ ) {
38153
38154				pSize ++;
38155				q = q.nextZ;
38156				if ( ! q ) break;
38157
38158			}
38159
38160			qSize = inSize;
38161
38162			while ( pSize > 0 || ( qSize > 0 && q ) ) {
38163
38164				if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
38165
38166					e = p;
38167					p = p.nextZ;
38168					pSize --;
38169
38170				} else {
38171
38172					e = q;
38173					q = q.nextZ;
38174					qSize --;
38175
38176				}
38177
38178				if ( tail ) tail.nextZ = e;
38179				else list = e;
38180
38181				e.prevZ = tail;
38182				tail = e;
38183
38184			}
38185
38186			p = q;
38187
38188		}
38189
38190		tail.nextZ = null;
38191		inSize *= 2;
38192
38193	} while ( numMerges > 1 );
38194
38195	return list;
38196
38197}
38198
38199// z-order of a point given coords and inverse of the longer side of data bbox
38200function zOrder( x, y, minX, minY, invSize ) {
38201
38202	// coords are transformed into non-negative 15-bit integer range
38203	x = ( x - minX ) * invSize | 0;
38204	y = ( y - minY ) * invSize | 0;
38205
38206	x = ( x | ( x << 8 ) ) & 0x00FF00FF;
38207	x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
38208	x = ( x | ( x << 2 ) ) & 0x33333333;
38209	x = ( x | ( x << 1 ) ) & 0x55555555;
38210
38211	y = ( y | ( y << 8 ) ) & 0x00FF00FF;
38212	y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
38213	y = ( y | ( y << 2 ) ) & 0x33333333;
38214	y = ( y | ( y << 1 ) ) & 0x55555555;
38215
38216	return x | ( y << 1 );
38217
38218}
38219
38220// find the leftmost node of a polygon ring
38221function getLeftmost( start ) {
38222
38223	let p = start,
38224		leftmost = start;
38225	do {
38226
38227		if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
38228		p = p.next;
38229
38230	} while ( p !== start );
38231
38232	return leftmost;
38233
38234}
38235
38236// check if a point lies within a convex triangle
38237function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
38238
38239	return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&
38240           ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&
38241           ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );
38242
38243}
38244
38245// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
38246function isValidDiagonal( a, b ) {
38247
38248	return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
38249           ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
38250            ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
38251            equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
38252
38253}
38254
38255// signed area of a triangle
38256function area( p, q, r ) {
38257
38258	return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
38259
38260}
38261
38262// check if two points are equal
38263function equals( p1, p2 ) {
38264
38265	return p1.x === p2.x && p1.y === p2.y;
38266
38267}
38268
38269// check if two segments intersect
38270function intersects( p1, q1, p2, q2 ) {
38271
38272	const o1 = sign( area( p1, q1, p2 ) );
38273	const o2 = sign( area( p1, q1, q2 ) );
38274	const o3 = sign( area( p2, q2, p1 ) );
38275	const o4 = sign( area( p2, q2, q1 ) );
38276
vendor: 7,786 bytes, lines 38277-38617
38277	if ( o1 !== o2 && o3 !== o4 ) return true; // general case
38278
38279	if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
38280	if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
38281	if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
38282	if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
38283
38284	return false;
38285
38286}
38287
38288// for collinear points p, q, r, check if point q lies on segment pr
38289function onSegment( p, q, r ) {
38290
38291	return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
38292
38293}
38294
38295function sign( num ) {
38296
38297	return num > 0 ? 1 : num < 0 ? - 1 : 0;
38298
38299}
38300
38301// check if a polygon diagonal intersects any polygon segments
38302function intersectsPolygon( a, b ) {
38303
38304	let p = a;
38305	do {
38306
38307		if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
38308			intersects( p, p.next, a, b ) ) return true;
38309		p = p.next;
38310
38311	} while ( p !== a );
38312
38313	return false;
38314
38315}
38316
38317// check if a polygon diagonal is locally inside the polygon
38318function locallyInside( a, b ) {
38319
38320	return area( a.prev, a, a.next ) < 0 ?
38321		area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
38322		area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
38323
38324}
38325
38326// check if the middle point of a polygon diagonal is inside the polygon
38327function middleInside( a, b ) {
38328
38329	let p = a,
38330		inside = false;
38331	const px = ( a.x + b.x ) / 2,
38332		py = ( a.y + b.y ) / 2;
38333	do {
38334
38335		if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
38336			( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
38337			inside = ! inside;
38338		p = p.next;
38339
38340	} while ( p !== a );
38341
38342	return inside;
38343
38344}
38345
38346// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
38347// if one belongs to the outer ring and another to a hole, it merges it into a single ring
38348function splitPolygon( a, b ) {
38349
38350	const a2 = new Node( a.i, a.x, a.y ),
38351		b2 = new Node( b.i, b.x, b.y ),
38352		an = a.next,
38353		bp = b.prev;
38354
38355	a.next = b;
38356	b.prev = a;
38357
38358	a2.next = an;
38359	an.prev = a2;
38360
38361	b2.next = a2;
38362	a2.prev = b2;
38363
38364	bp.next = b2;
38365	b2.prev = bp;
38366
38367	return b2;
38368
38369}
38370
38371// create a node and optionally link it with previous one (in a circular doubly linked list)
38372function insertNode( i, x, y, last ) {
38373
38374	const p = new Node( i, x, y );
38375
38376	if ( ! last ) {
38377
38378		p.prev = p;
38379		p.next = p;
38380
38381	} else {
38382
38383		p.next = last.next;
38384		p.prev = last;
38385		last.next.prev = p;
38386		last.next = p;
38387
38388	}
38389
38390	return p;
38391
38392}
38393
38394function removeNode( p ) {
38395
38396	p.next.prev = p.prev;
38397	p.prev.next = p.next;
38398
38399	if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
38400	if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
38401
38402}
38403
38404function Node( i, x, y ) {
38405
38406	// vertex index in coordinates array
38407	this.i = i;
38408
38409	// vertex coordinates
38410	this.x = x;
38411	this.y = y;
38412
38413	// previous and next vertex nodes in a polygon ring
38414	this.prev = null;
38415	this.next = null;
38416
38417	// z-order curve value
38418	this.z = 0;
38419
38420	// previous and next nodes in z-order
38421	this.prevZ = null;
38422	this.nextZ = null;
38423
38424	// indicates whether this is a steiner point
38425	this.steiner = false;
38426
38427}
38428
38429function signedArea( data, start, end, dim ) {
38430
38431	let sum = 0;
38432	for ( let i = start, j = end - dim; i < end; i += dim ) {
38433
38434		sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
38435		j = i;
38436
38437	}
38438
38439	return sum;
38440
38441}
38442
38443class ShapeUtils {
38444
38445	// calculate area of the contour polygon
38446
38447	static area( contour ) {
38448
38449		const n = contour.length;
38450		let a = 0.0;
38451
38452		for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
38453
38454			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
38455
38456		}
38457
38458		return a * 0.5;
38459
38460	}
38461
38462	static isClockWise( pts ) {
38463
38464		return ShapeUtils.area( pts ) < 0;
38465
38466	}
38467
38468	static triangulateShape( contour, holes ) {
38469
38470		const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
38471		const holeIndices = []; // array of hole indices
38472		const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
38473
38474		removeDupEndPts( contour );
38475		addContour( vertices, contour );
38476
38477		//
38478
38479		let holeIndex = contour.length;
38480
38481		holes.forEach( removeDupEndPts );
38482
38483		for ( let i = 0; i < holes.length; i ++ ) {
38484
38485			holeIndices.push( holeIndex );
38486			holeIndex += holes[ i ].length;
38487			addContour( vertices, holes[ i ] );
38488
38489		}
38490
38491		//
38492
38493		const triangles = Earcut.triangulate( vertices, holeIndices );
38494
38495		//
38496
38497		for ( let i = 0; i < triangles.length; i += 3 ) {
38498
38499			faces.push( triangles.slice( i, i + 3 ) );
38500
38501		}
38502
38503		return faces;
38504
38505	}
38506
38507}
38508
38509function removeDupEndPts( points ) {
38510
38511	const l = points.length;
38512
38513	if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
38514
38515		points.pop();
38516
38517	}
38518
38519}
38520
38521function addContour( vertices, contour ) {
38522
38523	for ( let i = 0; i < contour.length; i ++ ) {
38524
38525		vertices.push( contour[ i ].x );
38526		vertices.push( contour[ i ].y );
38527
38528	}
38529
38530}
38531
38532/**
38533 * Creates extruded geometry from a path shape.
38534 *
38535 * parameters = {
38536 *
38537 *  curveSegments: <int>, // number of points on the curves
38538 *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
38539 *  depth: <float>, // Depth to extrude the shape
38540 *
38541 *  bevelEnabled: <bool>, // turn on bevel
38542 *  bevelThickness: <float>, // how deep into the original shape bevel goes
38543 *  bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
38544 *  bevelOffset: <float>, // how far from shape outline does bevel start
38545 *  bevelSegments: <int>, // number of bevel layers
38546 *
38547 *  extrudePath: <THREE.Curve> // curve to extrude shape along
38548 *
38549 *  UVGenerator: <Object> // object that provides UV generator functions
38550 *
38551 * }
38552 */
38553
38554
38555class ExtrudeGeometry extends BufferGeometry {
38556
38557	constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) {
38558
38559		super();
38560
38561		this.type = 'ExtrudeGeometry';
38562
38563		this.parameters = {
38564			shapes: shapes,
38565			options: options
38566		};
38567
38568		shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
38569
38570		const scope = this;
38571
38572		const verticesArray = [];
38573		const uvArray = [];
38574
38575		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
38576
38577			const shape = shapes[ i ];
38578			addShape( shape );
38579
38580		}
38581
38582		// build geometry
38583
38584		this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
38585		this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
38586
38587		this.computeVertexNormals();
38588
38589		// functions
38590
38591		function addShape( shape ) {
38592
38593			const placeholder = [];
38594
38595			// options
38596
38597			const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
38598			const steps = options.steps !== undefined ? options.steps : 1;
38599			const depth = options.depth !== undefined ? options.depth : 1;
38600
38601			let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
38602			let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;
38603			let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;
38604			let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
38605			let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
38606
38607			const extrudePath = options.extrudePath;
38608
38609			const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
38610
38611			//
38612
38613			let extrudePts, extrudeByPath = false;
38614			let splineTube, binormal, normal, position2;
38615
38616			if ( extrudePath ) {
38617
vendor: 2,827 bytes, lines 38618-38727
38618				extrudePts = extrudePath.getSpacedPoints( steps );
38619
38620				extrudeByPath = true;
38621				bevelEnabled = false; // bevels not supported for path extrusion
38622
38623				// SETUP TNB variables
38624
38625				// TODO1 - have a .isClosed in spline?
38626
38627				splineTube = extrudePath.computeFrenetFrames( steps, false );
38628
38629				// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
38630
38631				binormal = new Vector3();
38632				normal = new Vector3();
38633				position2 = new Vector3();
38634
38635			}
38636
38637			// Safeguards if bevels are not enabled
38638
38639			if ( ! bevelEnabled ) {
38640
38641				bevelSegments = 0;
38642				bevelThickness = 0;
38643				bevelSize = 0;
38644				bevelOffset = 0;
38645
38646			}
38647
38648			// Variables initialization
38649
38650			const shapePoints = shape.extractPoints( curveSegments );
38651
38652			let vertices = shapePoints.shape;
38653			const holes = shapePoints.holes;
38654
38655			const reverse = ! ShapeUtils.isClockWise( vertices );
38656
38657			if ( reverse ) {
38658
38659				vertices = vertices.reverse();
38660
38661				// Maybe we should also check if holes are in the opposite direction, just to be safe ...
38662
38663				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38664
38665					const ahole = holes[ h ];
38666
38667					if ( ShapeUtils.isClockWise( ahole ) ) {
38668
38669						holes[ h ] = ahole.reverse();
38670
38671					}
38672
38673				}
38674
38675			}
38676
38677
38678			const faces = ShapeUtils.triangulateShape( vertices, holes );
38679
38680			/* Vertices */
38681
38682			const contour = vertices; // vertices has all points but contour has only points of circumference
38683
38684			for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38685
38686				const ahole = holes[ h ];
38687
38688				vertices = vertices.concat( ahole );
38689
38690			}
38691
38692
38693			function scalePt2( pt, vec, size ) {
38694
38695				if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
38696
38697				return pt.clone().addScaledVector( vec, size );
38698
38699			}
38700
38701			const vlen = vertices.length, flen = faces.length;
38702
38703
38704			// Find directions for point movement
38705
38706
38707			function getBevelVec( inPt, inPrev, inNext ) {
38708
38709				// computes for inPt the corresponding point inPt' on a new contour
38710				//   shifted by 1 unit (length of normalized vector) to the left
38711				// if we walk along contour clockwise, this new contour is outside the old one
38712				//
38713				// inPt' is the intersection of the two lines parallel to the two
38714				//  adjacent edges of inPt at a distance of 1 unit on the left side.
38715
38716				let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
38717
38718				// good reading for geometry algorithms (here: line-line intersection)
38719				// http://geomalgorithms.com/a05-_intersect-1.html
38720
38721				const v_prev_x = inPt.x - inPrev.x,
38722					v_prev_y = inPt.y - inPrev.y;
38723				const v_next_x = inNext.x - inPt.x,
38724					v_next_y = inNext.y - inPt.y;
38725
38726				const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
38727
vendor: 18,304 bytes, lines 38728-39579
38728				// check for collinear edges
38729				const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
38730
38731				if ( Math.abs( collinear0 ) > Number.EPSILON ) {
38732
38733					// not collinear
38734
38735					// length of vectors for normalizing
38736
38737					const v_prev_len = Math.sqrt( v_prev_lensq );
38738					const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
38739
38740					// shift adjacent points by unit vectors to the left
38741
38742					const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
38743					const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
38744
38745					const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
38746					const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
38747
38748					// scaling factor for v_prev to intersection point
38749
38750					const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
38751							( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
38752						( v_prev_x * v_next_y - v_prev_y * v_next_x );
38753
38754					// vector from inPt to intersection point
38755
38756					v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
38757					v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
38758
38759					// Don't normalize!, otherwise sharp corners become ugly
38760					//  but prevent crazy spikes
38761					const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
38762					if ( v_trans_lensq <= 2 ) {
38763
38764						return new Vector2( v_trans_x, v_trans_y );
38765
38766					} else {
38767
38768						shrink_by = Math.sqrt( v_trans_lensq / 2 );
38769
38770					}
38771
38772				} else {
38773
38774					// handle special case of collinear edges
38775
38776					let direction_eq = false; // assumes: opposite
38777
38778					if ( v_prev_x > Number.EPSILON ) {
38779
38780						if ( v_next_x > Number.EPSILON ) {
38781
38782							direction_eq = true;
38783
38784						}
38785
38786					} else {
38787
38788						if ( v_prev_x < - Number.EPSILON ) {
38789
38790							if ( v_next_x < - Number.EPSILON ) {
38791
38792								direction_eq = true;
38793
38794							}
38795
38796						} else {
38797
38798							if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
38799
38800								direction_eq = true;
38801
38802							}
38803
38804						}
38805
38806					}
38807
38808					if ( direction_eq ) {
38809
38810						// console.log("Warning: lines are a straight sequence");
38811						v_trans_x = - v_prev_y;
38812						v_trans_y = v_prev_x;
38813						shrink_by = Math.sqrt( v_prev_lensq );
38814
38815					} else {
38816
38817						// console.log("Warning: lines are a straight spike");
38818						v_trans_x = v_prev_x;
38819						v_trans_y = v_prev_y;
38820						shrink_by = Math.sqrt( v_prev_lensq / 2 );
38821
38822					}
38823
38824				}
38825
38826				return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
38827
38828			}
38829
38830
38831			const contourMovements = [];
38832
38833			for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38834
38835				if ( j === il ) j = 0;
38836				if ( k === il ) k = 0;
38837
38838				//  (j)---(i)---(k)
38839				// console.log('i,j,k', i, j , k)
38840
38841				contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
38842
38843			}
38844
38845			const holesMovements = [];
38846			let oneHoleMovements, verticesMovements = contourMovements.concat();
38847
38848			for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38849
38850				const ahole = holes[ h ];
38851
38852				oneHoleMovements = [];
38853
38854				for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38855
38856					if ( j === il ) j = 0;
38857					if ( k === il ) k = 0;
38858
38859					//  (j)---(i)---(k)
38860					oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
38861
38862				}
38863
38864				holesMovements.push( oneHoleMovements );
38865				verticesMovements = verticesMovements.concat( oneHoleMovements );
38866
38867			}
38868
38869
38870			// Loop bevelSegments, 1 for the front, 1 for the back
38871
38872			for ( let b = 0; b < bevelSegments; b ++ ) {
38873
38874				//for ( b = bevelSegments; b > 0; b -- ) {
38875
38876				const t = b / bevelSegments;
38877				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38878				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38879
38880				// contract shape
38881
38882				for ( let i = 0, il = contour.length; i < il; i ++ ) {
38883
38884					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38885
38886					v( vert.x, vert.y, - z );
38887
38888				}
38889
38890				// expand holes
38891
38892				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38893
38894					const ahole = holes[ h ];
38895					oneHoleMovements = holesMovements[ h ];
38896
38897					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38898
38899						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38900
38901						v( vert.x, vert.y, - z );
38902
38903					}
38904
38905				}
38906
38907			}
38908
38909			const bs = bevelSize + bevelOffset;
38910
38911			// Back facing vertices
38912
38913			for ( let i = 0; i < vlen; i ++ ) {
38914
38915				const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38916
38917				if ( ! extrudeByPath ) {
38918
38919					v( vert.x, vert.y, 0 );
38920
38921				} else {
38922
38923					// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
38924
38925					normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
38926					binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
38927
38928					position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
38929
38930					v( position2.x, position2.y, position2.z );
38931
38932				}
38933
38934			}
38935
38936			// Add stepped vertices...
38937			// Including front facing vertices
38938
38939			for ( let s = 1; s <= steps; s ++ ) {
38940
38941				for ( let i = 0; i < vlen; i ++ ) {
38942
38943					const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38944
38945					if ( ! extrudeByPath ) {
38946
38947						v( vert.x, vert.y, depth / steps * s );
38948
38949					} else {
38950
38951						// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
38952
38953						normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
38954						binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
38955
38956						position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
38957
38958						v( position2.x, position2.y, position2.z );
38959
38960					}
38961
38962				}
38963
38964			}
38965
38966
38967			// Add bevel segments planes
38968
38969			//for ( b = 1; b <= bevelSegments; b ++ ) {
38970			for ( let b = bevelSegments - 1; b >= 0; b -- ) {
38971
38972				const t = b / bevelSegments;
38973				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38974				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38975
38976				// contract shape
38977
38978				for ( let i = 0, il = contour.length; i < il; i ++ ) {
38979
38980					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38981					v( vert.x, vert.y, depth + z );
38982
38983				}
38984
38985				// expand holes
38986
38987				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38988
38989					const ahole = holes[ h ];
38990					oneHoleMovements = holesMovements[ h ];
38991
38992					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38993
38994						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38995
38996						if ( ! extrudeByPath ) {
38997
38998							v( vert.x, vert.y, depth + z );
38999
39000						} else {
39001
39002							v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
39003
39004						}
39005
39006					}
39007
39008				}
39009
39010			}
39011
39012			/* Faces */
39013
39014			// Top and bottom faces
39015
39016			buildLidFaces();
39017
39018			// Sides faces
39019
39020			buildSideFaces();
39021
39022
39023			/////  Internal functions
39024
39025			function buildLidFaces() {
39026
39027				const start = verticesArray.length / 3;
39028
39029				if ( bevelEnabled ) {
39030
39031					let layer = 0; // steps + 1
39032					let offset = vlen * layer;
39033
39034					// Bottom faces
39035
39036					for ( let i = 0; i < flen; i ++ ) {
39037
39038						const face = faces[ i ];
39039						f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
39040
39041					}
39042
39043					layer = steps + bevelSegments * 2;
39044					offset = vlen * layer;
39045
39046					// Top faces
39047
39048					for ( let i = 0; i < flen; i ++ ) {
39049
39050						const face = faces[ i ];
39051						f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
39052
39053					}
39054
39055				} else {
39056
39057					// Bottom faces
39058
39059					for ( let i = 0; i < flen; i ++ ) {
39060
39061						const face = faces[ i ];
39062						f3( face[ 2 ], face[ 1 ], face[ 0 ] );
39063
39064					}
39065
39066					// Top faces
39067
39068					for ( let i = 0; i < flen; i ++ ) {
39069
39070						const face = faces[ i ];
39071						f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
39072
39073					}
39074
39075				}
39076
39077				scope.addGroup( start, verticesArray.length / 3 - start, 0 );
39078
39079			}
39080
39081			// Create faces for the z-sides of the shape
39082
39083			function buildSideFaces() {
39084
39085				const start = verticesArray.length / 3;
39086				let layeroffset = 0;
39087				sidewalls( contour, layeroffset );
39088				layeroffset += contour.length;
39089
39090				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
39091
39092					const ahole = holes[ h ];
39093					sidewalls( ahole, layeroffset );
39094
39095					//, true
39096					layeroffset += ahole.length;
39097
39098				}
39099
39100
39101				scope.addGroup( start, verticesArray.length / 3 - start, 1 );
39102
39103
39104			}
39105
39106			function sidewalls( contour, layeroffset ) {
39107
39108				let i = contour.length;
39109
39110				while ( -- i >= 0 ) {
39111
39112					const j = i;
39113					let k = i - 1;
39114					if ( k < 0 ) k = contour.length - 1;
39115
39116					//console.log('b', i,j, i-1, k,vertices.length);
39117
39118					for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
39119
39120						const slen1 = vlen * s;
39121						const slen2 = vlen * ( s + 1 );
39122
39123						const a = layeroffset + j + slen1,
39124							b = layeroffset + k + slen1,
39125							c = layeroffset + k + slen2,
39126							d = layeroffset + j + slen2;
39127
39128						f4( a, b, c, d );
39129
39130					}
39131
39132				}
39133
39134			}
39135
39136			function v( x, y, z ) {
39137
39138				placeholder.push( x );
39139				placeholder.push( y );
39140				placeholder.push( z );
39141
39142			}
39143
39144
39145			function f3( a, b, c ) {
39146
39147				addVertex( a );
39148				addVertex( b );
39149				addVertex( c );
39150
39151				const nextIndex = verticesArray.length / 3;
39152				const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39153
39154				addUV( uvs[ 0 ] );
39155				addUV( uvs[ 1 ] );
39156				addUV( uvs[ 2 ] );
39157
39158			}
39159
39160			function f4( a, b, c, d ) {
39161
39162				addVertex( a );
39163				addVertex( b );
39164				addVertex( d );
39165
39166				addVertex( b );
39167				addVertex( c );
39168				addVertex( d );
39169
39170
39171				const nextIndex = verticesArray.length / 3;
39172				const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39173
39174				addUV( uvs[ 0 ] );
39175				addUV( uvs[ 1 ] );
39176				addUV( uvs[ 3 ] );
39177
39178				addUV( uvs[ 1 ] );
39179				addUV( uvs[ 2 ] );
39180				addUV( uvs[ 3 ] );
39181
39182			}
39183
39184			function addVertex( index ) {
39185
39186				verticesArray.push( placeholder[ index * 3 + 0 ] );
39187				verticesArray.push( placeholder[ index * 3 + 1 ] );
39188				verticesArray.push( placeholder[ index * 3 + 2 ] );
39189
39190			}
39191
39192
39193			function addUV( vector2 ) {
39194
39195				uvArray.push( vector2.x );
39196				uvArray.push( vector2.y );
39197
39198			}
39199
39200		}
39201
39202	}
39203
39204	copy( source ) {
39205
39206		super.copy( source );
39207
39208		this.parameters = Object.assign( {}, source.parameters );
39209
39210		return this;
39211
39212	}
39213
39214	toJSON() {
39215
39216		const data = super.toJSON();
39217
39218		const shapes = this.parameters.shapes;
39219		const options = this.parameters.options;
39220
39221		return toJSON$1( shapes, options, data );
39222
39223	}
39224
39225	static fromJSON( data, shapes ) {
39226
39227		const geometryShapes = [];
39228
39229		for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39230
39231			const shape = shapes[ data.shapes[ j ] ];
39232
39233			geometryShapes.push( shape );
39234
39235		}
39236
39237		const extrudePath = data.options.extrudePath;
39238
39239		if ( extrudePath !== undefined ) {
39240
39241			data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
39242
39243		}
39244
39245		return new ExtrudeGeometry( geometryShapes, data.options );
39246
39247	}
39248
39249}
39250
39251const WorldUVGenerator = {
39252
39253	generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
39254
39255		const a_x = vertices[ indexA * 3 ];
39256		const a_y = vertices[ indexA * 3 + 1 ];
39257		const b_x = vertices[ indexB * 3 ];
39258		const b_y = vertices[ indexB * 3 + 1 ];
39259		const c_x = vertices[ indexC * 3 ];
39260		const c_y = vertices[ indexC * 3 + 1 ];
39261
39262		return [
39263			new Vector2( a_x, a_y ),
39264			new Vector2( b_x, b_y ),
39265			new Vector2( c_x, c_y )
39266		];
39267
39268	},
39269
39270	generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
39271
39272		const a_x = vertices[ indexA * 3 ];
39273		const a_y = vertices[ indexA * 3 + 1 ];
39274		const a_z = vertices[ indexA * 3 + 2 ];
39275		const b_x = vertices[ indexB * 3 ];
39276		const b_y = vertices[ indexB * 3 + 1 ];
39277		const b_z = vertices[ indexB * 3 + 2 ];
39278		const c_x = vertices[ indexC * 3 ];
39279		const c_y = vertices[ indexC * 3 + 1 ];
39280		const c_z = vertices[ indexC * 3 + 2 ];
39281		const d_x = vertices[ indexD * 3 ];
39282		const d_y = vertices[ indexD * 3 + 1 ];
39283		const d_z = vertices[ indexD * 3 + 2 ];
39284
39285		if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {
39286
39287			return [
39288				new Vector2( a_x, 1 - a_z ),
39289				new Vector2( b_x, 1 - b_z ),
39290				new Vector2( c_x, 1 - c_z ),
39291				new Vector2( d_x, 1 - d_z )
39292			];
39293
39294		} else {
39295
39296			return [
39297				new Vector2( a_y, 1 - a_z ),
39298				new Vector2( b_y, 1 - b_z ),
39299				new Vector2( c_y, 1 - c_z ),
39300				new Vector2( d_y, 1 - d_z )
39301			];
39302
39303		}
39304
39305	}
39306
39307};
39308
39309function toJSON$1( shapes, options, data ) {
39310
39311	data.shapes = [];
39312
39313	if ( Array.isArray( shapes ) ) {
39314
39315		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39316
39317			const shape = shapes[ i ];
39318
39319			data.shapes.push( shape.uuid );
39320
39321		}
39322
39323	} else {
39324
39325		data.shapes.push( shapes.uuid );
39326
39327	}
39328
39329	data.options = Object.assign( {}, options );
39330
39331	if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
39332
39333	return data;
39334
39335}
39336
39337class IcosahedronGeometry extends PolyhedronGeometry {
39338
39339	constructor( radius = 1, detail = 0 ) {
39340
39341		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
39342
39343		const vertices = [
39344			- 1, t, 0, 	1, t, 0, 	- 1, - t, 0, 	1, - t, 0,
39345			0, - 1, t, 	0, 1, t,	0, - 1, - t, 	0, 1, - t,
39346			t, 0, - 1, 	t, 0, 1, 	- t, 0, - 1, 	- t, 0, 1
39347		];
39348
39349		const indices = [
39350			0, 11, 5, 	0, 5, 1, 	0, 1, 7, 	0, 7, 10, 	0, 10, 11,
39351			1, 5, 9, 	5, 11, 4,	11, 10, 2,	10, 7, 6,	7, 1, 8,
39352			3, 9, 4, 	3, 4, 2,	3, 2, 6,	3, 6, 8,	3, 8, 9,
39353			4, 9, 5, 	2, 4, 11,	6, 2, 10,	8, 6, 7,	9, 8, 1
39354		];
39355
39356		super( vertices, indices, radius, detail );
39357
39358		this.type = 'IcosahedronGeometry';
39359
39360		this.parameters = {
39361			radius: radius,
39362			detail: detail
39363		};
39364
39365	}
39366
39367	static fromJSON( data ) {
39368
39369		return new IcosahedronGeometry( data.radius, data.detail );
39370
39371	}
39372
39373}
39374
39375class OctahedronGeometry extends PolyhedronGeometry {
39376
39377	constructor( radius = 1, detail = 0 ) {
39378
39379		const vertices = [
39380			1, 0, 0, 	- 1, 0, 0,	0, 1, 0,
39381			0, - 1, 0, 	0, 0, 1,	0, 0, - 1
39382		];
39383
39384		const indices = [
39385			0, 2, 4,	0, 4, 3,	0, 3, 5,
39386			0, 5, 2,	1, 2, 5,	1, 5, 3,
39387			1, 3, 4,	1, 4, 2
39388		];
39389
39390		super( vertices, indices, radius, detail );
39391
39392		this.type = 'OctahedronGeometry';
39393
39394		this.parameters = {
39395			radius: radius,
39396			detail: detail
39397		};
39398
39399	}
39400
39401	static fromJSON( data ) {
39402
39403		return new OctahedronGeometry( data.radius, data.detail );
39404
39405	}
39406
39407}
39408
39409class RingGeometry extends BufferGeometry {
39410
39411	constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
39412
39413		super();
39414
39415		this.type = 'RingGeometry';
39416
39417		this.parameters = {
39418			innerRadius: innerRadius,
39419			outerRadius: outerRadius,
39420			thetaSegments: thetaSegments,
39421			phiSegments: phiSegments,
39422			thetaStart: thetaStart,
39423			thetaLength: thetaLength
39424		};
39425
39426		thetaSegments = Math.max( 3, thetaSegments );
39427		phiSegments = Math.max( 1, phiSegments );
39428
39429		// buffers
39430
39431		const indices = [];
39432		const vertices = [];
39433		const normals = [];
39434		const uvs = [];
39435
39436		// some helper variables
39437
39438		let radius = innerRadius;
39439		const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
39440		const vertex = new Vector3();
39441		const uv = new Vector2();
39442
39443		// generate vertices, normals and uvs
39444
39445		for ( let j = 0; j <= phiSegments; j ++ ) {
39446
39447			for ( let i = 0; i <= thetaSegments; i ++ ) {
39448
39449				// values are generate from the inside of the ring to the outside
39450
39451				const segment = thetaStart + i / thetaSegments * thetaLength;
39452
39453				// vertex
39454
39455				vertex.x = radius * Math.cos( segment );
39456				vertex.y = radius * Math.sin( segment );
39457
39458				vertices.push( vertex.x, vertex.y, vertex.z );
39459
39460				// normal
39461
39462				normals.push( 0, 0, 1 );
39463
39464				// uv
39465
39466				uv.x = ( vertex.x / outerRadius + 1 ) / 2;
39467				uv.y = ( vertex.y / outerRadius + 1 ) / 2;
39468
39469				uvs.push( uv.x, uv.y );
39470
39471			}
39472
39473			// increase the radius for next row of vertices
39474
39475			radius += radiusStep;
39476
39477		}
39478
39479		// indices
39480
39481		for ( let j = 0; j < phiSegments; j ++ ) {
39482
39483			const thetaSegmentLevel = j * ( thetaSegments + 1 );
39484
39485			for ( let i = 0; i < thetaSegments; i ++ ) {
39486
39487				const segment = i + thetaSegmentLevel;
39488
39489				const a = segment;
39490				const b = segment + thetaSegments + 1;
39491				const c = segment + thetaSegments + 2;
39492				const d = segment + 1;
39493
39494				// faces
39495
39496				indices.push( a, b, d );
39497				indices.push( b, c, d );
39498
39499			}
39500
39501		}
39502
39503		// build geometry
39504
39505		this.setIndex( indices );
39506		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39507		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39508		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39509
39510	}
39511
39512	copy( source ) {
39513
39514		super.copy( source );
39515
39516		this.parameters = Object.assign( {}, source.parameters );
39517
39518		return this;
39519
39520	}
39521
39522	static fromJSON( data ) {
39523
39524		return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength );
39525
39526	}
39527
39528}
39529
39530class ShapeGeometry extends BufferGeometry {
39531
39532	constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {
39533
39534		super();
39535
39536		this.type = 'ShapeGeometry';
39537
39538		this.parameters = {
39539			shapes: shapes,
39540			curveSegments: curveSegments
39541		};
39542
39543		// buffers
39544
39545		const indices = [];
39546		const vertices = [];
39547		const normals = [];
39548		const uvs = [];
39549
39550		// helper variables
39551
39552		let groupStart = 0;
39553		let groupCount = 0;
39554
39555		// allow single and array values for "shapes" parameter
39556
39557		if ( Array.isArray( shapes ) === false ) {
39558
39559			addShape( shapes );
39560
39561		} else {
39562
39563			for ( let i = 0; i < shapes.length; i ++ ) {
39564
39565				addShape( shapes[ i ] );
39566
39567				this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
39568
39569				groupStart += groupCount;
39570				groupCount = 0;
39571
39572			}
39573
39574		}
39575
39576		// build geometry
39577
39578		this.setIndex( indices );
39579		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,079 bytes, lines 39580-39782
39580		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39581		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39582
39583
39584		// helper functions
39585
39586		function addShape( shape ) {
39587
39588			const indexOffset = vertices.length / 3;
39589			const points = shape.extractPoints( curveSegments );
39590
39591			let shapeVertices = points.shape;
39592			const shapeHoles = points.holes;
39593
39594			// check direction of vertices
39595
39596			if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
39597
39598				shapeVertices = shapeVertices.reverse();
39599
39600			}
39601
39602			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39603
39604				const shapeHole = shapeHoles[ i ];
39605
39606				if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
39607
39608					shapeHoles[ i ] = shapeHole.reverse();
39609
39610				}
39611
39612			}
39613
39614			const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
39615
39616			// join vertices of inner and outer paths to a single array
39617
39618			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39619
39620				const shapeHole = shapeHoles[ i ];
39621				shapeVertices = shapeVertices.concat( shapeHole );
39622
39623			}
39624
39625			// vertices, normals, uvs
39626
39627			for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
39628
39629				const vertex = shapeVertices[ i ];
39630
39631				vertices.push( vertex.x, vertex.y, 0 );
39632				normals.push( 0, 0, 1 );
39633				uvs.push( vertex.x, vertex.y ); // world uvs
39634
39635			}
39636
39637			// indices
39638
39639			for ( let i = 0, l = faces.length; i < l; i ++ ) {
39640
39641				const face = faces[ i ];
39642
39643				const a = face[ 0 ] + indexOffset;
39644				const b = face[ 1 ] + indexOffset;
39645				const c = face[ 2 ] + indexOffset;
39646
39647				indices.push( a, b, c );
39648				groupCount += 3;
39649
39650			}
39651
39652		}
39653
39654	}
39655
39656	copy( source ) {
39657
39658		super.copy( source );
39659
39660		this.parameters = Object.assign( {}, source.parameters );
39661
39662		return this;
39663
39664	}
39665
39666	toJSON() {
39667
39668		const data = super.toJSON();
39669
39670		const shapes = this.parameters.shapes;
39671
39672		return toJSON( shapes, data );
39673
39674	}
39675
39676	static fromJSON( data, shapes ) {
39677
39678		const geometryShapes = [];
39679
39680		for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39681
39682			const shape = shapes[ data.shapes[ j ] ];
39683
39684			geometryShapes.push( shape );
39685
39686		}
39687
39688		return new ShapeGeometry( geometryShapes, data.curveSegments );
39689
39690	}
39691
39692}
39693
39694function toJSON( shapes, data ) {
39695
39696	data.shapes = [];
39697
39698	if ( Array.isArray( shapes ) ) {
39699
39700		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39701
39702			const shape = shapes[ i ];
39703
39704			data.shapes.push( shape.uuid );
39705
39706		}
39707
39708	} else {
39709
39710		data.shapes.push( shapes.uuid );
39711
39712	}
39713
39714	return data;
39715
39716}
39717
39718class SphereGeometry extends BufferGeometry {
39719
39720	constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
39721
39722		super();
39723
39724		this.type = 'SphereGeometry';
39725
39726		this.parameters = {
39727			radius: radius,
39728			widthSegments: widthSegments,
39729			heightSegments: heightSegments,
39730			phiStart: phiStart,
39731			phiLength: phiLength,
39732			thetaStart: thetaStart,
39733			thetaLength: thetaLength
39734		};
39735
39736		widthSegments = Math.max( 3, Math.floor( widthSegments ) );
39737		heightSegments = Math.max( 2, Math.floor( heightSegments ) );
39738
39739		const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
39740
39741		let index = 0;
39742		const grid = [];
39743
39744		const vertex = new Vector3();
39745		const normal = new Vector3();
39746
39747		// buffers
39748
39749		const indices = [];
39750		const vertices = [];
39751		const normals = [];
39752		const uvs = [];
39753
39754		// generate vertices, normals and uvs
39755
39756		for ( let iy = 0; iy <= heightSegments; iy ++ ) {
39757
39758			const verticesRow = [];
39759
39760			const v = iy / heightSegments;
39761
39762			// special case for the poles
39763
39764			let uOffset = 0;
39765
39766			if ( iy === 0 && thetaStart === 0 ) {
39767
39768				uOffset = 0.5 / widthSegments;
39769
39770			} else if ( iy === heightSegments && thetaEnd === Math.PI ) {
39771
39772				uOffset = - 0.5 / widthSegments;
39773
39774			}
39775
39776			for ( let ix = 0; ix <= widthSegments; ix ++ ) {
39777
39778				const u = ix / widthSegments;
39779
39780				// vertex
39781
39782				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vendor: 4,136 bytes, lines 39783-39972
39783				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
39784				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
39785
39786				vertices.push( vertex.x, vertex.y, vertex.z );
39787
39788				// normal
39789
39790				normal.copy( vertex ).normalize();
39791				normals.push( normal.x, normal.y, normal.z );
39792
39793				// uv
39794
39795				uvs.push( u + uOffset, 1 - v );
39796
39797				verticesRow.push( index ++ );
39798
39799			}
39800
39801			grid.push( verticesRow );
39802
39803		}
39804
39805		// indices
39806
39807		for ( let iy = 0; iy < heightSegments; iy ++ ) {
39808
39809			for ( let ix = 0; ix < widthSegments; ix ++ ) {
39810
39811				const a = grid[ iy ][ ix + 1 ];
39812				const b = grid[ iy ][ ix ];
39813				const c = grid[ iy + 1 ][ ix ];
39814				const d = grid[ iy + 1 ][ ix + 1 ];
39815
39816				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
39817				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
39818
39819			}
39820
39821		}
39822
39823		// build geometry
39824
39825		this.setIndex( indices );
39826		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39827		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39828		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39829
39830	}
39831
39832	copy( source ) {
39833
39834		super.copy( source );
39835
39836		this.parameters = Object.assign( {}, source.parameters );
39837
39838		return this;
39839
39840	}
39841
39842	static fromJSON( data ) {
39843
39844		return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );
39845
39846	}
39847
39848}
39849
39850class TetrahedronGeometry extends PolyhedronGeometry {
39851
39852	constructor( radius = 1, detail = 0 ) {
39853
39854		const vertices = [
39855			1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
39856		];
39857
39858		const indices = [
39859			2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
39860		];
39861
39862		super( vertices, indices, radius, detail );
39863
39864		this.type = 'TetrahedronGeometry';
39865
39866		this.parameters = {
39867			radius: radius,
39868			detail: detail
39869		};
39870
39871	}
39872
39873	static fromJSON( data ) {
39874
39875		return new TetrahedronGeometry( data.radius, data.detail );
39876
39877	}
39878
39879}
39880
39881class TorusGeometry extends BufferGeometry {
39882
39883	constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) {
39884
39885		super();
39886
39887		this.type = 'TorusGeometry';
39888
39889		this.parameters = {
39890			radius: radius,
39891			tube: tube,
39892			radialSegments: radialSegments,
39893			tubularSegments: tubularSegments,
39894			arc: arc
39895		};
39896
39897		radialSegments = Math.floor( radialSegments );
39898		tubularSegments = Math.floor( tubularSegments );
39899
39900		// buffers
39901
39902		const indices = [];
39903		const vertices = [];
39904		const normals = [];
39905		const uvs = [];
39906
39907		// helper variables
39908
39909		const center = new Vector3();
39910		const vertex = new Vector3();
39911		const normal = new Vector3();
39912
39913		// generate vertices, normals and uvs
39914
39915		for ( let j = 0; j <= radialSegments; j ++ ) {
39916
39917			for ( let i = 0; i <= tubularSegments; i ++ ) {
39918
39919				const u = i / tubularSegments * arc;
39920				const v = j / radialSegments * Math.PI * 2;
39921
39922				// vertex
39923
39924				vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
39925				vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
39926				vertex.z = tube * Math.sin( v );
39927
39928				vertices.push( vertex.x, vertex.y, vertex.z );
39929
39930				// normal
39931
39932				center.x = radius * Math.cos( u );
39933				center.y = radius * Math.sin( u );
39934				normal.subVectors( vertex, center ).normalize();
39935
39936				normals.push( normal.x, normal.y, normal.z );
39937
39938				// uv
39939
39940				uvs.push( i / tubularSegments );
39941				uvs.push( j / radialSegments );
39942
39943			}
39944
39945		}
39946
39947		// generate indices
39948
39949		for ( let j = 1; j <= radialSegments; j ++ ) {
39950
39951			for ( let i = 1; i <= tubularSegments; i ++ ) {
39952
39953				// indices
39954
39955				const a = ( tubularSegments + 1 ) * j + i - 1;
39956				const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
39957				const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
39958				const d = ( tubularSegments + 1 ) * j + i;
39959
39960				// faces
39961
39962				indices.push( a, b, d );
39963				indices.push( b, c, d );
39964
39965			}
39966
39967		}
39968
39969		// build geometry
39970
39971		this.setIndex( indices );
39972		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 47,067 bytes, lines 39973-42175
39973		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39974		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39975
39976	}
39977
39978	copy( source ) {
39979
39980		super.copy( source );
39981
39982		this.parameters = Object.assign( {}, source.parameters );
39983
39984		return this;
39985
39986	}
39987
39988	static fromJSON( data ) {
39989
39990		return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc );
39991
39992	}
39993
39994}
39995
39996class TorusKnotGeometry extends BufferGeometry {
39997
39998	constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
39999
40000		super();
40001
40002		this.type = 'TorusKnotGeometry';
40003
40004		this.parameters = {
40005			radius: radius,
40006			tube: tube,
40007			tubularSegments: tubularSegments,
40008			radialSegments: radialSegments,
40009			p: p,
40010			q: q
40011		};
40012
40013		tubularSegments = Math.floor( tubularSegments );
40014		radialSegments = Math.floor( radialSegments );
40015
40016		// buffers
40017
40018		const indices = [];
40019		const vertices = [];
40020		const normals = [];
40021		const uvs = [];
40022
40023		// helper variables
40024
40025		const vertex = new Vector3();
40026		const normal = new Vector3();
40027
40028		const P1 = new Vector3();
40029		const P2 = new Vector3();
40030
40031		const B = new Vector3();
40032		const T = new Vector3();
40033		const N = new Vector3();
40034
40035		// generate vertices, normals and uvs
40036
40037		for ( let i = 0; i <= tubularSegments; ++ i ) {
40038
40039			// the radian "u" is used to calculate the position on the torus curve of the current tubular segment
40040
40041			const u = i / tubularSegments * p * Math.PI * 2;
40042
40043			// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
40044			// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
40045
40046			calculatePositionOnCurve( u, p, q, radius, P1 );
40047			calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
40048
40049			// calculate orthonormal basis
40050
40051			T.subVectors( P2, P1 );
40052			N.addVectors( P2, P1 );
40053			B.crossVectors( T, N );
40054			N.crossVectors( B, T );
40055
40056			// normalize B, N. T can be ignored, we don't use it
40057
40058			B.normalize();
40059			N.normalize();
40060
40061			for ( let j = 0; j <= radialSegments; ++ j ) {
40062
40063				// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
40064				// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
40065
40066				const v = j / radialSegments * Math.PI * 2;
40067				const cx = - tube * Math.cos( v );
40068				const cy = tube * Math.sin( v );
40069
40070				// now calculate the final vertex position.
40071				// first we orient the extrusion with our basis vectors, then we add it to the current position on the curve
40072
40073				vertex.x = P1.x + ( cx * N.x + cy * B.x );
40074				vertex.y = P1.y + ( cx * N.y + cy * B.y );
40075				vertex.z = P1.z + ( cx * N.z + cy * B.z );
40076
40077				vertices.push( vertex.x, vertex.y, vertex.z );
40078
40079				// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
40080
40081				normal.subVectors( vertex, P1 ).normalize();
40082
40083				normals.push( normal.x, normal.y, normal.z );
40084
40085				// uv
40086
40087				uvs.push( i / tubularSegments );
40088				uvs.push( j / radialSegments );
40089
40090			}
40091
40092		}
40093
40094		// generate indices
40095
40096		for ( let j = 1; j <= tubularSegments; j ++ ) {
40097
40098			for ( let i = 1; i <= radialSegments; i ++ ) {
40099
40100				// indices
40101
40102				const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40103				const b = ( radialSegments + 1 ) * j + ( i - 1 );
40104				const c = ( radialSegments + 1 ) * j + i;
40105				const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40106
40107				// faces
40108
40109				indices.push( a, b, d );
40110				indices.push( b, c, d );
40111
40112			}
40113
40114		}
40115
40116		// build geometry
40117
40118		this.setIndex( indices );
40119		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40120		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40121		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40122
40123		// this function calculates the current position on the torus curve
40124
40125		function calculatePositionOnCurve( u, p, q, radius, position ) {
40126
40127			const cu = Math.cos( u );
40128			const su = Math.sin( u );
40129			const quOverP = q / p * u;
40130			const cs = Math.cos( quOverP );
40131
40132			position.x = radius * ( 2 + cs ) * 0.5 * cu;
40133			position.y = radius * ( 2 + cs ) * su * 0.5;
40134			position.z = radius * Math.sin( quOverP ) * 0.5;
40135
40136		}
40137
40138	}
40139
40140	copy( source ) {
40141
40142		super.copy( source );
40143
40144		this.parameters = Object.assign( {}, source.parameters );
40145
40146		return this;
40147
40148	}
40149
40150	static fromJSON( data ) {
40151
40152		return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q );
40153
40154	}
40155
40156}
40157
40158class TubeGeometry extends BufferGeometry {
40159
40160	constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
40161
40162		super();
40163
40164		this.type = 'TubeGeometry';
40165
40166		this.parameters = {
40167			path: path,
40168			tubularSegments: tubularSegments,
40169			radius: radius,
40170			radialSegments: radialSegments,
40171			closed: closed
40172		};
40173
40174		const frames = path.computeFrenetFrames( tubularSegments, closed );
40175
40176		// expose internals
40177
40178		this.tangents = frames.tangents;
40179		this.normals = frames.normals;
40180		this.binormals = frames.binormals;
40181
40182		// helper variables
40183
40184		const vertex = new Vector3();
40185		const normal = new Vector3();
40186		const uv = new Vector2();
40187		let P = new Vector3();
40188
40189		// buffer
40190
40191		const vertices = [];
40192		const normals = [];
40193		const uvs = [];
40194		const indices = [];
40195
40196		// create buffer data
40197
40198		generateBufferData();
40199
40200		// build geometry
40201
40202		this.setIndex( indices );
40203		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40204		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40205		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40206
40207		// functions
40208
40209		function generateBufferData() {
40210
40211			for ( let i = 0; i < tubularSegments; i ++ ) {
40212
40213				generateSegment( i );
40214
40215			}
40216
40217			// if the geometry is not closed, generate the last row of vertices and normals
40218			// at the regular position on the given path
40219			//
40220			// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
40221
40222			generateSegment( ( closed === false ) ? tubularSegments : 0 );
40223
40224			// uvs are generated in a separate function.
40225			// this makes it easy compute correct values for closed geometries
40226
40227			generateUVs();
40228
40229			// finally create faces
40230
40231			generateIndices();
40232
40233		}
40234
40235		function generateSegment( i ) {
40236
40237			// we use getPointAt to sample evenly distributed points from the given path
40238
40239			P = path.getPointAt( i / tubularSegments, P );
40240
40241			// retrieve corresponding normal and binormal
40242
40243			const N = frames.normals[ i ];
40244			const B = frames.binormals[ i ];
40245
40246			// generate normals and vertices for the current segment
40247
40248			for ( let j = 0; j <= radialSegments; j ++ ) {
40249
40250				const v = j / radialSegments * Math.PI * 2;
40251
40252				const sin = Math.sin( v );
40253				const cos = - Math.cos( v );
40254
40255				// normal
40256
40257				normal.x = ( cos * N.x + sin * B.x );
40258				normal.y = ( cos * N.y + sin * B.y );
40259				normal.z = ( cos * N.z + sin * B.z );
40260				normal.normalize();
40261
40262				normals.push( normal.x, normal.y, normal.z );
40263
40264				// vertex
40265
40266				vertex.x = P.x + radius * normal.x;
40267				vertex.y = P.y + radius * normal.y;
40268				vertex.z = P.z + radius * normal.z;
40269
40270				vertices.push( vertex.x, vertex.y, vertex.z );
40271
40272			}
40273
40274		}
40275
40276		function generateIndices() {
40277
40278			for ( let j = 1; j <= tubularSegments; j ++ ) {
40279
40280				for ( let i = 1; i <= radialSegments; i ++ ) {
40281
40282					const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40283					const b = ( radialSegments + 1 ) * j + ( i - 1 );
40284					const c = ( radialSegments + 1 ) * j + i;
40285					const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40286
40287					// faces
40288
40289					indices.push( a, b, d );
40290					indices.push( b, c, d );
40291
40292				}
40293
40294			}
40295
40296		}
40297
40298		function generateUVs() {
40299
40300			for ( let i = 0; i <= tubularSegments; i ++ ) {
40301
40302				for ( let j = 0; j <= radialSegments; j ++ ) {
40303
40304					uv.x = i / tubularSegments;
40305					uv.y = j / radialSegments;
40306
40307					uvs.push( uv.x, uv.y );
40308
40309				}
40310
40311			}
40312
40313		}
40314
40315	}
40316
40317	copy( source ) {
40318
40319		super.copy( source );
40320
40321		this.parameters = Object.assign( {}, source.parameters );
40322
40323		return this;
40324
40325	}
40326
40327	toJSON() {
40328
40329		const data = super.toJSON();
40330
40331		data.path = this.parameters.path.toJSON();
40332
40333		return data;
40334
40335	}
40336
40337	static fromJSON( data ) {
40338
40339		// This only works for built-in curves (e.g. CatmullRomCurve3).
40340		// User defined curves or instances of CurvePath will not be deserialized.
40341		return new TubeGeometry(
40342			new Curves[ data.path.type ]().fromJSON( data.path ),
40343			data.tubularSegments,
40344			data.radius,
40345			data.radialSegments,
40346			data.closed
40347		);
40348
40349	}
40350
40351}
40352
40353class WireframeGeometry extends BufferGeometry {
40354
40355	constructor( geometry = null ) {
40356
40357		super();
40358
40359		this.type = 'WireframeGeometry';
40360
40361		this.parameters = {
40362			geometry: geometry
40363		};
40364
40365		if ( geometry !== null ) {
40366
40367			// buffer
40368
40369			const vertices = [];
40370			const edges = new Set();
40371
40372			// helper variables
40373
40374			const start = new Vector3();
40375			const end = new Vector3();
40376
40377			if ( geometry.index !== null ) {
40378
40379				// indexed BufferGeometry
40380
40381				const position = geometry.attributes.position;
40382				const indices = geometry.index;
40383				let groups = geometry.groups;
40384
40385				if ( groups.length === 0 ) {
40386
40387					groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
40388
40389				}
40390
40391				// create a data structure that contains all edges without duplicates
40392
40393				for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
40394
40395					const group = groups[ o ];
40396
40397					const groupStart = group.start;
40398					const groupCount = group.count;
40399
40400					for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {
40401
40402						for ( let j = 0; j < 3; j ++ ) {
40403
40404							const index1 = indices.getX( i + j );
40405							const index2 = indices.getX( i + ( j + 1 ) % 3 );
40406
40407							start.fromBufferAttribute( position, index1 );
40408							end.fromBufferAttribute( position, index2 );
40409
40410							if ( isUniqueEdge( start, end, edges ) === true ) {
40411
40412								vertices.push( start.x, start.y, start.z );
40413								vertices.push( end.x, end.y, end.z );
40414
40415							}
40416
40417						}
40418
40419					}
40420
40421				}
40422
40423			} else {
40424
40425				// non-indexed BufferGeometry
40426
40427				const position = geometry.attributes.position;
40428
40429				for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
40430
40431					for ( let j = 0; j < 3; j ++ ) {
40432
40433						// three edges per triangle, an edge is represented as (index1, index2)
40434						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
40435
40436						const index1 = 3 * i + j;
40437						const index2 = 3 * i + ( ( j + 1 ) % 3 );
40438
40439						start.fromBufferAttribute( position, index1 );
40440						end.fromBufferAttribute( position, index2 );
40441
40442						if ( isUniqueEdge( start, end, edges ) === true ) {
40443
40444							vertices.push( start.x, start.y, start.z );
40445							vertices.push( end.x, end.y, end.z );
40446
40447						}
40448
40449					}
40450
40451				}
40452
40453			}
40454
40455			// build geometry
40456
40457			this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40458
40459		}
40460
40461	}
40462
40463	copy( source ) {
40464
40465		super.copy( source );
40466
40467		this.parameters = Object.assign( {}, source.parameters );
40468
40469		return this;
40470
40471	}
40472
40473}
40474
40475function isUniqueEdge( start, end, edges ) {
40476
40477	const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;
40478	const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge
40479
40480	if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {
40481
40482		return false;
40483
40484	} else {
40485
40486		edges.add( hash1 );
40487		edges.add( hash2 );
40488		return true;
40489
40490	}
40491
40492}
40493
40494var Geometries = /*#__PURE__*/Object.freeze({
40495	__proto__: null,
40496	BoxGeometry: BoxGeometry,
40497	CapsuleGeometry: CapsuleGeometry,
40498	CircleGeometry: CircleGeometry,
40499	ConeGeometry: ConeGeometry,
40500	CylinderGeometry: CylinderGeometry,
40501	DodecahedronGeometry: DodecahedronGeometry,
40502	EdgesGeometry: EdgesGeometry,
40503	ExtrudeGeometry: ExtrudeGeometry,
40504	IcosahedronGeometry: IcosahedronGeometry,
40505	LatheGeometry: LatheGeometry,
40506	OctahedronGeometry: OctahedronGeometry,
40507	PlaneGeometry: PlaneGeometry,
40508	PolyhedronGeometry: PolyhedronGeometry,
40509	RingGeometry: RingGeometry,
40510	ShapeGeometry: ShapeGeometry,
40511	SphereGeometry: SphereGeometry,
40512	TetrahedronGeometry: TetrahedronGeometry,
40513	TorusGeometry: TorusGeometry,
40514	TorusKnotGeometry: TorusKnotGeometry,
40515	TubeGeometry: TubeGeometry,
40516	WireframeGeometry: WireframeGeometry
40517});
40518
40519class ShadowMaterial extends Material {
40520
40521	constructor( parameters ) {
40522
40523		super();
40524
40525		this.isShadowMaterial = true;
40526
40527		this.type = 'ShadowMaterial';
40528
40529		this.color = new Color( 0x000000 );
40530		this.transparent = true;
40531
40532		this.fog = true;
40533
40534		this.setValues( parameters );
40535
40536	}
40537
40538	copy( source ) {
40539
40540		super.copy( source );
40541
40542		this.color.copy( source.color );
40543
40544		this.fog = source.fog;
40545
40546		return this;
40547
40548	}
40549
40550}
40551
40552class RawShaderMaterial extends ShaderMaterial {
40553
40554	constructor( parameters ) {
40555
40556		super( parameters );
40557
40558		this.isRawShaderMaterial = true;
40559
40560		this.type = 'RawShaderMaterial';
40561
40562	}
40563
40564}
40565
40566class MeshStandardMaterial extends Material {
40567
40568	constructor( parameters ) {
40569
40570		super();
40571
40572		this.isMeshStandardMaterial = true;
40573
40574		this.defines = { 'STANDARD': '' };
40575
40576		this.type = 'MeshStandardMaterial';
40577
40578		this.color = new Color( 0xffffff ); // diffuse
40579		this.roughness = 1.0;
40580		this.metalness = 0.0;
40581
40582		this.map = null;
40583
40584		this.lightMap = null;
40585		this.lightMapIntensity = 1.0;
40586
40587		this.aoMap = null;
40588		this.aoMapIntensity = 1.0;
40589
40590		this.emissive = new Color( 0x000000 );
40591		this.emissiveIntensity = 1.0;
40592		this.emissiveMap = null;
40593
40594		this.bumpMap = null;
40595		this.bumpScale = 1;
40596
40597		this.normalMap = null;
40598		this.normalMapType = TangentSpaceNormalMap;
40599		this.normalScale = new Vector2( 1, 1 );
40600
40601		this.displacementMap = null;
40602		this.displacementScale = 1;
40603		this.displacementBias = 0;
40604
40605		this.roughnessMap = null;
40606
40607		this.metalnessMap = null;
40608
40609		this.alphaMap = null;
40610
40611		this.envMap = null;
40612		this.envMapIntensity = 1.0;
40613
40614		this.wireframe = false;
40615		this.wireframeLinewidth = 1;
40616		this.wireframeLinecap = 'round';
40617		this.wireframeLinejoin = 'round';
40618
40619		this.flatShading = false;
40620
40621		this.fog = true;
40622
40623		this.setValues( parameters );
40624
40625	}
40626
40627	copy( source ) {
40628
40629		super.copy( source );
40630
40631		this.defines = { 'STANDARD': '' };
40632
40633		this.color.copy( source.color );
40634		this.roughness = source.roughness;
40635		this.metalness = source.metalness;
40636
40637		this.map = source.map;
40638
40639		this.lightMap = source.lightMap;
40640		this.lightMapIntensity = source.lightMapIntensity;
40641
40642		this.aoMap = source.aoMap;
40643		this.aoMapIntensity = source.aoMapIntensity;
40644
40645		this.emissive.copy( source.emissive );
40646		this.emissiveMap = source.emissiveMap;
40647		this.emissiveIntensity = source.emissiveIntensity;
40648
40649		this.bumpMap = source.bumpMap;
40650		this.bumpScale = source.bumpScale;
40651
40652		this.normalMap = source.normalMap;
40653		this.normalMapType = source.normalMapType;
40654		this.normalScale.copy( source.normalScale );
40655
40656		this.displacementMap = source.displacementMap;
40657		this.displacementScale = source.displacementScale;
40658		this.displacementBias = source.displacementBias;
40659
40660		this.roughnessMap = source.roughnessMap;
40661
40662		this.metalnessMap = source.metalnessMap;
40663
40664		this.alphaMap = source.alphaMap;
40665
40666		this.envMap = source.envMap;
40667		this.envMapIntensity = source.envMapIntensity;
40668
40669		this.wireframe = source.wireframe;
40670		this.wireframeLinewidth = source.wireframeLinewidth;
40671		this.wireframeLinecap = source.wireframeLinecap;
40672		this.wireframeLinejoin = source.wireframeLinejoin;
40673
40674		this.flatShading = source.flatShading;
40675
40676		this.fog = source.fog;
40677
40678		return this;
40679
40680	}
40681
40682}
40683
40684class MeshPhysicalMaterial extends MeshStandardMaterial {
40685
40686	constructor( parameters ) {
40687
40688		super();
40689
40690		this.isMeshPhysicalMaterial = true;
40691
40692		this.defines = {
40693
40694			'STANDARD': '',
40695			'PHYSICAL': ''
40696
40697		};
40698
40699		this.type = 'MeshPhysicalMaterial';
40700
40701		this.anisotropyRotation = 0;
40702		this.anisotropyMap = null;
40703
40704		this.clearcoatMap = null;
40705		this.clearcoatRoughness = 0.0;
40706		this.clearcoatRoughnessMap = null;
40707		this.clearcoatNormalScale = new Vector2( 1, 1 );
40708		this.clearcoatNormalMap = null;
40709
40710		this.ior = 1.5;
40711
40712		Object.defineProperty( this, 'reflectivity', {
40713			get: function () {
40714
40715				return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );
40716
40717			},
40718			set: function ( reflectivity ) {
40719
40720				this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );
40721
40722			}
40723		} );
40724
40725		this.iridescenceMap = null;
40726		this.iridescenceIOR = 1.3;
40727		this.iridescenceThicknessRange = [ 100, 400 ];
40728		this.iridescenceThicknessMap = null;
40729
40730		this.sheenColor = new Color( 0x000000 );
40731		this.sheenColorMap = null;
40732		this.sheenRoughness = 1.0;
40733		this.sheenRoughnessMap = null;
40734
40735		this.transmissionMap = null;
40736
40737		this.thickness = 0;
40738		this.thicknessMap = null;
40739		this.attenuationDistance = Infinity;
40740		this.attenuationColor = new Color( 1, 1, 1 );
40741
40742		this.specularIntensity = 1.0;
40743		this.specularIntensityMap = null;
40744		this.specularColor = new Color( 1, 1, 1 );
40745		this.specularColorMap = null;
40746
40747		this._anisotropy = 0;
40748		this._clearcoat = 0;
40749		this._iridescence = 0;
40750		this._sheen = 0.0;
40751		this._transmission = 0;
40752
40753		this.setValues( parameters );
40754
40755	}
40756
40757	get anisotropy() {
40758
40759		return this._anisotropy;
40760
40761	}
40762
40763	set anisotropy( value ) {
40764
40765		if ( this._anisotropy > 0 !== value > 0 ) {
40766
40767			this.version ++;
40768
40769		}
40770
40771		this._anisotropy = value;
40772
40773	}
40774
40775	get clearcoat() {
40776
40777		return this._clearcoat;
40778
40779	}
40780
40781	set clearcoat( value ) {
40782
40783		if ( this._clearcoat > 0 !== value > 0 ) {
40784
40785			this.version ++;
40786
40787		}
40788
40789		this._clearcoat = value;
40790
40791	}
40792
40793	get iridescence() {
40794
40795		return this._iridescence;
40796
40797	}
40798
40799	set iridescence( value ) {
40800
40801		if ( this._iridescence > 0 !== value > 0 ) {
40802
40803			this.version ++;
40804
40805		}
40806
40807		this._iridescence = value;
40808
40809	}
40810
40811	get sheen() {
40812
40813		return this._sheen;
40814
40815	}
40816
40817	set sheen( value ) {
40818
40819		if ( this._sheen > 0 !== value > 0 ) {
40820
40821			this.version ++;
40822
40823		}
40824
40825		this._sheen = value;
40826
40827	}
40828
40829	get transmission() {
40830
40831		return this._transmission;
40832
40833	}
40834
40835	set transmission( value ) {
40836
40837		if ( this._transmission > 0 !== value > 0 ) {
40838
40839			this.version ++;
40840
40841		}
40842
40843		this._transmission = value;
40844
40845	}
40846
40847	copy( source ) {
40848
40849		super.copy( source );
40850
40851		this.defines = {
40852
40853			'STANDARD': '',
40854			'PHYSICAL': ''
40855
40856		};
40857
40858		this.anisotropy = source.anisotropy;
40859		this.anisotropyRotation = source.anisotropyRotation;
40860		this.anisotropyMap = source.anisotropyMap;
40861
40862		this.clearcoat = source.clearcoat;
40863		this.clearcoatMap = source.clearcoatMap;
40864		this.clearcoatRoughness = source.clearcoatRoughness;
40865		this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
40866		this.clearcoatNormalMap = source.clearcoatNormalMap;
40867		this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
40868
40869		this.ior = source.ior;
40870
40871		this.iridescence = source.iridescence;
40872		this.iridescenceMap = source.iridescenceMap;
40873		this.iridescenceIOR = source.iridescenceIOR;
40874		this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];
40875		this.iridescenceThicknessMap = source.iridescenceThicknessMap;
40876
40877		this.sheen = source.sheen;
40878		this.sheenColor.copy( source.sheenColor );
40879		this.sheenColorMap = source.sheenColorMap;
40880		this.sheenRoughness = source.sheenRoughness;
40881		this.sheenRoughnessMap = source.sheenRoughnessMap;
40882
40883		this.transmission = source.transmission;
40884		this.transmissionMap = source.transmissionMap;
40885
40886		this.thickness = source.thickness;
40887		this.thicknessMap = source.thicknessMap;
40888		this.attenuationDistance = source.attenuationDistance;
40889		this.attenuationColor.copy( source.attenuationColor );
40890
40891		this.specularIntensity = source.specularIntensity;
40892		this.specularIntensityMap = source.specularIntensityMap;
40893		this.specularColor.copy( source.specularColor );
40894		this.specularColorMap = source.specularColorMap;
40895
40896		return this;
40897
40898	}
40899
40900}
40901
40902class MeshPhongMaterial extends Material {
40903
40904	constructor( parameters ) {
40905
40906		super();
40907
40908		this.isMeshPhongMaterial = true;
40909
40910		this.type = 'MeshPhongMaterial';
40911
40912		this.color = new Color( 0xffffff ); // diffuse
40913		this.specular = new Color( 0x111111 );
40914		this.shininess = 30;
40915
40916		this.map = null;
40917
40918		this.lightMap = null;
40919		this.lightMapIntensity = 1.0;
40920
40921		this.aoMap = null;
40922		this.aoMapIntensity = 1.0;
40923
40924		this.emissive = new Color( 0x000000 );
40925		this.emissiveIntensity = 1.0;
40926		this.emissiveMap = null;
40927
40928		this.bumpMap = null;
40929		this.bumpScale = 1;
40930
40931		this.normalMap = null;
40932		this.normalMapType = TangentSpaceNormalMap;
40933		this.normalScale = new Vector2( 1, 1 );
40934
40935		this.displacementMap = null;
40936		this.displacementScale = 1;
40937		this.displacementBias = 0;
40938
40939		this.specularMap = null;
40940
40941		this.alphaMap = null;
40942
40943		this.envMap = null;
40944		this.combine = MultiplyOperation;
40945		this.reflectivity = 1;
40946		this.refractionRatio = 0.98;
40947
40948		this.wireframe = false;
40949		this.wireframeLinewidth = 1;
40950		this.wireframeLinecap = 'round';
40951		this.wireframeLinejoin = 'round';
40952
40953		this.flatShading = false;
40954
40955		this.fog = true;
40956
40957		this.setValues( parameters );
40958
40959	}
40960
40961	copy( source ) {
40962
40963		super.copy( source );
40964
40965		this.color.copy( source.color );
40966		this.specular.copy( source.specular );
40967		this.shininess = source.shininess;
40968
40969		this.map = source.map;
40970
40971		this.lightMap = source.lightMap;
40972		this.lightMapIntensity = source.lightMapIntensity;
40973
40974		this.aoMap = source.aoMap;
40975		this.aoMapIntensity = source.aoMapIntensity;
40976
40977		this.emissive.copy( source.emissive );
40978		this.emissiveMap = source.emissiveMap;
40979		this.emissiveIntensity = source.emissiveIntensity;
40980
40981		this.bumpMap = source.bumpMap;
40982		this.bumpScale = source.bumpScale;
40983
40984		this.normalMap = source.normalMap;
40985		this.normalMapType = source.normalMapType;
40986		this.normalScale.copy( source.normalScale );
40987
40988		this.displacementMap = source.displacementMap;
40989		this.displacementScale = source.displacementScale;
40990		this.displacementBias = source.displacementBias;
40991
40992		this.specularMap = source.specularMap;
40993
40994		this.alphaMap = source.alphaMap;
40995
40996		this.envMap = source.envMap;
40997		this.combine = source.combine;
40998		this.reflectivity = source.reflectivity;
40999		this.refractionRatio = source.refractionRatio;
41000
41001		this.wireframe = source.wireframe;
41002		this.wireframeLinewidth = source.wireframeLinewidth;
41003		this.wireframeLinecap = source.wireframeLinecap;
41004		this.wireframeLinejoin = source.wireframeLinejoin;
41005
41006		this.flatShading = source.flatShading;
41007
41008		this.fog = source.fog;
41009
41010		return this;
41011
41012	}
41013
41014}
41015
41016class MeshToonMaterial extends Material {
41017
41018	constructor( parameters ) {
41019
41020		super();
41021
41022		this.isMeshToonMaterial = true;
41023
41024		this.defines = { 'TOON': '' };
41025
41026		this.type = 'MeshToonMaterial';
41027
41028		this.color = new Color( 0xffffff );
41029
41030		this.map = null;
41031		this.gradientMap = null;
41032
41033		this.lightMap = null;
41034		this.lightMapIntensity = 1.0;
41035
41036		this.aoMap = null;
41037		this.aoMapIntensity = 1.0;
41038
41039		this.emissive = new Color( 0x000000 );
41040		this.emissiveIntensity = 1.0;
41041		this.emissiveMap = null;
41042
41043		this.bumpMap = null;
41044		this.bumpScale = 1;
41045
41046		this.normalMap = null;
41047		this.normalMapType = TangentSpaceNormalMap;
41048		this.normalScale = new Vector2( 1, 1 );
41049
41050		this.displacementMap = null;
41051		this.displacementScale = 1;
41052		this.displacementBias = 0;
41053
41054		this.alphaMap = null;
41055
41056		this.wireframe = false;
41057		this.wireframeLinewidth = 1;
41058		this.wireframeLinecap = 'round';
41059		this.wireframeLinejoin = 'round';
41060
41061		this.fog = true;
41062
41063		this.setValues( parameters );
41064
41065	}
41066
41067	copy( source ) {
41068
41069		super.copy( source );
41070
41071		this.color.copy( source.color );
41072
41073		this.map = source.map;
41074		this.gradientMap = source.gradientMap;
41075
41076		this.lightMap = source.lightMap;
41077		this.lightMapIntensity = source.lightMapIntensity;
41078
41079		this.aoMap = source.aoMap;
41080		this.aoMapIntensity = source.aoMapIntensity;
41081
41082		this.emissive.copy( source.emissive );
41083		this.emissiveMap = source.emissiveMap;
41084		this.emissiveIntensity = source.emissiveIntensity;
41085
41086		this.bumpMap = source.bumpMap;
41087		this.bumpScale = source.bumpScale;
41088
41089		this.normalMap = source.normalMap;
41090		this.normalMapType = source.normalMapType;
41091		this.normalScale.copy( source.normalScale );
41092
41093		this.displacementMap = source.displacementMap;
41094		this.displacementScale = source.displacementScale;
41095		this.displacementBias = source.displacementBias;
41096
41097		this.alphaMap = source.alphaMap;
41098
41099		this.wireframe = source.wireframe;
41100		this.wireframeLinewidth = source.wireframeLinewidth;
41101		this.wireframeLinecap = source.wireframeLinecap;
41102		this.wireframeLinejoin = source.wireframeLinejoin;
41103
41104		this.fog = source.fog;
41105
41106		return this;
41107
41108	}
41109
41110}
41111
41112class MeshNormalMaterial extends Material {
41113
41114	constructor( parameters ) {
41115
41116		super();
41117
41118		this.isMeshNormalMaterial = true;
41119
41120		this.type = 'MeshNormalMaterial';
41121
41122		this.bumpMap = null;
41123		this.bumpScale = 1;
41124
41125		this.normalMap = null;
41126		this.normalMapType = TangentSpaceNormalMap;
41127		this.normalScale = new Vector2( 1, 1 );
41128
41129		this.displacementMap = null;
41130		this.displacementScale = 1;
41131		this.displacementBias = 0;
41132
41133		this.wireframe = false;
41134		this.wireframeLinewidth = 1;
41135
41136		this.flatShading = false;
41137
41138		this.setValues( parameters );
41139
41140	}
41141
41142	copy( source ) {
41143
41144		super.copy( source );
41145
41146		this.bumpMap = source.bumpMap;
41147		this.bumpScale = source.bumpScale;
41148
41149		this.normalMap = source.normalMap;
41150		this.normalMapType = source.normalMapType;
41151		this.normalScale.copy( source.normalScale );
41152
41153		this.displacementMap = source.displacementMap;
41154		this.displacementScale = source.displacementScale;
41155		this.displacementBias = source.displacementBias;
41156
41157		this.wireframe = source.wireframe;
41158		this.wireframeLinewidth = source.wireframeLinewidth;
41159
41160		this.flatShading = source.flatShading;
41161
41162		return this;
41163
41164	}
41165
41166}
41167
41168class MeshLambertMaterial extends Material {
41169
41170	constructor( parameters ) {
41171
41172		super();
41173
41174		this.isMeshLambertMaterial = true;
41175
41176		this.type = 'MeshLambertMaterial';
41177
41178		this.color = new Color( 0xffffff ); // diffuse
41179
41180		this.map = null;
41181
41182		this.lightMap = null;
41183		this.lightMapIntensity = 1.0;
41184
41185		this.aoMap = null;
41186		this.aoMapIntensity = 1.0;
41187
41188		this.emissive = new Color( 0x000000 );
41189		this.emissiveIntensity = 1.0;
41190		this.emissiveMap = null;
41191
41192		this.bumpMap = null;
41193		this.bumpScale = 1;
41194
41195		this.normalMap = null;
41196		this.normalMapType = TangentSpaceNormalMap;
41197		this.normalScale = new Vector2( 1, 1 );
41198
41199		this.displacementMap = null;
41200		this.displacementScale = 1;
41201		this.displacementBias = 0;
41202
41203		this.specularMap = null;
41204
41205		this.alphaMap = null;
41206
41207		this.envMap = null;
41208		this.combine = MultiplyOperation;
41209		this.reflectivity = 1;
41210		this.refractionRatio = 0.98;
41211
41212		this.wireframe = false;
41213		this.wireframeLinewidth = 1;
41214		this.wireframeLinecap = 'round';
41215		this.wireframeLinejoin = 'round';
41216
41217		this.flatShading = false;
41218
41219		this.fog = true;
41220
41221		this.setValues( parameters );
41222
41223	}
41224
41225	copy( source ) {
41226
41227		super.copy( source );
41228
41229		this.color.copy( source.color );
41230
41231		this.map = source.map;
41232
41233		this.lightMap = source.lightMap;
41234		this.lightMapIntensity = source.lightMapIntensity;
41235
41236		this.aoMap = source.aoMap;
41237		this.aoMapIntensity = source.aoMapIntensity;
41238
41239		this.emissive.copy( source.emissive );
41240		this.emissiveMap = source.emissiveMap;
41241		this.emissiveIntensity = source.emissiveIntensity;
41242
41243		this.bumpMap = source.bumpMap;
41244		this.bumpScale = source.bumpScale;
41245
41246		this.normalMap = source.normalMap;
41247		this.normalMapType = source.normalMapType;
41248		this.normalScale.copy( source.normalScale );
41249
41250		this.displacementMap = source.displacementMap;
41251		this.displacementScale = source.displacementScale;
41252		this.displacementBias = source.displacementBias;
41253
41254		this.specularMap = source.specularMap;
41255
41256		this.alphaMap = source.alphaMap;
41257
41258		this.envMap = source.envMap;
41259		this.combine = source.combine;
41260		this.reflectivity = source.reflectivity;
41261		this.refractionRatio = source.refractionRatio;
41262
41263		this.wireframe = source.wireframe;
41264		this.wireframeLinewidth = source.wireframeLinewidth;
41265		this.wireframeLinecap = source.wireframeLinecap;
41266		this.wireframeLinejoin = source.wireframeLinejoin;
41267
41268		this.flatShading = source.flatShading;
41269
41270		this.fog = source.fog;
41271
41272		return this;
41273
41274	}
41275
41276}
41277
41278class MeshMatcapMaterial extends Material {
41279
41280	constructor( parameters ) {
41281
41282		super();
41283
41284		this.isMeshMatcapMaterial = true;
41285
41286		this.defines = { 'MATCAP': '' };
41287
41288		this.type = 'MeshMatcapMaterial';
41289
41290		this.color = new Color( 0xffffff ); // diffuse
41291
41292		this.matcap = null;
41293
41294		this.map = null;
41295
41296		this.bumpMap = null;
41297		this.bumpScale = 1;
41298
41299		this.normalMap = null;
41300		this.normalMapType = TangentSpaceNormalMap;
41301		this.normalScale = new Vector2( 1, 1 );
41302
41303		this.displacementMap = null;
41304		this.displacementScale = 1;
41305		this.displacementBias = 0;
41306
41307		this.alphaMap = null;
41308
41309		this.flatShading = false;
41310
41311		this.fog = true;
41312
41313		this.setValues( parameters );
41314
41315	}
41316
41317
41318	copy( source ) {
41319
41320		super.copy( source );
41321
41322		this.defines = { 'MATCAP': '' };
41323
41324		this.color.copy( source.color );
41325
41326		this.matcap = source.matcap;
41327
41328		this.map = source.map;
41329
41330		this.bumpMap = source.bumpMap;
41331		this.bumpScale = source.bumpScale;
41332
41333		this.normalMap = source.normalMap;
41334		this.normalMapType = source.normalMapType;
41335		this.normalScale.copy( source.normalScale );
41336
41337		this.displacementMap = source.displacementMap;
41338		this.displacementScale = source.displacementScale;
41339		this.displacementBias = source.displacementBias;
41340
41341		this.alphaMap = source.alphaMap;
41342
41343		this.flatShading = source.flatShading;
41344
41345		this.fog = source.fog;
41346
41347		return this;
41348
41349	}
41350
41351}
41352
41353class LineDashedMaterial extends LineBasicMaterial {
41354
41355	constructor( parameters ) {
41356
41357		super();
41358
41359		this.isLineDashedMaterial = true;
41360
41361		this.type = 'LineDashedMaterial';
41362
41363		this.scale = 1;
41364		this.dashSize = 3;
41365		this.gapSize = 1;
41366
41367		this.setValues( parameters );
41368
41369	}
41370
41371	copy( source ) {
41372
41373		super.copy( source );
41374
41375		this.scale = source.scale;
41376		this.dashSize = source.dashSize;
41377		this.gapSize = source.gapSize;
41378
41379		return this;
41380
41381	}
41382
41383}
41384
41385// converts an array to a specific type
41386function convertArray( array, type, forceClone ) {
41387
41388	if ( ! array || // let 'undefined' and 'null' pass
41389		! forceClone && array.constructor === type ) return array;
41390
41391	if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
41392
41393		return new type( array ); // create typed array
41394
41395	}
41396
41397	return Array.prototype.slice.call( array ); // create Array
41398
41399}
41400
41401function isTypedArray( object ) {
41402
41403	return ArrayBuffer.isView( object ) &&
41404		! ( object instanceof DataView );
41405
41406}
41407
41408// returns an array by which times and values can be sorted
41409function getKeyframeOrder( times ) {
41410
41411	function compareTime( i, j ) {
41412
41413		return times[ i ] - times[ j ];
41414
41415	}
41416
41417	const n = times.length;
41418	const result = new Array( n );
41419	for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
41420
41421	result.sort( compareTime );
41422
41423	return result;
41424
41425}
41426
41427// uses the array previously returned by 'getKeyframeOrder' to sort data
41428function sortedArray( values, stride, order ) {
41429
41430	const nValues = values.length;
41431	const result = new values.constructor( nValues );
41432
41433	for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
41434
41435		const srcOffset = order[ i ] * stride;
41436
41437		for ( let j = 0; j !== stride; ++ j ) {
41438
41439			result[ dstOffset ++ ] = values[ srcOffset + j ];
41440
41441		}
41442
41443	}
41444
41445	return result;
41446
41447}
41448
41449// function for parsing AOS keyframe formats
41450function flattenJSON( jsonKeys, times, values, valuePropertyName ) {
41451
41452	let i = 1, key = jsonKeys[ 0 ];
41453
41454	while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
41455
41456		key = jsonKeys[ i ++ ];
41457
41458	}
41459
41460	if ( key === undefined ) return; // no data
41461
41462	let value = key[ valuePropertyName ];
41463	if ( value === undefined ) return; // no data
41464
41465	if ( Array.isArray( value ) ) {
41466
41467		do {
41468
41469			value = key[ valuePropertyName ];
41470
41471			if ( value !== undefined ) {
41472
41473				times.push( key.time );
41474				values.push.apply( values, value ); // push all elements
41475
41476			}
41477
41478			key = jsonKeys[ i ++ ];
41479
41480		} while ( key !== undefined );
41481
41482	} else if ( value.toArray !== undefined ) {
41483
41484		// ...assume THREE.Math-ish
41485
41486		do {
41487
41488			value = key[ valuePropertyName ];
41489
41490			if ( value !== undefined ) {
41491
41492				times.push( key.time );
41493				value.toArray( values, values.length );
41494
41495			}
41496
41497			key = jsonKeys[ i ++ ];
41498
41499		} while ( key !== undefined );
41500
41501	} else {
41502
41503		// otherwise push as-is
41504
41505		do {
41506
41507			value = key[ valuePropertyName ];
41508
41509			if ( value !== undefined ) {
41510
41511				times.push( key.time );
41512				values.push( value );
41513
41514			}
41515
41516			key = jsonKeys[ i ++ ];
41517
41518		} while ( key !== undefined );
41519
41520	}
41521
41522}
41523
41524function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {
41525
41526	const clip = sourceClip.clone();
41527
41528	clip.name = name;
41529
41530	const tracks = [];
41531
41532	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41533
41534		const track = clip.tracks[ i ];
41535		const valueSize = track.getValueSize();
41536
41537		const times = [];
41538		const values = [];
41539
41540		for ( let j = 0; j < track.times.length; ++ j ) {
41541
41542			const frame = track.times[ j ] * fps;
41543
41544			if ( frame < startFrame || frame >= endFrame ) continue;
41545
41546			times.push( track.times[ j ] );
41547
41548			for ( let k = 0; k < valueSize; ++ k ) {
41549
41550				values.push( track.values[ j * valueSize + k ] );
41551
41552			}
41553
41554		}
41555
41556		if ( times.length === 0 ) continue;
41557
41558		track.times = convertArray( times, track.times.constructor );
41559		track.values = convertArray( values, track.values.constructor );
41560
41561		tracks.push( track );
41562
41563	}
41564
41565	clip.tracks = tracks;
41566
41567	// find minimum .times value across all tracks in the trimmed clip
41568
41569	let minStartTime = Infinity;
41570
41571	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41572
41573		if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
41574
41575			minStartTime = clip.tracks[ i ].times[ 0 ];
41576
41577		}
41578
41579	}
41580
41581	// shift all tracks such that clip begins at t=0
41582
41583	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41584
41585		clip.tracks[ i ].shift( - 1 * minStartTime );
41586
41587	}
41588
41589	clip.resetDuration();
41590
41591	return clip;
41592
41593}
41594
41595function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
41596
41597	if ( fps <= 0 ) fps = 30;
41598
41599	const numTracks = referenceClip.tracks.length;
41600	const referenceTime = referenceFrame / fps;
41601
41602	// Make each track's values relative to the values at the reference frame
41603	for ( let i = 0; i < numTracks; ++ i ) {
41604
41605		const referenceTrack = referenceClip.tracks[ i ];
41606		const referenceTrackType = referenceTrack.ValueTypeName;
41607
41608		// Skip this track if it's non-numeric
41609		if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
41610
41611		// Find the track in the target clip whose name and type matches the reference track
41612		const targetTrack = targetClip.tracks.find( function ( track ) {
41613
41614			return track.name === referenceTrack.name
41615				&& track.ValueTypeName === referenceTrackType;
41616
41617		} );
41618
41619		if ( targetTrack === undefined ) continue;
41620
41621		let referenceOffset = 0;
41622		const referenceValueSize = referenceTrack.getValueSize();
41623
41624		if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41625
41626			referenceOffset = referenceValueSize / 3;
41627
41628		}
41629
41630		let targetOffset = 0;
41631		const targetValueSize = targetTrack.getValueSize();
41632
41633		if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41634
41635			targetOffset = targetValueSize / 3;
41636
41637		}
41638
41639		const lastIndex = referenceTrack.times.length - 1;
41640		let referenceValue;
41641
41642		// Find the value to subtract out of the track
41643		if ( referenceTime <= referenceTrack.times[ 0 ] ) {
41644
41645			// Reference frame is earlier than the first keyframe, so just use the first keyframe
41646			const startIndex = referenceOffset;
41647			const endIndex = referenceValueSize - referenceOffset;
41648			referenceValue = referenceTrack.values.slice( startIndex, endIndex );
41649
41650		} else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
41651
41652			// Reference frame is after the last keyframe, so just use the last keyframe
41653			const startIndex = lastIndex * referenceValueSize + referenceOffset;
41654			const endIndex = startIndex + referenceValueSize - referenceOffset;
41655			referenceValue = referenceTrack.values.slice( startIndex, endIndex );
41656
41657		} else {
41658
41659			// Interpolate to the reference value
41660			const interpolant = referenceTrack.createInterpolant();
41661			const startIndex = referenceOffset;
41662			const endIndex = referenceValueSize - referenceOffset;
41663			interpolant.evaluate( referenceTime );
41664			referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );
41665
41666		}
41667
41668		// Conjugate the quaternion
41669		if ( referenceTrackType === 'quaternion' ) {
41670
41671			const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
41672			referenceQuat.toArray( referenceValue );
41673
41674		}
41675
41676		// Subtract the reference value from all of the track values
41677
41678		const numTimes = targetTrack.times.length;
41679		for ( let j = 0; j < numTimes; ++ j ) {
41680
41681			const valueStart = j * targetValueSize + targetOffset;
41682
41683			if ( referenceTrackType === 'quaternion' ) {
41684
41685				// Multiply the conjugate for quaternion track types
41686				Quaternion.multiplyQuaternionsFlat(
41687					targetTrack.values,
41688					valueStart,
41689					referenceValue,
41690					0,
41691					targetTrack.values,
41692					valueStart
41693				);
41694
41695			} else {
41696
41697				const valueEnd = targetValueSize - targetOffset * 2;
41698
41699				// Subtract each value for all other numeric track types
41700				for ( let k = 0; k < valueEnd; ++ k ) {
41701
41702					targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
41703
41704				}
41705
41706			}
41707
41708		}
41709
41710	}
41711
41712	targetClip.blendMode = AdditiveAnimationBlendMode;
41713
41714	return targetClip;
41715
41716}
41717
41718const AnimationUtils = {
41719	convertArray: convertArray,
41720	isTypedArray: isTypedArray,
41721	getKeyframeOrder: getKeyframeOrder,
41722	sortedArray: sortedArray,
41723	flattenJSON: flattenJSON,
41724	subclip: subclip,
41725	makeClipAdditive: makeClipAdditive
41726};
41727
41728/**
41729 * Abstract base class of interpolants over parametric samples.
41730 *
41731 * The parameter domain is one dimensional, typically the time or a path
41732 * along a curve defined by the data.
41733 *
41734 * The sample values can have any dimensionality and derived classes may
41735 * apply special interpretations to the data.
41736 *
41737 * This class provides the interval seek in a Template Method, deferring
41738 * the actual interpolation to derived classes.
41739 *
41740 * Time complexity is O(1) for linear access crossing at most two points
41741 * and O(log N) for random access, where N is the number of positions.
41742 *
41743 * References:
41744 *
41745 * 		http://www.oodesign.com/template-method-pattern.html
41746 *
41747 */
41748
41749class Interpolant {
41750
41751	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
41752
41753		this.parameterPositions = parameterPositions;
41754		this._cachedIndex = 0;
41755
41756		this.resultBuffer = resultBuffer !== undefined ?
41757			resultBuffer : new sampleValues.constructor( sampleSize );
41758		this.sampleValues = sampleValues;
41759		this.valueSize = sampleSize;
41760
41761		this.settings = null;
41762		this.DefaultSettings_ = {};
41763
41764	}
41765
41766	evaluate( t ) {
41767
41768		const pp = this.parameterPositions;
41769		let i1 = this._cachedIndex,
41770			t1 = pp[ i1 ],
41771			t0 = pp[ i1 - 1 ];
41772
41773		validate_interval: {
41774
41775			seek: {
41776
41777				let right;
41778
41779				linear_scan: {
41780
41781					//- See http://jsperf.com/comparison-to-undefined/3
41782					//- slower code:
41783					//-
41784					//- 				if ( t >= t1 || t1 === undefined ) {
41785					forward_scan: if ( ! ( t < t1 ) ) {
41786
41787						for ( let giveUpAt = i1 + 2; ; ) {
41788
41789							if ( t1 === undefined ) {
41790
41791								if ( t < t0 ) break forward_scan;
41792
41793								// after end
41794
41795								i1 = pp.length;
41796								this._cachedIndex = i1;
41797								return this.copySampleValue_( i1 - 1 );
41798
41799							}
41800
41801							if ( i1 === giveUpAt ) break; // this loop
41802
41803							t0 = t1;
41804							t1 = pp[ ++ i1 ];
41805
41806							if ( t < t1 ) {
41807
41808								// we have arrived at the sought interval
41809								break seek;
41810
41811							}
41812
41813						}
41814
41815						// prepare binary search on the right side of the index
41816						right = pp.length;
41817						break linear_scan;
41818
41819					}
41820
41821					//- slower code:
41822					//-					if ( t < t0 || t0 === undefined ) {
41823					if ( ! ( t >= t0 ) ) {
41824
41825						// looping?
41826
41827						const t1global = pp[ 1 ];
41828
41829						if ( t < t1global ) {
41830
41831							i1 = 2; // + 1, using the scan for the details
41832							t0 = t1global;
41833
41834						}
41835
41836						// linear reverse scan
41837
41838						for ( let giveUpAt = i1 - 2; ; ) {
41839
41840							if ( t0 === undefined ) {
41841
41842								// before start
41843
41844								this._cachedIndex = 0;
41845								return this.copySampleValue_( 0 );
41846
41847							}
41848
41849							if ( i1 === giveUpAt ) break; // this loop
41850
41851							t1 = t0;
41852							t0 = pp[ -- i1 - 1 ];
41853
41854							if ( t >= t0 ) {
41855
41856								// we have arrived at the sought interval
41857								break seek;
41858
41859							}
41860
41861						}
41862
41863						// prepare binary search on the left side of the index
41864						right = i1;
41865						i1 = 0;
41866						break linear_scan;
41867
41868					}
41869
41870					// the interval is valid
41871
41872					break validate_interval;
41873
41874				} // linear scan
41875
41876				// binary search
41877
41878				while ( i1 < right ) {
41879
41880					const mid = ( i1 + right ) >>> 1;
41881
41882					if ( t < pp[ mid ] ) {
41883
41884						right = mid;
41885
41886					} else {
41887
41888						i1 = mid + 1;
41889
41890					}
41891
41892				}
41893
41894				t1 = pp[ i1 ];
41895				t0 = pp[ i1 - 1 ];
41896
41897				// check boundary cases, again
41898
41899				if ( t0 === undefined ) {
41900
41901					this._cachedIndex = 0;
41902					return this.copySampleValue_( 0 );
41903
41904				}
41905
41906				if ( t1 === undefined ) {
41907
41908					i1 = pp.length;
41909					this._cachedIndex = i1;
41910					return this.copySampleValue_( i1 - 1 );
41911
41912				}
41913
41914			} // seek
41915
41916			this._cachedIndex = i1;
41917
41918			this.intervalChanged_( i1, t0, t1 );
41919
41920		} // validate_interval
41921
41922		return this.interpolate_( i1, t0, t, t1 );
41923
41924	}
41925
41926	getSettings_() {
41927
41928		return this.settings || this.DefaultSettings_;
41929
41930	}
41931
41932	copySampleValue_( index ) {
41933
41934		// copies a sample value to the result buffer
41935
41936		const result = this.resultBuffer,
41937			values = this.sampleValues,
41938			stride = this.valueSize,
41939			offset = index * stride;
41940
41941		for ( let i = 0; i !== stride; ++ i ) {
41942
41943			result[ i ] = values[ offset + i ];
41944
41945		}
41946
41947		return result;
41948
41949	}
41950
41951	// Template methods for derived classes:
41952
41953	interpolate_( /* i1, t0, t, t1 */ ) {
41954
41955		throw new Error( 'call to abstract method' );
41956		// implementations shall return this.resultBuffer
41957
41958	}
41959
41960	intervalChanged_( /* i1, t0, t1 */ ) {
41961
41962		// empty
41963
41964	}
41965
41966}
41967
41968/**
41969 * Fast and simple cubic spline interpolant.
41970 *
41971 * It was derived from a Hermitian construction setting the first derivative
41972 * at each sample position to the linear slope between neighboring positions
41973 * over their parameter interval.
41974 */
41975
41976class CubicInterpolant extends Interpolant {
41977
41978	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
41979
41980		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
41981
41982		this._weightPrev = - 0;
41983		this._offsetPrev = - 0;
41984		this._weightNext = - 0;
41985		this._offsetNext = - 0;
41986
41987		this.DefaultSettings_ = {
41988
41989			endingStart: ZeroCurvatureEnding,
41990			endingEnd: ZeroCurvatureEnding
41991
41992		};
41993
41994	}
41995
41996	intervalChanged_( i1, t0, t1 ) {
41997
41998		const pp = this.parameterPositions;
41999		let iPrev = i1 - 2,
42000			iNext = i1 + 1,
42001
42002			tPrev = pp[ iPrev ],
42003			tNext = pp[ iNext ];
42004
42005		if ( tPrev === undefined ) {
42006
42007			switch ( this.getSettings_().endingStart ) {
42008
42009				case ZeroSlopeEnding:
42010
42011					// f'(t0) = 0
42012					iPrev = i1;
42013					tPrev = 2 * t0 - t1;
42014
42015					break;
42016
42017				case WrapAroundEnding:
42018
42019					// use the other end of the curve
42020					iPrev = pp.length - 2;
42021					tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
42022
42023					break;
42024
42025				default: // ZeroCurvatureEnding
42026
42027					// f''(t0) = 0 a.k.a. Natural Spline
42028					iPrev = i1;
42029					tPrev = t1;
42030
42031			}
42032
42033		}
42034
42035		if ( tNext === undefined ) {
42036
42037			switch ( this.getSettings_().endingEnd ) {
42038
42039				case ZeroSlopeEnding:
42040
42041					// f'(tN) = 0
42042					iNext = i1;
42043					tNext = 2 * t1 - t0;
42044
42045					break;
42046
42047				case WrapAroundEnding:
42048
42049					// use the other end of the curve
42050					iNext = 1;
42051					tNext = t1 + pp[ 1 ] - pp[ 0 ];
42052
42053					break;
42054
42055				default: // ZeroCurvatureEnding
42056
42057					// f''(tN) = 0, a.k.a. Natural Spline
42058					iNext = i1 - 1;
42059					tNext = t0;
42060
42061			}
42062
42063		}
42064
42065		const halfDt = ( t1 - t0 ) * 0.5,
42066			stride = this.valueSize;
42067
42068		this._weightPrev = halfDt / ( t0 - tPrev );
42069		this._weightNext = halfDt / ( tNext - t1 );
42070		this._offsetPrev = iPrev * stride;
42071		this._offsetNext = iNext * stride;
42072
42073	}
42074
42075	interpolate_( i1, t0, t, t1 ) {
42076
42077		const result = this.resultBuffer,
42078			values = this.sampleValues,
42079			stride = this.valueSize,
42080
42081			o1 = i1 * stride,		o0 = o1 - stride,
42082			oP = this._offsetPrev, 	oN = this._offsetNext,
42083			wP = this._weightPrev,	wN = this._weightNext,
42084
42085			p = ( t - t0 ) / ( t1 - t0 ),
42086			pp = p * p,
42087			ppp = pp * p;
42088
42089		// evaluate polynomials
42090
42091		const sP = - wP * ppp + 2 * wP * pp - wP * p;
42092		const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
42093		const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
42094		const sN = wN * ppp - wN * pp;
42095
42096		// combine data linearly
42097
42098		for ( let i = 0; i !== stride; ++ i ) {
42099
42100			result[ i ] =
42101					sP * values[ oP + i ] +
42102					s0 * values[ o0 + i ] +
42103					s1 * values[ o1 + i ] +
42104					sN * values[ oN + i ];
42105
42106		}
42107
42108		return result;
42109
42110	}
42111
42112}
42113
42114class LinearInterpolant extends Interpolant {
42115
42116	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42117
42118		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42119
42120	}
42121
42122	interpolate_( i1, t0, t, t1 ) {
42123
42124		const result = this.resultBuffer,
42125			values = this.sampleValues,
42126			stride = this.valueSize,
42127
42128			offset1 = i1 * stride,
42129			offset0 = offset1 - stride,
42130
42131			weight1 = ( t - t0 ) / ( t1 - t0 ),
42132			weight0 = 1 - weight1;
42133
42134		for ( let i = 0; i !== stride; ++ i ) {
42135
42136			result[ i ] =
42137					values[ offset0 + i ] * weight0 +
42138					values[ offset1 + i ] * weight1;
42139
42140		}
42141
42142		return result;
42143
42144	}
42145
42146}
42147
42148/**
42149 *
42150 * Interpolant that evaluates to the sample value at the position preceding
42151 * the parameter.
42152 */
42153
42154class DiscreteInterpolant extends Interpolant {
42155
42156	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42157
42158		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42159
42160	}
42161
42162	interpolate_( i1 /*, t0, t, t1 */ ) {
42163
42164		return this.copySampleValue_( i1 - 1 );
42165
42166	}
42167
42168}
42169
42170class KeyframeTrack {
42171
42172	constructor( name, times, values, interpolation ) {
42173
42174		if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
42175		if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + n
vendor: 25,402 bytes, lines 42175-43499
42175ame );
42176
42177		this.name = name;
42178
42179		this.times = convertArray( times, this.TimeBufferType );
42180		this.values = convertArray( values, this.ValueBufferType );
42181
42182		this.setInterpolation( interpolation || this.DefaultInterpolation );
42183
42184	}
42185
42186	// Serialization (in static context, because of constructor invocation
42187	// and automatic invocation of .toJSON):
42188
42189	static toJSON( track ) {
42190
42191		const trackType = track.constructor;
42192
42193		let json;
42194
42195		// derived classes can define a static toJSON method
42196		if ( trackType.toJSON !== this.toJSON ) {
42197
42198			json = trackType.toJSON( track );
42199
42200		} else {
42201
42202			// by default, we assume the data can be serialized as-is
42203			json = {
42204
42205				'name': track.name,
42206				'times': convertArray( track.times, Array ),
42207				'values': convertArray( track.values, Array )
42208
42209			};
42210
42211			const interpolation = track.getInterpolation();
42212
42213			if ( interpolation !== track.DefaultInterpolation ) {
42214
42215				json.interpolation = interpolation;
42216
42217			}
42218
42219		}
42220
42221		json.type = track.ValueTypeName; // mandatory
42222
42223		return json;
42224
42225	}
42226
42227	InterpolantFactoryMethodDiscrete( result ) {
42228
42229		return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
42230
42231	}
42232
42233	InterpolantFactoryMethodLinear( result ) {
42234
42235		return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
42236
42237	}
42238
42239	InterpolantFactoryMethodSmooth( result ) {
42240
42241		return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
42242
42243	}
42244
42245	setInterpolation( interpolation ) {
42246
42247		let factoryMethod;
42248
42249		switch ( interpolation ) {
42250
42251			case InterpolateDiscrete:
42252
42253				factoryMethod = this.InterpolantFactoryMethodDiscrete;
42254
42255				break;
42256
42257			case InterpolateLinear:
42258
42259				factoryMethod = this.InterpolantFactoryMethodLinear;
42260
42261				break;
42262
42263			case InterpolateSmooth:
42264
42265				factoryMethod = this.InterpolantFactoryMethodSmooth;
42266
42267				break;
42268
42269		}
42270
42271		if ( factoryMethod === undefined ) {
42272
42273			const message = 'unsupported interpolation for ' +
42274				this.ValueTypeName + ' keyframe track named ' + this.name;
42275
42276			if ( this.createInterpolant === undefined ) {
42277
42278				// fall back to default, unless the default itself is messed up
42279				if ( interpolation !== this.DefaultInterpolation ) {
42280
42281					this.setInterpolation( this.DefaultInterpolation );
42282
42283				} else {
42284
42285					throw new Error( message ); // fatal, in this case
42286
42287				}
42288
42289			}
42290
42291			console.warn( 'THREE.KeyframeTrack:', message );
42292			return this;
42293
42294		}
42295
42296		this.createInterpolant = factoryMethod;
42297
42298		return this;
42299
42300	}
42301
42302	getInterpolation() {
42303
42304		switch ( this.createInterpolant ) {
42305
42306			case this.InterpolantFactoryMethodDiscrete:
42307
42308				return InterpolateDiscrete;
42309
42310			case this.InterpolantFactoryMethodLinear:
42311
42312				return InterpolateLinear;
42313
42314			case this.InterpolantFactoryMethodSmooth:
42315
42316				return InterpolateSmooth;
42317
42318		}
42319
42320	}
42321
42322	getValueSize() {
42323
42324		return this.values.length / this.times.length;
42325
42326	}
42327
42328	// move all keyframes either forwards or backwards in time
42329	shift( timeOffset ) {
42330
42331		if ( timeOffset !== 0.0 ) {
42332
42333			const times = this.times;
42334
42335			for ( let i = 0, n = times.length; i !== n; ++ i ) {
42336
42337				times[ i ] += timeOffset;
42338
42339			}
42340
42341		}
42342
42343		return this;
42344
42345	}
42346
42347	// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
42348	scale( timeScale ) {
42349
42350		if ( timeScale !== 1.0 ) {
42351
42352			const times = this.times;
42353
42354			for ( let i = 0, n = times.length; i !== n; ++ i ) {
42355
42356				times[ i ] *= timeScale;
42357
42358			}
42359
42360		}
42361
42362		return this;
42363
42364	}
42365
42366	// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
42367	// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
42368	trim( startTime, endTime ) {
42369
42370		const times = this.times,
42371			nKeys = times.length;
42372
42373		let from = 0,
42374			to = nKeys - 1;
42375
42376		while ( from !== nKeys && times[ from ] < startTime ) {
42377
42378			++ from;
42379
42380		}
42381
42382		while ( to !== - 1 && times[ to ] > endTime ) {
42383
42384			-- to;
42385
42386		}
42387
42388		++ to; // inclusive -> exclusive bound
42389
42390		if ( from !== 0 || to !== nKeys ) {
42391
42392			// empty tracks are forbidden, so keep at least one keyframe
42393			if ( from >= to ) {
42394
42395				to = Math.max( to, 1 );
42396				from = to - 1;
42397
42398			}
42399
42400			const stride = this.getValueSize();
42401			this.times = times.slice( from, to );
42402			this.values = this.values.slice( from * stride, to * stride );
42403
42404		}
42405
42406		return this;
42407
42408	}
42409
42410	// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
42411	validate() {
42412
42413		let valid = true;
42414
42415		const valueSize = this.getValueSize();
42416		if ( valueSize - Math.floor( valueSize ) !== 0 ) {
42417
42418			console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
42419			valid = false;
42420
42421		}
42422
42423		const times = this.times,
42424			values = this.values,
42425
42426			nKeys = times.length;
42427
42428		if ( nKeys === 0 ) {
42429
42430			console.error( 'THREE.KeyframeTrack: Track is empty.', this );
42431			valid = false;
42432
42433		}
42434
42435		let prevTime = null;
42436
42437		for ( let i = 0; i !== nKeys; i ++ ) {
42438
42439			const currTime = times[ i ];
42440
42441			if ( typeof currTime === 'number' && isNaN( currTime ) ) {
42442
42443				console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
42444				valid = false;
42445				break;
42446
42447			}
42448
42449			if ( prevTime !== null && prevTime > currTime ) {
42450
42451				console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
42452				valid = false;
42453				break;
42454
42455			}
42456
42457			prevTime = currTime;
42458
42459		}
42460
42461		if ( values !== undefined ) {
42462
42463			if ( isTypedArray( values ) ) {
42464
42465				for ( let i = 0, n = values.length; i !== n; ++ i ) {
42466
42467					const value = values[ i ];
42468
42469					if ( isNaN( value ) ) {
42470
42471						console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
42472						valid = false;
42473						break;
42474
42475					}
42476
42477				}
42478
42479			}
42480
42481		}
42482
42483		return valid;
42484
42485	}
42486
42487	// removes equivalent sequential keys as common in morph target sequences
42488	// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
42489	optimize() {
42490
42491		// times or values may be shared with other tracks, so overwriting is unsafe
42492		const times = this.times.slice(),
42493			values = this.values.slice(),
42494			stride = this.getValueSize(),
42495
42496			smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
42497
42498			lastIndex = times.length - 1;
42499
42500		let writeIndex = 1;
42501
42502		for ( let i = 1; i < lastIndex; ++ i ) {
42503
42504			let keep = false;
42505
42506			const time = times[ i ];
42507			const timeNext = times[ i + 1 ];
42508
42509			// remove adjacent keyframes scheduled at the same time
42510
42511			if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
42512
42513				if ( ! smoothInterpolation ) {
42514
42515					// remove unnecessary keyframes same as their neighbors
42516
42517					const offset = i * stride,
42518						offsetP = offset - stride,
42519						offsetN = offset + stride;
42520
42521					for ( let j = 0; j !== stride; ++ j ) {
42522
42523						const value = values[ offset + j ];
42524
42525						if ( value !== values[ offsetP + j ] ||
42526							value !== values[ offsetN + j ] ) {
42527
42528							keep = true;
42529							break;
42530
42531						}
42532
42533					}
42534
42535				} else {
42536
42537					keep = true;
42538
42539				}
42540
42541			}
42542
42543			// in-place compaction
42544
42545			if ( keep ) {
42546
42547				if ( i !== writeIndex ) {
42548
42549					times[ writeIndex ] = times[ i ];
42550
42551					const readOffset = i * stride,
42552						writeOffset = writeIndex * stride;
42553
42554					for ( let j = 0; j !== stride; ++ j ) {
42555
42556						values[ writeOffset + j ] = values[ readOffset + j ];
42557
42558					}
42559
42560				}
42561
42562				++ writeIndex;
42563
42564			}
42565
42566		}
42567
42568		// flush last keyframe (compaction looks ahead)
42569
42570		if ( lastIndex > 0 ) {
42571
42572			times[ writeIndex ] = times[ lastIndex ];
42573
42574			for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
42575
42576				values[ writeOffset + j ] = values[ readOffset + j ];
42577
42578			}
42579
42580			++ writeIndex;
42581
42582		}
42583
42584		if ( writeIndex !== times.length ) {
42585
42586			this.times = times.slice( 0, writeIndex );
42587			this.values = values.slice( 0, writeIndex * stride );
42588
42589		} else {
42590
42591			this.times = times;
42592			this.values = values;
42593
42594		}
42595
42596		return this;
42597
42598	}
42599
42600	clone() {
42601
42602		const times = this.times.slice();
42603		const values = this.values.slice();
42604
42605		const TypedKeyframeTrack = this.constructor;
42606		const track = new TypedKeyframeTrack( this.name, times, values );
42607
42608		// Interpolant argument to constructor is not saved, so copy the factory method directly.
42609		track.createInterpolant = this.createInterpolant;
42610
42611		return track;
42612
42613	}
42614
42615}
42616
42617KeyframeTrack.prototype.TimeBufferType = Float32Array;
42618KeyframeTrack.prototype.ValueBufferType = Float32Array;
42619KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42620
42621/**
42622 * A Track of Boolean keyframe values.
42623 */
42624class BooleanKeyframeTrack extends KeyframeTrack {}
42625
42626BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';
42627BooleanKeyframeTrack.prototype.ValueBufferType = Array;
42628BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42629BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42630BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42631
42632/**
42633 * A Track of keyframe values that represent color.
42634 */
42635class ColorKeyframeTrack extends KeyframeTrack {}
42636
42637ColorKeyframeTrack.prototype.ValueTypeName = 'color';
42638
42639/**
42640 * A Track of numeric keyframe values.
42641 */
42642class NumberKeyframeTrack extends KeyframeTrack {}
42643
42644NumberKeyframeTrack.prototype.ValueTypeName = 'number';
42645
42646/**
42647 * Spherical linear unit quaternion interpolant.
42648 */
42649
42650class QuaternionLinearInterpolant extends Interpolant {
42651
42652	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42653
42654		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42655
42656	}
42657
42658	interpolate_( i1, t0, t, t1 ) {
42659
42660		const result = this.resultBuffer,
42661			values = this.sampleValues,
42662			stride = this.valueSize,
42663
42664			alpha = ( t - t0 ) / ( t1 - t0 );
42665
42666		let offset = i1 * stride;
42667
42668		for ( let end = offset + stride; offset !== end; offset += 4 ) {
42669
42670			Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
42671
42672		}
42673
42674		return result;
42675
42676	}
42677
42678}
42679
42680/**
42681 * A Track of quaternion keyframe values.
42682 */
42683class QuaternionKeyframeTrack extends KeyframeTrack {
42684
42685	InterpolantFactoryMethodLinear( result ) {
42686
42687		return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
42688
42689	}
42690
42691}
42692
42693QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';
42694// ValueBufferType is inherited
42695QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42696QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42697
42698/**
42699 * A Track that interpolates Strings
42700 */
42701class StringKeyframeTrack extends KeyframeTrack {}
42702
42703StringKeyframeTrack.prototype.ValueTypeName = 'string';
42704StringKeyframeTrack.prototype.ValueBufferType = Array;
42705StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42706StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42707StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42708
42709/**
42710 * A Track of vectored keyframe values.
42711 */
42712class VectorKeyframeTrack extends KeyframeTrack {}
42713
42714VectorKeyframeTrack.prototype.ValueTypeName = 'vector';
42715
42716class AnimationClip {
42717
42718	constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
42719
42720		this.name = name;
42721		this.tracks = tracks;
42722		this.duration = duration;
42723		this.blendMode = blendMode;
42724
42725		this.uuid = generateUUID();
42726
42727		// this means it should figure out its duration by scanning the tracks
42728		if ( this.duration < 0 ) {
42729
42730			this.resetDuration();
42731
42732		}
42733
42734	}
42735
42736
42737	static parse( json ) {
42738
42739		const tracks = [],
42740			jsonTracks = json.tracks,
42741			frameTime = 1.0 / ( json.fps || 1.0 );
42742
42743		for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
42744
42745			tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
42746
42747		}
42748
42749		const clip = new this( json.name, json.duration, tracks, json.blendMode );
42750		clip.uuid = json.uuid;
42751
42752		return clip;
42753
42754	}
42755
42756	static toJSON( clip ) {
42757
42758		const tracks = [],
42759			clipTracks = clip.tracks;
42760
42761		const json = {
42762
42763			'name': clip.name,
42764			'duration': clip.duration,
42765			'tracks': tracks,
42766			'uuid': clip.uuid,
42767			'blendMode': clip.blendMode
42768
42769		};
42770
42771		for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
42772
42773			tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
42774
42775		}
42776
42777		return json;
42778
42779	}
42780
42781	static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {
42782
42783		const numMorphTargets = morphTargetSequence.length;
42784		const tracks = [];
42785
42786		for ( let i = 0; i < numMorphTargets; i ++ ) {
42787
42788			let times = [];
42789			let values = [];
42790
42791			times.push(
42792				( i + numMorphTargets - 1 ) % numMorphTargets,
42793				i,
42794				( i + 1 ) % numMorphTargets );
42795
42796			values.push( 0, 1, 0 );
42797
42798			const order = getKeyframeOrder( times );
42799			times = sortedArray( times, 1, order );
42800			values = sortedArray( values, 1, order );
42801
42802			// if there is a key at the first frame, duplicate it as the
42803			// last frame as well for perfect loop.
42804			if ( ! noLoop && times[ 0 ] === 0 ) {
42805
42806				times.push( numMorphTargets );
42807				values.push( values[ 0 ] );
42808
42809			}
42810
42811			tracks.push(
42812				new NumberKeyframeTrack(
42813					'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
42814					times, values
42815				).scale( 1.0 / fps ) );
42816
42817		}
42818
42819		return new this( name, - 1, tracks );
42820
42821	}
42822
42823	static findByName( objectOrClipArray, name ) {
42824
42825		let clipArray = objectOrClipArray;
42826
42827		if ( ! Array.isArray( objectOrClipArray ) ) {
42828
42829			const o = objectOrClipArray;
42830			clipArray = o.geometry && o.geometry.animations || o.animations;
42831
42832		}
42833
42834		for ( let i = 0; i < clipArray.length; i ++ ) {
42835
42836			if ( clipArray[ i ].name === name ) {
42837
42838				return clipArray[ i ];
42839
42840			}
42841
42842		}
42843
42844		return null;
42845
42846	}
42847
42848	static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {
42849
42850		const animationToMorphTargets = {};
42851
42852		// tested with https://regex101.com/ on trick sequences
42853		// such flamingo_flyA_003, flamingo_run1_003, crdeath0059
42854		const pattern = /^([\w-]*?)([\d]+)$/;
42855
42856		// sort morph target names into animation groups based
42857		// patterns like Walk_001, Walk_002, Run_001, Run_002
42858		for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
42859
42860			const morphTarget = morphTargets[ i ];
42861			const parts = morphTarget.name.match( pattern );
42862
42863			if ( parts && parts.length > 1 ) {
42864
42865				const name = parts[ 1 ];
42866
42867				let animationMorphTargets = animationToMorphTargets[ name ];
42868
42869				if ( ! animationMorphTargets ) {
42870
42871					animationToMorphTargets[ name ] = animationMorphTargets = [];
42872
42873				}
42874
42875				animationMorphTargets.push( morphTarget );
42876
42877			}
42878
42879		}
42880
42881		const clips = [];
42882
42883		for ( const name in animationToMorphTargets ) {
42884
42885			clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
42886
42887		}
42888
42889		return clips;
42890
42891	}
42892
42893	// parse the animation.hierarchy format
42894	static parseAnimation( animation, bones ) {
42895
42896		if ( ! animation ) {
42897
42898			console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
42899			return null;
42900
42901		}
42902
42903		const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
42904
42905			// only return track if there are actually keys.
42906			if ( animationKeys.length !== 0 ) {
42907
42908				const times = [];
42909				const values = [];
42910
42911				flattenJSON( animationKeys, times, values, propertyName );
42912
42913				// empty keys are filtered out, so check again
42914				if ( times.length !== 0 ) {
42915
42916					destTracks.push( new trackType( trackName, times, values ) );
42917
42918				}
42919
42920			}
42921
42922		};
42923
42924		const tracks = [];
42925
42926		const clipName = animation.name || 'default';
42927		const fps = animation.fps || 30;
42928		const blendMode = animation.blendMode;
42929
42930		// automatic length determination in AnimationClip.
42931		let duration = animation.length || - 1;
42932
42933		const hierarchyTracks = animation.hierarchy || [];
42934
42935		for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
42936
42937			const animationKeys = hierarchyTracks[ h ].keys;
42938
42939			// skip empty tracks
42940			if ( ! animationKeys || animationKeys.length === 0 ) continue;
42941
42942			// process morph targets
42943			if ( animationKeys[ 0 ].morphTargets ) {
42944
42945				// figure out all morph targets used in this track
42946				const morphTargetNames = {};
42947
42948				let k;
42949
42950				for ( k = 0; k < animationKeys.length; k ++ ) {
42951
42952					if ( animationKeys[ k ].morphTargets ) {
42953
42954						for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
42955
42956							morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
42957
42958						}
42959
42960					}
42961
42962				}
42963
42964				// create a track for each morph target with all zero
42965				// morphTargetInfluences except for the keys in which
42966				// the morphTarget is named.
42967				for ( const morphTargetName in morphTargetNames ) {
42968
42969					const times = [];
42970					const values = [];
42971
42972					for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
42973
42974						const animationKey = animationKeys[ k ];
42975
42976						times.push( animationKey.time );
42977						values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
42978
42979					}
42980
42981					tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
42982
42983				}
42984
42985				duration = morphTargetNames.length * fps;
42986
42987			} else {
42988
42989				// ...assume skeletal animation
42990
42991				const boneName = '.bones[' + bones[ h ].name + ']';
42992
42993				addNonemptyTrack(
42994					VectorKeyframeTrack, boneName + '.position',
42995					animationKeys, 'pos', tracks );
42996
42997				addNonemptyTrack(
42998					QuaternionKeyframeTrack, boneName + '.quaternion',
42999					animationKeys, 'rot', tracks );
43000
43001				addNonemptyTrack(
43002					VectorKeyframeTrack, boneName + '.scale',
43003					animationKeys, 'scl', tracks );
43004
43005			}
43006
43007		}
43008
43009		if ( tracks.length === 0 ) {
43010
43011			return null;
43012
43013		}
43014
43015		const clip = new this( clipName, duration, tracks, blendMode );
43016
43017		return clip;
43018
43019	}
43020
43021	resetDuration() {
43022
43023		const tracks = this.tracks;
43024		let duration = 0;
43025
43026		for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
43027
43028			const track = this.tracks[ i ];
43029
43030			duration = Math.max( duration, track.times[ track.times.length - 1 ] );
43031
43032		}
43033
43034		this.duration = duration;
43035
43036		return this;
43037
43038	}
43039
43040	trim() {
43041
43042		for ( let i = 0; i < this.tracks.length; i ++ ) {
43043
43044			this.tracks[ i ].trim( 0, this.duration );
43045
43046		}
43047
43048		return this;
43049
43050	}
43051
43052	validate() {
43053
43054		let valid = true;
43055
43056		for ( let i = 0; i < this.tracks.length; i ++ ) {
43057
43058			valid = valid && this.tracks[ i ].validate();
43059
43060		}
43061
43062		return valid;
43063
43064	}
43065
43066	optimize() {
43067
43068		for ( let i = 0; i < this.tracks.length; i ++ ) {
43069
43070			this.tracks[ i ].optimize();
43071
43072		}
43073
43074		return this;
43075
43076	}
43077
43078	clone() {
43079
43080		const tracks = [];
43081
43082		for ( let i = 0; i < this.tracks.length; i ++ ) {
43083
43084			tracks.push( this.tracks[ i ].clone() );
43085
43086		}
43087
43088		return new this.constructor( this.name, this.duration, tracks, this.blendMode );
43089
43090	}
43091
43092	toJSON() {
43093
43094		return this.constructor.toJSON( this );
43095
43096	}
43097
43098}
43099
43100function getTrackTypeForValueTypeName( typeName ) {
43101
43102	switch ( typeName.toLowerCase() ) {
43103
43104		case 'scalar':
43105		case 'double':
43106		case 'float':
43107		case 'number':
43108		case 'integer':
43109
43110			return NumberKeyframeTrack;
43111
43112		case 'vector':
43113		case 'vector2':
43114		case 'vector3':
43115		case 'vector4':
43116
43117			return VectorKeyframeTrack;
43118
43119		case 'color':
43120
43121			return ColorKeyframeTrack;
43122
43123		case 'quaternion':
43124
43125			return QuaternionKeyframeTrack;
43126
43127		case 'bool':
43128		case 'boolean':
43129
43130			return BooleanKeyframeTrack;
43131
43132		case 'string':
43133
43134			return StringKeyframeTrack;
43135
43136	}
43137
43138	throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
43139
43140}
43141
43142function parseKeyframeTrack( json ) {
43143
43144	if ( json.type === undefined ) {
43145
43146		throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
43147
43148	}
43149
43150	const trackType = getTrackTypeForValueTypeName( json.type );
43151
43152	if ( json.times === undefined ) {
43153
43154		const times = [], values = [];
43155
43156		flattenJSON( json.keys, times, values, 'value' );
43157
43158		json.times = times;
43159		json.values = values;
43160
43161	}
43162
43163	// derived classes can define a static parse method
43164	if ( trackType.parse !== undefined ) {
43165
43166		return trackType.parse( json );
43167
43168	} else {
43169
43170		// by default, we assume a constructor compatible with the base
43171		return new trackType( json.name, json.times, json.values, json.interpolation );
43172
43173	}
43174
43175}
43176
43177const Cache = {
43178
43179	enabled: false,
43180
43181	files: {},
43182
43183	add: function ( key, file ) {
43184
43185		if ( this.enabled === false ) return;
43186
43187		// console.log( 'THREE.Cache', 'Adding key:', key );
43188
43189		this.files[ key ] = file;
43190
43191	},
43192
43193	get: function ( key ) {
43194
43195		if ( this.enabled === false ) return;
43196
43197		// console.log( 'THREE.Cache', 'Checking key:', key );
43198
43199		return this.files[ key ];
43200
43201	},
43202
43203	remove: function ( key ) {
43204
43205		delete this.files[ key ];
43206
43207	},
43208
43209	clear: function () {
43210
43211		this.files = {};
43212
43213	}
43214
43215};
43216
43217class LoadingManager {
43218
43219	constructor( onLoad, onProgress, onError ) {
43220
43221		const scope = this;
43222
43223		let isLoading = false;
43224		let itemsLoaded = 0;
43225		let itemsTotal = 0;
43226		let urlModifier = undefined;
43227		const handlers = [];
43228
43229		// Refer to #5689 for the reason why we don't set .onStart
43230		// in the constructor
43231
43232		this.onStart = undefined;
43233		this.onLoad = onLoad;
43234		this.onProgress = onProgress;
43235		this.onError = onError;
43236
43237		this.itemStart = function ( url ) {
43238
43239			itemsTotal ++;
43240
43241			if ( isLoading === false ) {
43242
43243				if ( scope.onStart !== undefined ) {
43244
43245					scope.onStart( url, itemsLoaded, itemsTotal );
43246
43247				}
43248
43249			}
43250
43251			isLoading = true;
43252
43253		};
43254
43255		this.itemEnd = function ( url ) {
43256
43257			itemsLoaded ++;
43258
43259			if ( scope.onProgress !== undefined ) {
43260
43261				scope.onProgress( url, itemsLoaded, itemsTotal );
43262
43263			}
43264
43265			if ( itemsLoaded === itemsTotal ) {
43266
43267				isLoading = false;
43268
43269				if ( scope.onLoad !== undefined ) {
43270
43271					scope.onLoad();
43272
43273				}
43274
43275			}
43276
43277		};
43278
43279		this.itemError = function ( url ) {
43280
43281			if ( scope.onError !== undefined ) {
43282
43283				scope.onError( url );
43284
43285			}
43286
43287		};
43288
43289		this.resolveURL = function ( url ) {
43290
43291			if ( urlModifier ) {
43292
43293				return urlModifier( url );
43294
43295			}
43296
43297			return url;
43298
43299		};
43300
43301		this.setURLModifier = function ( transform ) {
43302
43303			urlModifier = transform;
43304
43305			return this;
43306
43307		};
43308
43309		this.addHandler = function ( regex, loader ) {
43310
43311			handlers.push( regex, loader );
43312
43313			return this;
43314
43315		};
43316
43317		this.removeHandler = function ( regex ) {
43318
43319			const index = handlers.indexOf( regex );
43320
43321			if ( index !== - 1 ) {
43322
43323				handlers.splice( index, 2 );
43324
43325			}
43326
43327			return this;
43328
43329		};
43330
43331		this.getHandler = function ( file ) {
43332
43333			for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
43334
43335				const regex = handlers[ i ];
43336				const loader = handlers[ i + 1 ];
43337
43338				if ( regex.global ) regex.lastIndex = 0; // see #17920
43339
43340				if ( regex.test( file ) ) {
43341
43342					return loader;
43343
43344				}
43345
43346			}
43347
43348			return null;
43349
43350		};
43351
43352	}
43353
43354}
43355
43356const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();
43357
43358class Loader {
43359
43360	constructor( manager ) {
43361
43362		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
43363
43364		this.crossOrigin = 'anonymous';
43365		this.withCredentials = false;
43366		this.path = '';
43367		this.resourcePath = '';
43368		this.requestHeader = {};
43369
43370	}
43371
43372	load( /* url, onLoad, onProgress, onError */ ) {}
43373
43374	loadAsync( url, onProgress ) {
43375
43376		const scope = this;
43377
43378		return new Promise( function ( resolve, reject ) {
43379
43380			scope.load( url, resolve, onProgress, reject );
43381
43382		} );
43383
43384	}
43385
43386	parse( /* data */ ) {}
43387
43388	setCrossOrigin( crossOrigin ) {
43389
43390		this.crossOrigin = crossOrigin;
43391		return this;
43392
43393	}
43394
43395	setWithCredentials( value ) {
43396
43397		this.withCredentials = value;
43398		return this;
43399
43400	}
43401
43402	setPath( path ) {
43403
43404		this.path = path;
43405		return this;
43406
43407	}
43408
43409	setResourcePath( resourcePath ) {
43410
43411		this.resourcePath = resourcePath;
43412		return this;
43413
43414	}
43415
43416	setRequestHeader( requestHeader ) {
43417
43418		this.requestHeader = requestHeader;
43419		return this;
43420
43421	}
43422
43423}
43424
43425Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
43426
43427const loading = {};
43428
43429class HttpError extends Error {
43430
43431	constructor( message, response ) {
43432
43433		super( message );
43434		this.response = response;
43435
43436	}
43437
43438}
43439
43440class FileLoader extends Loader {
43441
43442	constructor( manager ) {
43443
43444		super( manager );
43445
43446	}
43447
43448	load( url, onLoad, onProgress, onError ) {
43449
43450		if ( url === undefined ) url = '';
43451
43452		if ( this.path !== undefined ) url = this.path + url;
43453
43454		url = this.manager.resolveURL( url );
43455
43456		const cached = Cache.get( url );
43457
43458		if ( cached !== undefined ) {
43459
43460			this.manager.itemStart( url );
43461
43462			setTimeout( () => {
43463
43464				if ( onLoad ) onLoad( cached );
43465
43466				this.manager.itemEnd( url );
43467
43468			}, 0 );
43469
43470			return cached;
43471
43472		}
43473
43474		// Check if request is duplicate
43475
43476		if ( loading[ url ] !== undefined ) {
43477
43478			loading[ url ].push( {
43479
43480				onLoad: onLoad,
43481				onProgress: onProgress,
43482				onError: onError
43483
43484			} );
43485
43486			return;
43487
43488		}
43489
43490		// Initialise array for duplicate requests
43491		loading[ url ] = [];
43492
43493		loading[ url ].push( {
43494			onLoad: onLoad,
43495			onProgress: onProgress,
43496			onError: onError,
43497		} );
43498
43499		// create request
vendor: 11,646 bytes, lines 43500-44091
43500		const req = new Request( url, {
43501			headers: new Headers( this.requestHeader ),
43502			credentials: this.withCredentials ? 'include' : 'same-origin',
43503			// An abort controller could be added within a future PR
43504		} );
43505
43506		// record states ( avoid data race )
43507		const mimeType = this.mimeType;
43508		const responseType = this.responseType;
43509
43510		// start the fetch
43511		fetch( req )
43512			.then( response => {
43513
43514				if ( response.status === 200 || response.status === 0 ) {
43515
43516					// Some browsers return HTTP Status 0 when using non-http protocol
43517					// e.g. 'file://' or 'data://'. Handle as success.
43518
43519					if ( response.status === 0 ) {
43520
43521						console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
43522
43523					}
43524
43525					// Workaround: Checking if response.body === undefined for Alipay browser #23548
43526
43527					if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) {
43528
43529						return response;
43530
43531					}
43532
43533					const callbacks = loading[ url ];
43534					const reader = response.body.getReader();
43535
43536					// Nginx needs X-File-Size check
43537					// https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content
43538					const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' );
43539					const total = contentLength ? parseInt( contentLength ) : 0;
43540					const lengthComputable = total !== 0;
43541					let loaded = 0;
43542
43543					// periodically read data into the new stream tracking while download progress
43544					const stream = new ReadableStream( {
43545						start( controller ) {
43546
43547							readData();
43548
43549							function readData() {
43550
43551								reader.read().then( ( { done, value } ) => {
43552
43553									if ( done ) {
43554
43555										controller.close();
43556
43557									} else {
43558
43559										loaded += value.byteLength;
43560
43561										const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );
43562										for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43563
43564											const callback = callbacks[ i ];
43565											if ( callback.onProgress ) callback.onProgress( event );
43566
43567										}
43568
43569										controller.enqueue( value );
43570										readData();
43571
43572									}
43573
43574								} );
43575
43576							}
43577
43578						}
43579
43580					} );
43581
43582					return new Response( stream );
43583
43584				} else {
43585
43586					throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response );
43587
43588				}
43589
43590			} )
43591			.then( response => {
43592
43593				switch ( responseType ) {
43594
43595					case 'arraybuffer':
43596
43597						return response.arrayBuffer();
43598
43599					case 'blob':
43600
43601						return response.blob();
43602
43603					case 'document':
43604
43605						return response.text()
43606							.then( text => {
43607
43608								const parser = new DOMParser();
43609								return parser.parseFromString( text, mimeType );
43610
43611							} );
43612
43613					case 'json':
43614
43615						return response.json();
43616
43617					default:
43618
43619						if ( mimeType === undefined ) {
43620
43621							return response.text();
43622
43623						} else {
43624
43625							// sniff encoding
43626							const re = /charset="?([^;"\s]*)"?/i;
43627							const exec = re.exec( mimeType );
43628							const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined;
43629							const decoder = new TextDecoder( label );
43630							return response.arrayBuffer().then( ab => decoder.decode( ab ) );
43631
43632						}
43633
43634				}
43635
43636			} )
43637			.then( data => {
43638
43639				// Add to cache only on HTTP success, so that we do not cache
43640				// error response bodies as proper responses to requests.
43641				Cache.add( url, data );
43642
43643				const callbacks = loading[ url ];
43644				delete loading[ url ];
43645
43646				for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43647
43648					const callback = callbacks[ i ];
43649					if ( callback.onLoad ) callback.onLoad( data );
43650
43651				}
43652
43653			} )
43654			.catch( err => {
43655
43656				// Abort errors and other errors are handled the same
43657
43658				const callbacks = loading[ url ];
43659
43660				if ( callbacks === undefined ) {
43661
43662					// When onLoad was called and url was deleted in `loading`
43663					this.manager.itemError( url );
43664					throw err;
43665
43666				}
43667
43668				delete loading[ url ];
43669
43670				for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43671
43672					const callback = callbacks[ i ];
43673					if ( callback.onError ) callback.onError( err );
43674
43675				}
43676
43677				this.manager.itemError( url );
43678
43679			} )
43680			.finally( () => {
43681
43682				this.manager.itemEnd( url );
43683
43684			} );
43685
43686		this.manager.itemStart( url );
43687
43688	}
43689
43690	setResponseType( value ) {
43691
43692		this.responseType = value;
43693		return this;
43694
43695	}
43696
43697	setMimeType( value ) {
43698
43699		this.mimeType = value;
43700		return this;
43701
43702	}
43703
43704}
43705
43706class AnimationLoader extends Loader {
43707
43708	constructor( manager ) {
43709
43710		super( manager );
43711
43712	}
43713
43714	load( url, onLoad, onProgress, onError ) {
43715
43716		const scope = this;
43717
43718		const loader = new FileLoader( this.manager );
43719		loader.setPath( this.path );
43720		loader.setRequestHeader( this.requestHeader );
43721		loader.setWithCredentials( this.withCredentials );
43722		loader.load( url, function ( text ) {
43723
43724			try {
43725
43726				onLoad( scope.parse( JSON.parse( text ) ) );
43727
43728			} catch ( e ) {
43729
43730				if ( onError ) {
43731
43732					onError( e );
43733
43734				} else {
43735
43736					console.error( e );
43737
43738				}
43739
43740				scope.manager.itemError( url );
43741
43742			}
43743
43744		}, onProgress, onError );
43745
43746	}
43747
43748	parse( json ) {
43749
43750		const animations = [];
43751
43752		for ( let i = 0; i < json.length; i ++ ) {
43753
43754			const clip = AnimationClip.parse( json[ i ] );
43755
43756			animations.push( clip );
43757
43758		}
43759
43760		return animations;
43761
43762	}
43763
43764}
43765
43766/**
43767 * Abstract Base class to block based textures loader (dds, pvr, ...)
43768 *
43769 * Sub classes have to implement the parse() method which will be used in load().
43770 */
43771
43772class CompressedTextureLoader extends Loader {
43773
43774	constructor( manager ) {
43775
43776		super( manager );
43777
43778	}
43779
43780	load( url, onLoad, onProgress, onError ) {
43781
43782		const scope = this;
43783
43784		const images = [];
43785
43786		const texture = new CompressedTexture();
43787
43788		const loader = new FileLoader( this.manager );
43789		loader.setPath( this.path );
43790		loader.setResponseType( 'arraybuffer' );
43791		loader.setRequestHeader( this.requestHeader );
43792		loader.setWithCredentials( scope.withCredentials );
43793
43794		let loaded = 0;
43795
43796		function loadTexture( i ) {
43797
43798			loader.load( url[ i ], function ( buffer ) {
43799
43800				const texDatas = scope.parse( buffer, true );
43801
43802				images[ i ] = {
43803					width: texDatas.width,
43804					height: texDatas.height,
43805					format: texDatas.format,
43806					mipmaps: texDatas.mipmaps
43807				};
43808
43809				loaded += 1;
43810
43811				if ( loaded === 6 ) {
43812
43813					if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
43814
43815					texture.image = images;
43816					texture.format = texDatas.format;
43817					texture.needsUpdate = true;
43818
43819					if ( onLoad ) onLoad( texture );
43820
43821				}
43822
43823			}, onProgress, onError );
43824
43825		}
43826
43827		if ( Array.isArray( url ) ) {
43828
43829			for ( let i = 0, il = url.length; i < il; ++ i ) {
43830
43831				loadTexture( i );
43832
43833			}
43834
43835		} else {
43836
43837			// compressed cubemap texture stored in a single DDS file
43838
43839			loader.load( url, function ( buffer ) {
43840
43841				const texDatas = scope.parse( buffer, true );
43842
43843				if ( texDatas.isCubemap ) {
43844
43845					const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
43846
43847					for ( let f = 0; f < faces; f ++ ) {
43848
43849						images[ f ] = { mipmaps: [] };
43850
43851						for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
43852
43853							images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
43854							images[ f ].format = texDatas.format;
43855							images[ f ].width = texDatas.width;
43856							images[ f ].height = texDatas.height;
43857
43858						}
43859
43860					}
43861
43862					texture.image = images;
43863
43864				} else {
43865
43866					texture.image.width = texDatas.width;
43867					texture.image.height = texDatas.height;
43868					texture.mipmaps = texDatas.mipmaps;
43869
43870				}
43871
43872				if ( texDatas.mipmapCount === 1 ) {
43873
43874					texture.minFilter = LinearFilter;
43875
43876				}
43877
43878				texture.format = texDatas.format;
43879				texture.needsUpdate = true;
43880
43881				if ( onLoad ) onLoad( texture );
43882
43883			}, onProgress, onError );
43884
43885		}
43886
43887		return texture;
43888
43889	}
43890
43891}
43892
43893class ImageLoader extends Loader {
43894
43895	constructor( manager ) {
43896
43897		super( manager );
43898
43899	}
43900
43901	load( url, onLoad, onProgress, onError ) {
43902
43903		if ( this.path !== undefined ) url = this.path + url;
43904
43905		url = this.manager.resolveURL( url );
43906
43907		const scope = this;
43908
43909		const cached = Cache.get( url );
43910
43911		if ( cached !== undefined ) {
43912
43913			scope.manager.itemStart( url );
43914
43915			setTimeout( function () {
43916
43917				if ( onLoad ) onLoad( cached );
43918
43919				scope.manager.itemEnd( url );
43920
43921			}, 0 );
43922
43923			return cached;
43924
43925		}
43926
43927		const image = createElementNS( 'img' );
43928
43929		function onImageLoad() {
43930
43931			removeEventListeners();
43932
43933			Cache.add( url, this );
43934
43935			if ( onLoad ) onLoad( this );
43936
43937			scope.manager.itemEnd( url );
43938
43939		}
43940
43941		function onImageError( event ) {
43942
43943			removeEventListeners();
43944
43945			if ( onError ) onError( event );
43946
43947			scope.manager.itemError( url );
43948			scope.manager.itemEnd( url );
43949
43950		}
43951
43952		function removeEventListeners() {
43953
43954			image.removeEventListener( 'load', onImageLoad, false );
43955			image.removeEventListener( 'error', onImageError, false );
43956
43957		}
43958
43959		image.addEventListener( 'load', onImageLoad, false );
43960		image.addEventListener( 'error', onImageError, false );
43961
43962		if ( url.slice( 0, 5 ) !== 'data:' ) {
43963
43964			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
43965
43966		}
43967
43968		scope.manager.itemStart( url );
43969
43970		image.src = url;
43971
43972		return image;
43973
43974	}
43975
43976}
43977
43978class CubeTextureLoader extends Loader {
43979
43980	constructor( manager ) {
43981
43982		super( manager );
43983
43984	}
43985
43986	load( urls, onLoad, onProgress, onError ) {
43987
43988		const texture = new CubeTexture();
43989		texture.colorSpace = SRGBColorSpace;
43990
43991		const loader = new ImageLoader( this.manager );
43992		loader.setCrossOrigin( this.crossOrigin );
43993		loader.setPath( this.path );
43994
43995		let loaded = 0;
43996
43997		function loadTexture( i ) {
43998
43999			loader.load( urls[ i ], function ( image ) {
44000
44001				texture.images[ i ] = image;
44002
44003				loaded ++;
44004
44005				if ( loaded === 6 ) {
44006
44007					texture.needsUpdate = true;
44008
44009					if ( onLoad ) onLoad( texture );
44010
44011				}
44012
44013			}, undefined, onError );
44014
44015		}
44016
44017		for ( let i = 0; i < urls.length; ++ i ) {
44018
44019			loadTexture( i );
44020
44021		}
44022
44023		return texture;
44024
44025	}
44026
44027}
44028
44029/**
44030 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
44031 *
44032 * Sub classes have to implement the parse() method which will be used in load().
44033 */
44034
44035class DataTextureLoader extends Loader {
44036
44037	constructor( manager ) {
44038
44039		super( manager );
44040
44041	}
44042
44043	load( url, onLoad, onProgress, onError ) {
44044
44045		const scope = this;
44046
44047		const texture = new DataTexture();
44048
44049		const loader = new FileLoader( this.manager );
44050		loader.setResponseType( 'arraybuffer' );
44051		loader.setRequestHeader( this.requestHeader );
44052		loader.setPath( this.path );
44053		loader.setWithCredentials( scope.withCredentials );
44054		loader.load( url, function ( buffer ) {
44055
44056			let texData;
44057
44058			try {
44059
44060				texData = scope.parse( buffer );
44061
44062			} catch ( error ) {
44063
44064				if ( onError !== undefined ) {
44065
44066					onError( error );
44067
44068				} else {
44069
44070					console.error( error );
44071					return;
44072
44073				}
44074
44075			}
44076
44077			if ( texData.image !== undefined ) {
44078
44079				texture.image = texData.image;
44080
44081			} else if ( texData.data !== undefined ) {
44082
44083				texture.image.width = texData.width;
44084				texture.image.height = texData.height;
44085				texture.image.data = texData.data;
44086
44087			}
44088
44089			texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
44090			texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
44091
vendor: 5,358 bytes, lines 44092-44382
44092			texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
44093			texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
44094
44095			texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
44096
44097			if ( texData.colorSpace !== undefined ) {
44098
44099				texture.colorSpace = texData.colorSpace;
44100
44101			} else if ( texData.encoding !== undefined ) { // @deprecated, r152
44102
44103				texture.encoding = texData.encoding;
44104
44105			}
44106
44107			if ( texData.flipY !== undefined ) {
44108
44109				texture.flipY = texData.flipY;
44110
44111			}
44112
44113			if ( texData.format !== undefined ) {
44114
44115				texture.format = texData.format;
44116
44117			}
44118
44119			if ( texData.type !== undefined ) {
44120
44121				texture.type = texData.type;
44122
44123			}
44124
44125			if ( texData.mipmaps !== undefined ) {
44126
44127				texture.mipmaps = texData.mipmaps;
44128				texture.minFilter = LinearMipmapLinearFilter; // presumably...
44129
44130			}
44131
44132			if ( texData.mipmapCount === 1 ) {
44133
44134				texture.minFilter = LinearFilter;
44135
44136			}
44137
44138			if ( texData.generateMipmaps !== undefined ) {
44139
44140				texture.generateMipmaps = texData.generateMipmaps;
44141
44142			}
44143
44144			texture.needsUpdate = true;
44145
44146			if ( onLoad ) onLoad( texture, texData );
44147
44148		}, onProgress, onError );
44149
44150
44151		return texture;
44152
44153	}
44154
44155}
44156
44157class TextureLoader extends Loader {
44158
44159	constructor( manager ) {
44160
44161		super( manager );
44162
44163	}
44164
44165	load( url, onLoad, onProgress, onError ) {
44166
44167		const texture = new Texture();
44168
44169		const loader = new ImageLoader( this.manager );
44170		loader.setCrossOrigin( this.crossOrigin );
44171		loader.setPath( this.path );
44172
44173		loader.load( url, function ( image ) {
44174
44175			texture.image = image;
44176			texture.needsUpdate = true;
44177
44178			if ( onLoad !== undefined ) {
44179
44180				onLoad( texture );
44181
44182			}
44183
44184		}, onProgress, onError );
44185
44186		return texture;
44187
44188	}
44189
44190}
44191
44192class Light extends Object3D {
44193
44194	constructor( color, intensity = 1 ) {
44195
44196		super();
44197
44198		this.isLight = true;
44199
44200		this.type = 'Light';
44201
44202		this.color = new Color( color );
44203		this.intensity = intensity;
44204
44205	}
44206
44207	dispose() {
44208
44209		// Empty here in base class; some subclasses override.
44210
44211	}
44212
44213	copy( source, recursive ) {
44214
44215		super.copy( source, recursive );
44216
44217		this.color.copy( source.color );
44218		this.intensity = source.intensity;
44219
44220		return this;
44221
44222	}
44223
44224	toJSON( meta ) {
44225
44226		const data = super.toJSON( meta );
44227
44228		data.object.color = this.color.getHex();
44229		data.object.intensity = this.intensity;
44230
44231		if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
44232
44233		if ( this.distance !== undefined ) data.object.distance = this.distance;
44234		if ( this.angle !== undefined ) data.object.angle = this.angle;
44235		if ( this.decay !== undefined ) data.object.decay = this.decay;
44236		if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
44237
44238		if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
44239
44240		return data;
44241
44242	}
44243
44244}
44245
44246class HemisphereLight extends Light {
44247
44248	constructor( skyColor, groundColor, intensity ) {
44249
44250		super( skyColor, intensity );
44251
44252		this.isHemisphereLight = true;
44253
44254		this.type = 'HemisphereLight';
44255
44256		this.position.copy( Object3D.DEFAULT_UP );
44257		this.updateMatrix();
44258
44259		this.groundColor = new Color( groundColor );
44260
44261	}
44262
44263	copy( source, recursive ) {
44264
44265		super.copy( source, recursive );
44266
44267		this.groundColor.copy( source.groundColor );
44268
44269		return this;
44270
44271	}
44272
44273}
44274
44275const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();
44276const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();
44277const _lookTarget$1 = /*@__PURE__*/ new Vector3();
44278
44279class LightShadow {
44280
44281	constructor( camera ) {
44282
44283		this.camera = camera;
44284
44285		this.bias = 0;
44286		this.normalBias = 0;
44287		this.radius = 1;
44288		this.blurSamples = 8;
44289
44290		this.mapSize = new Vector2( 512, 512 );
44291
44292		this.map = null;
44293		this.mapPass = null;
44294		this.matrix = new Matrix4();
44295
44296		this.autoUpdate = true;
44297		this.needsUpdate = false;
44298
44299		this._frustum = new Frustum();
44300		this._frameExtents = new Vector2( 1, 1 );
44301
44302		this._viewportCount = 1;
44303
44304		this._viewports = [
44305
44306			new Vector4( 0, 0, 1, 1 )
44307
44308		];
44309
44310	}
44311
44312	getViewportCount() {
44313
44314		return this._viewportCount;
44315
44316	}
44317
44318	getFrustum() {
44319
44320		return this._frustum;
44321
44322	}
44323
44324	updateMatrices( light ) {
44325
44326		const shadowCamera = this.camera;
44327		const shadowMatrix = this.matrix;
44328
44329		_lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );
44330		shadowCamera.position.copy( _lightPositionWorld$1 );
44331
44332		_lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );
44333		shadowCamera.lookAt( _lookTarget$1 );
44334		shadowCamera.updateMatrixWorld();
44335
44336		_projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
44337		this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );
44338
44339		shadowMatrix.set(
44340			0.5, 0.0, 0.0, 0.5,
44341			0.0, 0.5, 0.0, 0.5,
44342			0.0, 0.0, 0.5, 0.5,
44343			0.0, 0.0, 0.0, 1.0
44344		);
44345
44346		shadowMatrix.multiply( _projScreenMatrix$1 );
44347
44348	}
44349
44350	getViewport( viewportIndex ) {
44351
44352		return this._viewports[ viewportIndex ];
44353
44354	}
44355
44356	getFrameExtents() {
44357
44358		return this._frameExtents;
44359
44360	}
44361
44362	dispose() {
44363
44364		if ( this.map ) {
44365
44366			this.map.dispose();
44367
44368		}
44369
44370		if ( this.mapPass ) {
44371
44372			this.mapPass.dispose();
44373
44374		}
44375
44376	}
44377
44378	copy( source ) {
44379
44380		this.camera = source.camera.clone();
44381
44382		this.bias = source.bias;
vendor: 5,997 bytes, lines 44383-44670
44383		this.radius = source.radius;
44384
44385		this.mapSize.copy( source.mapSize );
44386
44387		return this;
44388
44389	}
44390
44391	clone() {
44392
44393		return new this.constructor().copy( this );
44394
44395	}
44396
44397	toJSON() {
44398
44399		const object = {};
44400
44401		if ( this.bias !== 0 ) object.bias = this.bias;
44402		if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
44403		if ( this.radius !== 1 ) object.radius = this.radius;
44404		if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
44405
44406		object.camera = this.camera.toJSON( false ).object;
44407		delete object.camera.matrix;
44408
44409		return object;
44410
44411	}
44412
44413}
44414
44415class SpotLightShadow extends LightShadow {
44416
44417	constructor() {
44418
44419		super( new PerspectiveCamera( 50, 1, 0.5, 500 ) );
44420
44421		this.isSpotLightShadow = true;
44422
44423		this.focus = 1;
44424
44425	}
44426
44427	updateMatrices( light ) {
44428
44429		const camera = this.camera;
44430
44431		const fov = RAD2DEG * 2 * light.angle * this.focus;
44432		const aspect = this.mapSize.width / this.mapSize.height;
44433		const far = light.distance || camera.far;
44434
44435		if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
44436
44437			camera.fov = fov;
44438			camera.aspect = aspect;
44439			camera.far = far;
44440			camera.updateProjectionMatrix();
44441
44442		}
44443
44444		super.updateMatrices( light );
44445
44446	}
44447
44448	copy( source ) {
44449
44450		super.copy( source );
44451
44452		this.focus = source.focus;
44453
44454		return this;
44455
44456	}
44457
44458}
44459
44460class SpotLight extends Light {
44461
44462	constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) {
44463
44464		super( color, intensity );
44465
44466		this.isSpotLight = true;
44467
44468		this.type = 'SpotLight';
44469
44470		this.position.copy( Object3D.DEFAULT_UP );
44471		this.updateMatrix();
44472
44473		this.target = new Object3D();
44474
44475		this.distance = distance;
44476		this.angle = angle;
44477		this.penumbra = penumbra;
44478		this.decay = decay;
44479
44480		this.map = null;
44481
44482		this.shadow = new SpotLightShadow();
44483
44484	}
44485
44486	get power() {
44487
44488		// compute the light's luminous power (in lumens) from its intensity (in candela)
44489		// by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)
44490		return this.intensity * Math.PI;
44491
44492	}
44493
44494	set power( power ) {
44495
44496		// set the light's intensity (in candela) from the desired luminous power (in lumens)
44497		this.intensity = power / Math.PI;
44498
44499	}
44500
44501	dispose() {
44502
44503		this.shadow.dispose();
44504
44505	}
44506
44507	copy( source, recursive ) {
44508
44509		super.copy( source, recursive );
44510
44511		this.distance = source.distance;
44512		this.angle = source.angle;
44513		this.penumbra = source.penumbra;
44514		this.decay = source.decay;
44515
44516		this.target = source.target.clone();
44517
44518		this.shadow = source.shadow.clone();
44519
44520		return this;
44521
44522	}
44523
44524}
44525
44526const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
44527const _lightPositionWorld = /*@__PURE__*/ new Vector3();
44528const _lookTarget = /*@__PURE__*/ new Vector3();
44529
44530class PointLightShadow extends LightShadow {
44531
44532	constructor() {
44533
44534		super( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
44535
44536		this.isPointLightShadow = true;
44537
44538		this._frameExtents = new Vector2( 4, 2 );
44539
44540		this._viewportCount = 6;
44541
44542		this._viewports = [
44543			// These viewports map a cube-map onto a 2D texture with the
44544			// following orientation:
44545			//
44546			//  xzXZ
44547			//   y Y
44548			//
44549			// X - Positive x direction
44550			// x - Negative x direction
44551			// Y - Positive y direction
44552			// y - Negative y direction
44553			// Z - Positive z direction
44554			// z - Negative z direction
44555
44556			// positive X
44557			new Vector4( 2, 1, 1, 1 ),
44558			// negative X
44559			new Vector4( 0, 1, 1, 1 ),
44560			// positive Z
44561			new Vector4( 3, 1, 1, 1 ),
44562			// negative Z
44563			new Vector4( 1, 1, 1, 1 ),
44564			// positive Y
44565			new Vector4( 3, 0, 1, 1 ),
44566			// negative Y
44567			new Vector4( 1, 0, 1, 1 )
44568		];
44569
44570		this._cubeDirections = [
44571			new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
44572			new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
44573		];
44574
44575		this._cubeUps = [
44576			new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
44577			new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
44578		];
44579
44580	}
44581
44582	updateMatrices( light, viewportIndex = 0 ) {
44583
44584		const camera = this.camera;
44585		const shadowMatrix = this.matrix;
44586
44587		const far = light.distance || camera.far;
44588
44589		if ( far !== camera.far ) {
44590
44591			camera.far = far;
44592			camera.updateProjectionMatrix();
44593
44594		}
44595
44596		_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
44597		camera.position.copy( _lightPositionWorld );
44598
44599		_lookTarget.copy( camera.position );
44600		_lookTarget.add( this._cubeDirections[ viewportIndex ] );
44601		camera.up.copy( this._cubeUps[ viewportIndex ] );
44602		camera.lookAt( _lookTarget );
44603		camera.updateMatrixWorld();
44604
44605		shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
44606
44607		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
44608		this._frustum.setFromProjectionMatrix( _projScreenMatrix );
44609
44610	}
44611
44612}
44613
44614class PointLight extends Light {
44615
44616	constructor( color, intensity, distance = 0, decay = 2 ) {
44617
44618		super( color, intensity );
44619
44620		this.isPointLight = true;
44621
44622		this.type = 'PointLight';
44623
44624		this.distance = distance;
44625		this.decay = decay;
44626
44627		this.shadow = new PointLightShadow();
44628
44629	}
44630
44631	get power() {
44632
44633		// compute the light's luminous power (in lumens) from its intensity (in candela)
44634		// for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)
44635		return this.intensity * 4 * Math.PI;
44636
44637	}
44638
44639	set power( power ) {
44640
44641		// set the light's intensity (in candela) from the desired luminous power (in lumens)
44642		this.intensity = power / ( 4 * Math.PI );
44643
44644	}
44645
44646	dispose() {
44647
44648		this.shadow.dispose();
44649
44650	}
44651
44652	copy( source, recursive ) {
44653
44654		super.copy( source, recursive );
44655
44656		this.distance = source.distance;
44657		this.decay = source.decay;
44658
44659		this.shadow = source.shadow.clone();
44660
44661		return this;
44662
44663	}
44664
44665}
44666
44667class DirectionalLightShadow extends LightShadow {
44668
44669	constructor() {
44670
vendor: 4,703 bytes, lines 44671-44908
44671		super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
44672
44673		this.isDirectionalLightShadow = true;
44674
44675	}
44676
44677}
44678
44679class DirectionalLight extends Light {
44680
44681	constructor( color, intensity ) {
44682
44683		super( color, intensity );
44684
44685		this.isDirectionalLight = true;
44686
44687		this.type = 'DirectionalLight';
44688
44689		this.position.copy( Object3D.DEFAULT_UP );
44690		this.updateMatrix();
44691
44692		this.target = new Object3D();
44693
44694		this.shadow = new DirectionalLightShadow();
44695
44696	}
44697
44698	dispose() {
44699
44700		this.shadow.dispose();
44701
44702	}
44703
44704	copy( source ) {
44705
44706		super.copy( source );
44707
44708		this.target = source.target.clone();
44709		this.shadow = source.shadow.clone();
44710
44711		return this;
44712
44713	}
44714
44715}
44716
44717class AmbientLight extends Light {
44718
44719	constructor( color, intensity ) {
44720
44721		super( color, intensity );
44722
44723		this.isAmbientLight = true;
44724
44725		this.type = 'AmbientLight';
44726
44727	}
44728
44729}
44730
44731class RectAreaLight extends Light {
44732
44733	constructor( color, intensity, width = 10, height = 10 ) {
44734
44735		super( color, intensity );
44736
44737		this.isRectAreaLight = true;
44738
44739		this.type = 'RectAreaLight';
44740
44741		this.width = width;
44742		this.height = height;
44743
44744	}
44745
44746	get power() {
44747
44748		// compute the light's luminous power (in lumens) from its intensity (in nits)
44749		return this.intensity * this.width * this.height * Math.PI;
44750
44751	}
44752
44753	set power( power ) {
44754
44755		// set the light's intensity (in nits) from the desired luminous power (in lumens)
44756		this.intensity = power / ( this.width * this.height * Math.PI );
44757
44758	}
44759
44760	copy( source ) {
44761
44762		super.copy( source );
44763
44764		this.width = source.width;
44765		this.height = source.height;
44766
44767		return this;
44768
44769	}
44770
44771	toJSON( meta ) {
44772
44773		const data = super.toJSON( meta );
44774
44775		data.object.width = this.width;
44776		data.object.height = this.height;
44777
44778		return data;
44779
44780	}
44781
44782}
44783
44784/**
44785 * Primary reference:
44786 *   https://graphics.stanford.edu/papers/envmap/envmap.pdf
44787 *
44788 * Secondary reference:
44789 *   https://www.ppsloan.org/publications/StupidSH36.pdf
44790 */
44791
44792// 3-band SH defined by 9 coefficients
44793
44794class SphericalHarmonics3 {
44795
44796	constructor() {
44797
44798		this.isSphericalHarmonics3 = true;
44799
44800		this.coefficients = [];
44801
44802		for ( let i = 0; i < 9; i ++ ) {
44803
44804			this.coefficients.push( new Vector3() );
44805
44806		}
44807
44808	}
44809
44810	set( coefficients ) {
44811
44812		for ( let i = 0; i < 9; i ++ ) {
44813
44814			this.coefficients[ i ].copy( coefficients[ i ] );
44815
44816		}
44817
44818		return this;
44819
44820	}
44821
44822	zero() {
44823
44824		for ( let i = 0; i < 9; i ++ ) {
44825
44826			this.coefficients[ i ].set( 0, 0, 0 );
44827
44828		}
44829
44830		return this;
44831
44832	}
44833
44834	// get the radiance in the direction of the normal
44835	// target is a Vector3
44836	getAt( normal, target ) {
44837
44838		// normal is assumed to be unit length
44839
44840		const x = normal.x, y = normal.y, z = normal.z;
44841
44842		const coeff = this.coefficients;
44843
44844		// band 0
44845		target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
44846
44847		// band 1
44848		target.addScaledVector( coeff[ 1 ], 0.488603 * y );
44849		target.addScaledVector( coeff[ 2 ], 0.488603 * z );
44850		target.addScaledVector( coeff[ 3 ], 0.488603 * x );
44851
44852		// band 2
44853		target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
44854		target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
44855		target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
44856		target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
44857		target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
44858
44859		return target;
44860
44861	}
44862
44863	// get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
44864	// target is a Vector3
44865	// https://graphics.stanford.edu/papers/envmap/envmap.pdf
44866	getIrradianceAt( normal, target ) {
44867
44868		// normal is assumed to be unit length
44869
44870		const x = normal.x, y = normal.y, z = normal.z;
44871
44872		const coeff = this.coefficients;
44873
44874		// band 0
44875		target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
44876
44877		// band 1
44878		target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
44879		target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
44880		target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
44881
44882		// band 2
44883		target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
44884		target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
44885		target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
44886		target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
44887		target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
44888
44889		return target;
44890
44891	}
44892
44893	add( sh ) {
44894
44895		for ( let i = 0; i < 9; i ++ ) {
44896
44897			this.coefficients[ i ].add( sh.coefficients[ i ] );
44898
44899		}
44900
44901		return this;
44902
44903	}
44904
44905	addScaledSH( sh, s ) {
44906
44907		for ( let i = 0; i < 9; i ++ ) {
44908
vendor: 35,968 bytes, lines 44909-46322
44909			this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
44910
44911		}
44912
44913		return this;
44914
44915	}
44916
44917	scale( s ) {
44918
44919		for ( let i = 0; i < 9; i ++ ) {
44920
44921			this.coefficients[ i ].multiplyScalar( s );
44922
44923		}
44924
44925		return this;
44926
44927	}
44928
44929	lerp( sh, alpha ) {
44930
44931		for ( let i = 0; i < 9; i ++ ) {
44932
44933			this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
44934
44935		}
44936
44937		return this;
44938
44939	}
44940
44941	equals( sh ) {
44942
44943		for ( let i = 0; i < 9; i ++ ) {
44944
44945			if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
44946
44947				return false;
44948
44949			}
44950
44951		}
44952
44953		return true;
44954
44955	}
44956
44957	copy( sh ) {
44958
44959		return this.set( sh.coefficients );
44960
44961	}
44962
44963	clone() {
44964
44965		return new this.constructor().copy( this );
44966
44967	}
44968
44969	fromArray( array, offset = 0 ) {
44970
44971		const coefficients = this.coefficients;
44972
44973		for ( let i = 0; i < 9; i ++ ) {
44974
44975			coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
44976
44977		}
44978
44979		return this;
44980
44981	}
44982
44983	toArray( array = [], offset = 0 ) {
44984
44985		const coefficients = this.coefficients;
44986
44987		for ( let i = 0; i < 9; i ++ ) {
44988
44989			coefficients[ i ].toArray( array, offset + ( i * 3 ) );
44990
44991		}
44992
44993		return array;
44994
44995	}
44996
44997	// evaluate the basis functions
44998	// shBasis is an Array[ 9 ]
44999	static getBasisAt( normal, shBasis ) {
45000
45001		// normal is assumed to be unit length
45002
45003		const x = normal.x, y = normal.y, z = normal.z;
45004
45005		// band 0
45006		shBasis[ 0 ] = 0.282095;
45007
45008		// band 1
45009		shBasis[ 1 ] = 0.488603 * y;
45010		shBasis[ 2 ] = 0.488603 * z;
45011		shBasis[ 3 ] = 0.488603 * x;
45012
45013		// band 2
45014		shBasis[ 4 ] = 1.092548 * x * y;
45015		shBasis[ 5 ] = 1.092548 * y * z;
45016		shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
45017		shBasis[ 7 ] = 1.092548 * x * z;
45018		shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
45019
45020	}
45021
45022}
45023
45024class LightProbe extends Light {
45025
45026	constructor( sh = new SphericalHarmonics3(), intensity = 1 ) {
45027
45028		super( undefined, intensity );
45029
45030		this.isLightProbe = true;
45031
45032		this.sh = sh;
45033
45034	}
45035
45036	copy( source ) {
45037
45038		super.copy( source );
45039
45040		this.sh.copy( source.sh );
45041
45042		return this;
45043
45044	}
45045
45046	fromJSON( json ) {
45047
45048		this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
45049		this.sh.fromArray( json.sh );
45050
45051		return this;
45052
45053	}
45054
45055	toJSON( meta ) {
45056
45057		const data = super.toJSON( meta );
45058
45059		data.object.sh = this.sh.toArray();
45060
45061		return data;
45062
45063	}
45064
45065}
45066
45067class MaterialLoader extends Loader {
45068
45069	constructor( manager ) {
45070
45071		super( manager );
45072		this.textures = {};
45073
45074	}
45075
45076	load( url, onLoad, onProgress, onError ) {
45077
45078		const scope = this;
45079
45080		const loader = new FileLoader( scope.manager );
45081		loader.setPath( scope.path );
45082		loader.setRequestHeader( scope.requestHeader );
45083		loader.setWithCredentials( scope.withCredentials );
45084		loader.load( url, function ( text ) {
45085
45086			try {
45087
45088				onLoad( scope.parse( JSON.parse( text ) ) );
45089
45090			} catch ( e ) {
45091
45092				if ( onError ) {
45093
45094					onError( e );
45095
45096				} else {
45097
45098					console.error( e );
45099
45100				}
45101
45102				scope.manager.itemError( url );
45103
45104			}
45105
45106		}, onProgress, onError );
45107
45108	}
45109
45110	parse( json ) {
45111
45112		const textures = this.textures;
45113
45114		function getTexture( name ) {
45115
45116			if ( textures[ name ] === undefined ) {
45117
45118				console.warn( 'THREE.MaterialLoader: Undefined texture', name );
45119
45120			}
45121
45122			return textures[ name ];
45123
45124		}
45125
45126		const material = MaterialLoader.createMaterialFromType( json.type );
45127
45128		if ( json.uuid !== undefined ) material.uuid = json.uuid;
45129		if ( json.name !== undefined ) material.name = json.name;
45130		if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
45131		if ( json.roughness !== undefined ) material.roughness = json.roughness;
45132		if ( json.metalness !== undefined ) material.metalness = json.metalness;
45133		if ( json.sheen !== undefined ) material.sheen = json.sheen;
45134		if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor );
45135		if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness;
45136		if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
45137		if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
45138		if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;
45139		if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor );
45140		if ( json.shininess !== undefined ) material.shininess = json.shininess;
45141		if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
45142		if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
45143		if ( json.iridescence !== undefined ) material.iridescence = json.iridescence;
45144		if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR;
45145		if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange;
45146		if ( json.transmission !== undefined ) material.transmission = json.transmission;
45147		if ( json.thickness !== undefined ) material.thickness = json.thickness;
45148		if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;
45149		if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );
45150		if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;
45151		if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation;
45152		if ( json.fog !== undefined ) material.fog = json.fog;
45153		if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
45154		if ( json.blending !== undefined ) material.blending = json.blending;
45155		if ( json.combine !== undefined ) material.combine = json.combine;
45156		if ( json.side !== undefined ) material.side = json.side;
45157		if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide;
45158		if ( json.opacity !== undefined ) material.opacity = json.opacity;
45159		if ( json.transparent !== undefined ) material.transparent = json.transparent;
45160		if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
45161		if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;
45162		if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc;
45163		if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
45164		if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
45165		if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
45166		if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc;
45167		if ( json.blendDst !== undefined ) material.blendDst = json.blendDst;
45168		if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation;
45169		if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha;
45170		if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha;
45171		if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha;
45172		if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor );
45173		if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha;
45174		if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
45175		if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
45176		if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
45177		if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
45178		if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
45179		if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
45180		if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
45181		if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
45182
45183		if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
45184		if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
45185		if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
45186		if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
45187
45188		if ( json.rotation !== undefined ) material.rotation = json.rotation;
45189
45190		if ( json.linewidth !== undefined ) material.linewidth = json.linewidth;
45191		if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
45192		if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
45193		if ( json.scale !== undefined ) material.scale = json.scale;
45194
45195		if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
45196		if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
45197		if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
45198
45199		if ( json.dithering !== undefined ) material.dithering = json.dithering;
45200
45201		if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage;
45202		if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha;
45203		if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass;
45204
45205		if ( json.visible !== undefined ) material.visible = json.visible;
45206
45207		if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
45208
45209		if ( json.userData !== undefined ) material.userData = json.userData;
45210
45211		if ( json.vertexColors !== undefined ) {
45212
45213			if ( typeof json.vertexColors === 'number' ) {
45214
45215				material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
45216
45217			} else {
45218
45219				material.vertexColors = json.vertexColors;
45220
45221			}
45222
45223		}
45224
45225		// Shader Material
45226
45227		if ( json.uniforms !== undefined ) {
45228
45229			for ( const name in json.uniforms ) {
45230
45231				const uniform = json.uniforms[ name ];
45232
45233				material.uniforms[ name ] = {};
45234
45235				switch ( uniform.type ) {
45236
45237					case 't':
45238						material.uniforms[ name ].value = getTexture( uniform.value );
45239						break;
45240
45241					case 'c':
45242						material.uniforms[ name ].value = new Color().setHex( uniform.value );
45243						break;
45244
45245					case 'v2':
45246						material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
45247						break;
45248
45249					case 'v3':
45250						material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
45251						break;
45252
45253					case 'v4':
45254						material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
45255						break;
45256
45257					case 'm3':
45258						material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
45259						break;
45260
45261					case 'm4':
45262						material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
45263						break;
45264
45265					default:
45266						material.uniforms[ name ].value = uniform.value;
45267
45268				}
45269
45270			}
45271
45272		}
45273
45274		if ( json.defines !== undefined ) material.defines = json.defines;
45275		if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
45276		if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
45277		if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion;
45278
45279		if ( json.extensions !== undefined ) {
45280
45281			for ( const key in json.extensions ) {
45282
45283				material.extensions[ key ] = json.extensions[ key ];
45284
45285			}
45286
45287		}
45288
45289		if ( json.lights !== undefined ) material.lights = json.lights;
45290		if ( json.clipping !== undefined ) material.clipping = json.clipping;
45291
45292		// for PointsMaterial
45293
45294		if ( json.size !== undefined ) material.size = json.size;
45295		if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
45296
45297		// maps
45298
45299		if ( json.map !== undefined ) material.map = getTexture( json.map );
45300		if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
45301
45302		if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
45303
45304		if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
45305		if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
45306
45307		if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
45308		if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
45309		if ( json.normalScale !== undefined ) {
45310
45311			let normalScale = json.normalScale;
45312
45313			if ( Array.isArray( normalScale ) === false ) {
45314
45315				// Blender exporter used to export a scalar. See #7459
45316
45317				normalScale = [ normalScale, normalScale ];
45318
45319			}
45320
45321			material.normalScale = new Vector2().fromArray( normalScale );
45322
45323		}
45324
45325		if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
45326		if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
45327		if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
45328
45329		if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
45330		if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
45331
45332		if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
45333		if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
45334
45335		if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
45336		if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );
45337		if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap );
45338
45339		if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
45340		if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
45341
45342		if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
45343		if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
45344
45345		if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
45346		if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
45347
45348		if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
45349		if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
45350
45351		if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
45352
45353		if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
45354		if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
45355		if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
45356		if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
45357
45358		if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap );
45359		if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap );
45360
45361		if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
45362		if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );
45363
45364		if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );
45365
45366		if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );
45367		if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );
45368
45369		return material;
45370
45371	}
45372
45373	setTextures( value ) {
45374
45375		this.textures = value;
45376		return this;
45377
45378	}
45379
45380	static createMaterialFromType( type ) {
45381
45382		const materialLib = {
45383			ShadowMaterial,
45384			SpriteMaterial,
45385			RawShaderMaterial,
45386			ShaderMaterial,
45387			PointsMaterial,
45388			MeshPhysicalMaterial,
45389			MeshStandardMaterial,
45390			MeshPhongMaterial,
45391			MeshToonMaterial,
45392			MeshNormalMaterial,
45393			MeshLambertMaterial,
45394			MeshDepthMaterial,
45395			MeshDistanceMaterial,
45396			MeshBasicMaterial,
45397			MeshMatcapMaterial,
45398			LineDashedMaterial,
45399			LineBasicMaterial,
45400			Material
45401		};
45402
45403		return new materialLib[ type ]();
45404
45405	}
45406
45407}
45408
45409class LoaderUtils {
45410
45411	static decodeText( array ) {
45412
45413		if ( typeof TextDecoder !== 'undefined' ) {
45414
45415			return new TextDecoder().decode( array );
45416
45417		}
45418
45419		// Avoid the String.fromCharCode.apply(null, array) shortcut, which
45420		// throws a "maximum call stack size exceeded" error for large arrays.
45421
45422		let s = '';
45423
45424		for ( let i = 0, il = array.length; i < il; i ++ ) {
45425
45426			// Implicitly assumes little-endian.
45427			s += String.fromCharCode( array[ i ] );
45428
45429		}
45430
45431		try {
45432
45433			// merges multi-byte utf-8 characters.
45434
45435			return decodeURIComponent( escape( s ) );
45436
45437		} catch ( e ) { // see #16358
45438
45439			return s;
45440
45441		}
45442
45443	}
45444
45445	static extractUrlBase( url ) {
45446
45447		const index = url.lastIndexOf( '/' );
45448
45449		if ( index === - 1 ) return './';
45450
45451		return url.slice( 0, index + 1 );
45452
45453	}
45454
45455	static resolveURL( url, path ) {
45456
45457		// Invalid URL
45458		if ( typeof url !== 'string' || url === '' ) return '';
45459
45460		// Host Relative URL
45461		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
45462
45463			path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
45464
45465		}
45466
45467		// Absolute URL http://,https://,//
45468		if ( /^(https?:)?\/\//i.test( url ) ) return url;
45469
45470		// Data URI
45471		if ( /^data:.*,.*$/i.test( url ) ) return url;
45472
45473		// Blob URL
45474		if ( /^blob:.*$/i.test( url ) ) return url;
45475
45476		// Relative URL
45477		return path + url;
45478
45479	}
45480
45481}
45482
45483class InstancedBufferGeometry extends BufferGeometry {
45484
45485	constructor() {
45486
45487		super();
45488
45489		this.isInstancedBufferGeometry = true;
45490
45491		this.type = 'InstancedBufferGeometry';
45492		this.instanceCount = Infinity;
45493
45494	}
45495
45496	copy( source ) {
45497
45498		super.copy( source );
45499
45500		this.instanceCount = source.instanceCount;
45501
45502		return this;
45503
45504	}
45505
45506	toJSON() {
45507
45508		const data = super.toJSON();
45509
45510		data.instanceCount = this.instanceCount;
45511
45512		data.isInstancedBufferGeometry = true;
45513
45514		return data;
45515
45516	}
45517
45518}
45519
45520class BufferGeometryLoader extends Loader {
45521
45522	constructor( manager ) {
45523
45524		super( manager );
45525
45526	}
45527
45528	load( url, onLoad, onProgress, onError ) {
45529
45530		const scope = this;
45531
45532		const loader = new FileLoader( scope.manager );
45533		loader.setPath( scope.path );
45534		loader.setRequestHeader( scope.requestHeader );
45535		loader.setWithCredentials( scope.withCredentials );
45536		loader.load( url, function ( text ) {
45537
45538			try {
45539
45540				onLoad( scope.parse( JSON.parse( text ) ) );
45541
45542			} catch ( e ) {
45543
45544				if ( onError ) {
45545
45546					onError( e );
45547
45548				} else {
45549
45550					console.error( e );
45551
45552				}
45553
45554				scope.manager.itemError( url );
45555
45556			}
45557
45558		}, onProgress, onError );
45559
45560	}
45561
45562	parse( json ) {
45563
45564		const interleavedBufferMap = {};
45565		const arrayBufferMap = {};
45566
45567		function getInterleavedBuffer( json, uuid ) {
45568
45569			if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
45570
45571			const interleavedBuffers = json.interleavedBuffers;
45572			const interleavedBuffer = interleavedBuffers[ uuid ];
45573
45574			const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
45575
45576			const array = getTypedArray( interleavedBuffer.type, buffer );
45577			const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
45578			ib.uuid = interleavedBuffer.uuid;
45579
45580			interleavedBufferMap[ uuid ] = ib;
45581
45582			return ib;
45583
45584		}
45585
45586		function getArrayBuffer( json, uuid ) {
45587
45588			if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
45589
45590			const arrayBuffers = json.arrayBuffers;
45591			const arrayBuffer = arrayBuffers[ uuid ];
45592
45593			const ab = new Uint32Array( arrayBuffer ).buffer;
45594
45595			arrayBufferMap[ uuid ] = ab;
45596
45597			return ab;
45598
45599		}
45600
45601		const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
45602
45603		const index = json.data.index;
45604
45605		if ( index !== undefined ) {
45606
45607			const typedArray = getTypedArray( index.type, index.array );
45608			geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
45609
45610		}
45611
45612		const attributes = json.data.attributes;
45613
45614		for ( const key in attributes ) {
45615
45616			const attribute = attributes[ key ];
45617			let bufferAttribute;
45618
45619			if ( attribute.isInterleavedBufferAttribute ) {
45620
45621				const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45622				bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45623
45624			} else {
45625
45626				const typedArray = getTypedArray( attribute.type, attribute.array );
45627				const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
45628				bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
45629
45630			}
45631
45632			if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45633			if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage );
45634
45635			geometry.setAttribute( key, bufferAttribute );
45636
45637		}
45638
45639		const morphAttributes = json.data.morphAttributes;
45640
45641		if ( morphAttributes ) {
45642
45643			for ( const key in morphAttributes ) {
45644
45645				const attributeArray = morphAttributes[ key ];
45646
45647				const array = [];
45648
45649				for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
45650
45651					const attribute = attributeArray[ i ];
45652					let bufferAttribute;
45653
45654					if ( attribute.isInterleavedBufferAttribute ) {
45655
45656						const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45657						bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45658
45659					} else {
45660
45661						const typedArray = getTypedArray( attribute.type, attribute.array );
45662						bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
45663
45664					}
45665
45666					if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45667					array.push( bufferAttribute );
45668
45669				}
45670
45671				geometry.morphAttributes[ key ] = array;
45672
45673			}
45674
45675		}
45676
45677		const morphTargetsRelative = json.data.morphTargetsRelative;
45678
45679		if ( morphTargetsRelative ) {
45680
45681			geometry.morphTargetsRelative = true;
45682
45683		}
45684
45685		const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
45686
45687		if ( groups !== undefined ) {
45688
45689			for ( let i = 0, n = groups.length; i !== n; ++ i ) {
45690
45691				const group = groups[ i ];
45692
45693				geometry.addGroup( group.start, group.count, group.materialIndex );
45694
45695			}
45696
45697		}
45698
45699		const boundingSphere = json.data.boundingSphere;
45700
45701		if ( boundingSphere !== undefined ) {
45702
45703			const center = new Vector3();
45704
45705			if ( boundingSphere.center !== undefined ) {
45706
45707				center.fromArray( boundingSphere.center );
45708
45709			}
45710
45711			geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
45712
45713		}
45714
45715		if ( json.name ) geometry.name = json.name;
45716		if ( json.userData ) geometry.userData = json.userData;
45717
45718		return geometry;
45719
45720	}
45721
45722}
45723
45724class ObjectLoader extends Loader {
45725
45726	constructor( manager ) {
45727
45728		super( manager );
45729
45730	}
45731
45732	load( url, onLoad, onProgress, onError ) {
45733
45734		const scope = this;
45735
45736		const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45737		this.resourcePath = this.resourcePath || path;
45738
45739		const loader = new FileLoader( this.manager );
45740		loader.setPath( this.path );
45741		loader.setRequestHeader( this.requestHeader );
45742		loader.setWithCredentials( this.withCredentials );
45743		loader.load( url, function ( text ) {
45744
45745			let json = null;
45746
45747			try {
45748
45749				json = JSON.parse( text );
45750
45751			} catch ( error ) {
45752
45753				if ( onError !== undefined ) onError( error );
45754
45755				console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
45756
45757				return;
45758
45759			}
45760
45761			const metadata = json.metadata;
45762
45763			if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45764
45765				if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) );
45766
45767				console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
45768				return;
45769
45770			}
45771
45772			scope.parse( json, onLoad );
45773
45774		}, onProgress, onError );
45775
45776	}
45777
45778	async loadAsync( url, onProgress ) {
45779
45780		const scope = this;
45781
45782		const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45783		this.resourcePath = this.resourcePath || path;
45784
45785		const loader = new FileLoader( this.manager );
45786		loader.setPath( this.path );
45787		loader.setRequestHeader( this.requestHeader );
45788		loader.setWithCredentials( this.withCredentials );
45789
45790		const text = await loader.loadAsync( url, onProgress );
45791
45792		const json = JSON.parse( text );
45793
45794		const metadata = json.metadata;
45795
45796		if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45797
45798			throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url );
45799
45800		}
45801
45802		return await scope.parseAsync( json );
45803
45804	}
45805
45806	parse( json, onLoad ) {
45807
45808		const animations = this.parseAnimations( json.animations );
45809		const shapes = this.parseShapes( json.shapes );
45810		const geometries = this.parseGeometries( json.geometries, shapes );
45811
45812		const images = this.parseImages( json.images, function () {
45813
45814			if ( onLoad !== undefined ) onLoad( object );
45815
45816		} );
45817
45818		const textures = this.parseTextures( json.textures, images );
45819		const materials = this.parseMaterials( json.materials, textures );
45820
45821		const object = this.parseObject( json.object, geometries, materials, textures, animations );
45822		const skeletons = this.parseSkeletons( json.skeletons, object );
45823
45824		this.bindSkeletons( object, skeletons );
45825
45826		//
45827
45828		if ( onLoad !== undefined ) {
45829
45830			let hasImages = false;
45831
45832			for ( const uuid in images ) {
45833
45834				if ( images[ uuid ].data instanceof HTMLImageElement ) {
45835
45836					hasImages = true;
45837					break;
45838
45839				}
45840
45841			}
45842
45843			if ( hasImages === false ) onLoad( object );
45844
45845		}
45846
45847		return object;
45848
45849	}
45850
45851	async parseAsync( json ) {
45852
45853		const animations = this.parseAnimations( json.animations );
45854		const shapes = this.parseShapes( json.shapes );
45855		const geometries = this.parseGeometries( json.geometries, shapes );
45856
45857		const images = await this.parseImagesAsync( json.images );
45858
45859		const textures = this.parseTextures( json.textures, images );
45860		const materials = this.parseMaterials( json.materials, textures );
45861
45862		const object = this.parseObject( json.object, geometries, materials, textures, animations );
45863		const skeletons = this.parseSkeletons( json.skeletons, object );
45864
45865		this.bindSkeletons( object, skeletons );
45866
45867		return object;
45868
45869	}
45870
45871	parseShapes( json ) {
45872
45873		const shapes = {};
45874
45875		if ( json !== undefined ) {
45876
45877			for ( let i = 0, l = json.length; i < l; i ++ ) {
45878
45879				const shape = new Shape().fromJSON( json[ i ] );
45880
45881				shapes[ shape.uuid ] = shape;
45882
45883			}
45884
45885		}
45886
45887		return shapes;
45888
45889	}
45890
45891	parseSkeletons( json, object ) {
45892
45893		const skeletons = {};
45894		const bones = {};
45895
45896		// generate bone lookup table
45897
45898		object.traverse( function ( child ) {
45899
45900			if ( child.isBone ) bones[ child.uuid ] = child;
45901
45902		} );
45903
45904		// create skeletons
45905
45906		if ( json !== undefined ) {
45907
45908			for ( let i = 0, l = json.length; i < l; i ++ ) {
45909
45910				const skeleton = new Skeleton().fromJSON( json[ i ], bones );
45911
45912				skeletons[ skeleton.uuid ] = skeleton;
45913
45914			}
45915
45916		}
45917
45918		return skeletons;
45919
45920	}
45921
45922	parseGeometries( json, shapes ) {
45923
45924		const geometries = {};
45925
45926		if ( json !== undefined ) {
45927
45928			const bufferGeometryLoader = new BufferGeometryLoader();
45929
45930			for ( let i = 0, l = json.length; i < l; i ++ ) {
45931
45932				let geometry;
45933				const data = json[ i ];
45934
45935				switch ( data.type ) {
45936
45937					case 'BufferGeometry':
45938					case 'InstancedBufferGeometry':
45939
45940						geometry = bufferGeometryLoader.parse( data );
45941						break;
45942
45943					default:
45944
45945						if ( data.type in Geometries ) {
45946
45947							geometry = Geometries[ data.type ].fromJSON( data, shapes );
45948
45949						} else {
45950
45951							console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` );
45952
45953						}
45954
45955				}
45956
45957				geometry.uuid = data.uuid;
45958
45959				if ( data.name !== undefined ) geometry.name = data.name;
45960				if ( data.userData !== undefined ) geometry.userData = data.userData;
45961
45962				geometries[ data.uuid ] = geometry;
45963
45964			}
45965
45966		}
45967
45968		return geometries;
45969
45970	}
45971
45972	parseMaterials( json, textures ) {
45973
45974		const cache = {}; // MultiMaterial
45975		const materials = {};
45976
45977		if ( json !== undefined ) {
45978
45979			const loader = new MaterialLoader();
45980			loader.setTextures( textures );
45981
45982			for ( let i = 0, l = json.length; i < l; i ++ ) {
45983
45984				const data = json[ i ];
45985
45986				if ( cache[ data.uuid ] === undefined ) {
45987
45988					cache[ data.uuid ] = loader.parse( data );
45989
45990				}
45991
45992				materials[ data.uuid ] = cache[ data.uuid ];
45993
45994			}
45995
45996		}
45997
45998		return materials;
45999
46000	}
46001
46002	parseAnimations( json ) {
46003
46004		const animations = {};
46005
46006		if ( json !== undefined ) {
46007
46008			for ( let i = 0; i < json.length; i ++ ) {
46009
46010				const data = json[ i ];
46011
46012				const clip = AnimationClip.parse( data );
46013
46014				animations[ clip.uuid ] = clip;
46015
46016			}
46017
46018		}
46019
46020		return animations;
46021
46022	}
46023
46024	parseImages( json, onLoad ) {
46025
46026		const scope = this;
46027		const images = {};
46028
46029		let loader;
46030
46031		function loadImage( url ) {
46032
46033			scope.manager.itemStart( url );
46034
46035			return loader.load( url, function () {
46036
46037				scope.manager.itemEnd( url );
46038
46039			}, undefined, function () {
46040
46041				scope.manager.itemError( url );
46042				scope.manager.itemEnd( url );
46043
46044			} );
46045
46046		}
46047
46048		function deserializeImage( image ) {
46049
46050			if ( typeof image === 'string' ) {
46051
46052				const url = image;
46053
46054				const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46055
46056				return loadImage( path );
46057
46058			} else {
46059
46060				if ( image.data ) {
46061
46062					return {
46063						data: getTypedArray( image.type, image.data ),
46064						width: image.width,
46065						height: image.height
46066					};
46067
46068				} else {
46069
46070					return null;
46071
46072				}
46073
46074			}
46075
46076		}
46077
46078		if ( json !== undefined && json.length > 0 ) {
46079
46080			const manager = new LoadingManager( onLoad );
46081
46082			loader = new ImageLoader( manager );
46083			loader.setCrossOrigin( this.crossOrigin );
46084
46085			for ( let i = 0, il = json.length; i < il; i ++ ) {
46086
46087				const image = json[ i ];
46088				const url = image.url;
46089
46090				if ( Array.isArray( url ) ) {
46091
46092					// load array of images e.g CubeTexture
46093
46094					const imageArray = [];
46095
46096					for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46097
46098						const currentUrl = url[ j ];
46099
46100						const deserializedImage = deserializeImage( currentUrl );
46101
46102						if ( deserializedImage !== null ) {
46103
46104							if ( deserializedImage instanceof HTMLImageElement ) {
46105
46106								imageArray.push( deserializedImage );
46107
46108							} else {
46109
46110								// special case: handle array of data textures for cube textures
46111
46112								imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46113
46114							}
46115
46116						}
46117
46118					}
46119
46120					images[ image.uuid ] = new Source( imageArray );
46121
46122				} else {
46123
46124					// load single image
46125
46126					const deserializedImage = deserializeImage( image.url );
46127					images[ image.uuid ] = new Source( deserializedImage );
46128
46129
46130				}
46131
46132			}
46133
46134		}
46135
46136		return images;
46137
46138	}
46139
46140	async parseImagesAsync( json ) {
46141
46142		const scope = this;
46143		const images = {};
46144
46145		let loader;
46146
46147		async function deserializeImage( image ) {
46148
46149			if ( typeof image === 'string' ) {
46150
46151				const url = image;
46152
46153				const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46154
46155				return await loader.loadAsync( path );
46156
46157			} else {
46158
46159				if ( image.data ) {
46160
46161					return {
46162						data: getTypedArray( image.type, image.data ),
46163						width: image.width,
46164						height: image.height
46165					};
46166
46167				} else {
46168
46169					return null;
46170
46171				}
46172
46173			}
46174
46175		}
46176
46177		if ( json !== undefined && json.length > 0 ) {
46178
46179			loader = new ImageLoader( this.manager );
46180			loader.setCrossOrigin( this.crossOrigin );
46181
46182			for ( let i = 0, il = json.length; i < il; i ++ ) {
46183
46184				const image = json[ i ];
46185				const url = image.url;
46186
46187				if ( Array.isArray( url ) ) {
46188
46189					// load array of images e.g CubeTexture
46190
46191					const imageArray = [];
46192
46193					for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46194
46195						const currentUrl = url[ j ];
46196
46197						const deserializedImage = await deserializeImage( currentUrl );
46198
46199						if ( deserializedImage !== null ) {
46200
46201							if ( deserializedImage instanceof HTMLImageElement ) {
46202
46203								imageArray.push( deserializedImage );
46204
46205							} else {
46206
46207								// special case: handle array of data textures for cube textures
46208
46209								imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46210
46211							}
46212
46213						}
46214
46215					}
46216
46217					images[ image.uuid ] = new Source( imageArray );
46218
46219				} else {
46220
46221					// load single image
46222
46223					const deserializedImage = await deserializeImage( image.url );
46224					images[ image.uuid ] = new Source( deserializedImage );
46225
46226				}
46227
46228			}
46229
46230		}
46231
46232		return images;
46233
46234	}
46235
46236	parseTextures( json, images ) {
46237
46238		function parseConstant( value, type ) {
46239
46240			if ( typeof value === 'number' ) return value;
46241
46242			console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
46243
46244			return type[ value ];
46245
46246		}
46247
46248		const textures = {};
46249
46250		if ( json !== undefined ) {
46251
46252			for ( let i = 0, l = json.length; i < l; i ++ ) {
46253
46254				const data = json[ i ];
46255
46256				if ( data.image === undefined ) {
46257
46258					console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
46259
46260				}
46261
46262				if ( images[ data.image ] === undefined ) {
46263
46264					console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
46265
46266				}
46267
46268				const source = images[ data.image ];
46269				const image = source.data;
46270
46271				let texture;
46272
46273				if ( Array.isArray( image ) ) {
46274
46275					texture = new CubeTexture();
46276
46277					if ( image.length === 6 ) texture.needsUpdate = true;
46278
46279				} else {
46280
46281					if ( image && image.data ) {
46282
46283						texture = new DataTexture();
46284
46285					} else {
46286
46287						texture = new Texture();
46288
46289					}
46290
46291					if ( image ) texture.needsUpdate = true; // textures can have undefined image data
46292
46293				}
46294
46295				texture.source = source;
46296
46297				texture.uuid = data.uuid;
46298
46299				if ( data.name !== undefined ) texture.name = data.name;
46300
46301				if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
46302				if ( data.channel !== undefined ) texture.channel = data.channel;
46303
46304				if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
46305				if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
46306				if ( data.center !== undefined ) texture.center.fromArray( data.center );
46307				if ( data.rotation !== undefined ) texture.rotation = data.rotation;
46308
46309				if ( data.wrap !== undefined ) {
46310
46311					texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
46312					texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
46313
46314				}
46315
46316				if ( data.format !== undefined ) texture.format = data.format;
46317				if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat;
46318				if ( data.type !== undefined ) texture.type = data.type;
46319				if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace;
46320				if ( data.encoding !== undefined ) texture.encoding = data.encoding; // @deprecated, r152
46321
46322				if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minF
46322ilter, TEXTURE_FILTER );
46323				if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
46324				if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
46325
46326				if ( data.flipY !== undefined ) texture.flipY = data.flipY;
46327
46328				if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps;
46329				if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
46330				if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
46331				if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;
46332
46333				if ( data.userData !== undefined ) texture.userData = data.userData;
46334
46335				textures[ data.uuid ] = texture;
46336
46337			}
46338
46339		}
46340
46341		return textures;
46342
46343	}
46344
46345	parseObject( data, geometries, materials, textures, animations ) {
46346
46347		let object;
46348
46349		function getGeometry( name ) {
46350
46351			if ( geometries[ name ] === undefined ) {
46352
46353				console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
46354
46355			}
46356
46357			return geometries[ name ];
46358
46359		}
46360
46361		function getMaterial( name ) {
46362
vendor: 5,576 bytes, lines 46363-46587
46363			if ( name === undefined ) return undefined;
46364
46365			if ( Array.isArray( name ) ) {
46366
46367				const array = [];
46368
46369				for ( let i = 0, l = name.length; i < l; i ++ ) {
46370
46371					const uuid = name[ i ];
46372
46373					if ( materials[ uuid ] === undefined ) {
46374
46375						console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
46376
46377					}
46378
46379					array.push( materials[ uuid ] );
46380
46381				}
46382
46383				return array;
46384
46385			}
46386
46387			if ( materials[ name ] === undefined ) {
46388
46389				console.warn( 'THREE.ObjectLoader: Undefined material', name );
46390
46391			}
46392
46393			return materials[ name ];
46394
46395		}
46396
46397		function getTexture( uuid ) {
46398
46399			if ( textures[ uuid ] === undefined ) {
46400
46401				console.warn( 'THREE.ObjectLoader: Undefined texture', uuid );
46402
46403			}
46404
46405			return textures[ uuid ];
46406
46407		}
46408
46409		let geometry, material;
46410
46411		switch ( data.type ) {
46412
46413			case 'Scene':
46414
46415				object = new Scene();
46416
46417				if ( data.background !== undefined ) {
46418
46419					if ( Number.isInteger( data.background ) ) {
46420
46421						object.background = new Color( data.background );
46422
46423					} else {
46424
46425						object.background = getTexture( data.background );
46426
46427					}
46428
46429				}
46430
46431				if ( data.environment !== undefined ) {
46432
46433					object.environment = getTexture( data.environment );
46434
46435				}
46436
46437				if ( data.fog !== undefined ) {
46438
46439					if ( data.fog.type === 'Fog' ) {
46440
46441						object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
46442
46443					} else if ( data.fog.type === 'FogExp2' ) {
46444
46445						object.fog = new FogExp2( data.fog.color, data.fog.density );
46446
46447					}
46448
46449					if ( data.fog.name !== '' ) {
46450
46451						object.fog.name = data.fog.name;
46452
46453					}
46454
46455				}
46456
46457				if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness;
46458				if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity;
46459
46460				break;
46461
46462			case 'PerspectiveCamera':
46463
46464				object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
46465
46466				if ( data.focus !== undefined ) object.focus = data.focus;
46467				if ( data.zoom !== undefined ) object.zoom = data.zoom;
46468				if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
46469				if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
46470				if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46471
46472				break;
46473
46474			case 'OrthographicCamera':
46475
46476				object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
46477
46478				if ( data.zoom !== undefined ) object.zoom = data.zoom;
46479				if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46480
46481				break;
46482
46483			case 'AmbientLight':
46484
46485				object = new AmbientLight( data.color, data.intensity );
46486
46487				break;
46488
46489			case 'DirectionalLight':
46490
46491				object = new DirectionalLight( data.color, data.intensity );
46492
46493				break;
46494
46495			case 'PointLight':
46496
46497
46498				object = new PointLight( data.color, data.intensity, data.distance, data.decay );
46499
46500				break;
46501
46502			case 'RectAreaLight':
46503
46504				object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
46505
46506				break;
46507
46508			case 'SpotLight':
46509
46510				object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
46511
46512				break;
46513
46514			case 'HemisphereLight':
46515
46516				object = new HemisphereLight( data.color, data.groundColor, data.intensity );
46517
46518				break;
46519
46520			case 'LightProbe':
46521
46522				object = new LightProbe().fromJSON( data );
46523
46524				break;
46525
46526			case 'SkinnedMesh':
46527
46528				geometry = getGeometry( data.geometry );
46529			 	material = getMaterial( data.material );
46530
46531				object = new SkinnedMesh( geometry, material );
46532
46533				if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
46534				if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
46535				if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
46536
46537				break;
46538
46539			case 'Mesh':
46540
46541				geometry = getGeometry( data.geometry );
46542				material = getMaterial( data.material );
46543
46544				object = new Mesh( geometry, material );
46545
46546				break;
46547
46548			case 'InstancedMesh':
46549
46550				geometry = getGeometry( data.geometry );
46551				material = getMaterial( data.material );
46552				const count = data.count;
46553				const instanceMatrix = data.instanceMatrix;
46554				const instanceColor = data.instanceColor;
46555
46556				object = new InstancedMesh( geometry, material, count );
46557				object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
46558				if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize );
46559
46560				break;
46561
46562			case 'BatchedMesh':
46563
46564				geometry = getGeometry( data.geometry );
46565				material = getMaterial( data.material );
46566
46567				object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material );
46568				object.geometry = geometry;
46569				object.perObjectFrustumCulled = data.perObjectFrustumCulled;
46570				object.sortObjects = data.sortObjects;
46571
46572				object._drawRanges = data.drawRanges;
46573				object._reservedRanges = data.reservedRanges;
46574
46575				object._visibility = data.visibility;
46576				object._active = data.active;
46577				object._bounds = data.bounds.map( bound => {
46578
46579					const box = new Box3();
46580					box.min.fromArray( bound.boxMin );
46581					box.max.fromArray( bound.boxMax );
46582
46583					const sphere = new Sphere();
46584					sphere.radius = bound.sphereRadius;
46585					sphere.center.fromArray( bound.sphereCenter );
46586
46587					return {
vendor: 40,161 bytes, lines 46588-48541
46588						boxInitialized: bound.boxInitialized,
46589						box: box,
46590
46591						sphereInitialized: bound.sphereInitialized,
46592						sphere: sphere
46593					};
46594
46595				} );
46596
46597				object._maxGeometryCount = data.maxGeometryCount;
46598				object._maxVertexCount = data.maxVertexCount;
46599				object._maxIndexCount = data.maxIndexCount;
46600
46601				object._geometryInitialized = data.geometryInitialized;
46602				object._geometryCount = data.geometryCount;
46603
46604				object._matricesTexture = getTexture( data.matricesTexture.uuid );
46605
46606				break;
46607
46608			case 'LOD':
46609
46610				object = new LOD();
46611
46612				break;
46613
46614			case 'Line':
46615
46616				object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );
46617
46618				break;
46619
46620			case 'LineLoop':
46621
46622				object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
46623
46624				break;
46625
46626			case 'LineSegments':
46627
46628				object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
46629
46630				break;
46631
46632			case 'PointCloud':
46633			case 'Points':
46634
46635				object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
46636
46637				break;
46638
46639			case 'Sprite':
46640
46641				object = new Sprite( getMaterial( data.material ) );
46642
46643				break;
46644
46645			case 'Group':
46646
46647				object = new Group();
46648
46649				break;
46650
46651			case 'Bone':
46652
46653				object = new Bone();
46654
46655				break;
46656
46657			default:
46658
46659				object = new Object3D();
46660
46661		}
46662
46663		object.uuid = data.uuid;
46664
46665		if ( data.name !== undefined ) object.name = data.name;
46666
46667		if ( data.matrix !== undefined ) {
46668
46669			object.matrix.fromArray( data.matrix );
46670
46671			if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
46672			if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
46673
46674		} else {
46675
46676			if ( data.position !== undefined ) object.position.fromArray( data.position );
46677			if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
46678			if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
46679			if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
46680
46681		}
46682
46683		if ( data.up !== undefined ) object.up.fromArray( data.up );
46684
46685		if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
46686		if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
46687
46688		if ( data.shadow ) {
46689
46690			if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
46691			if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
46692			if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
46693			if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
46694			if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
46695
46696		}
46697
46698		if ( data.visible !== undefined ) object.visible = data.visible;
46699		if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
46700		if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
46701		if ( data.userData !== undefined ) object.userData = data.userData;
46702		if ( data.layers !== undefined ) object.layers.mask = data.layers;
46703
46704		if ( data.children !== undefined ) {
46705
46706			const children = data.children;
46707
46708			for ( let i = 0; i < children.length; i ++ ) {
46709
46710				object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) );
46711
46712			}
46713
46714		}
46715
46716		if ( data.animations !== undefined ) {
46717
46718			const objectAnimations = data.animations;
46719
46720			for ( let i = 0; i < objectAnimations.length; i ++ ) {
46721
46722				const uuid = objectAnimations[ i ];
46723
46724				object.animations.push( animations[ uuid ] );
46725
46726			}
46727
46728		}
46729
46730		if ( data.type === 'LOD' ) {
46731
46732			if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
46733
46734			const levels = data.levels;
46735
46736			for ( let l = 0; l < levels.length; l ++ ) {
46737
46738				const level = levels[ l ];
46739				const child = object.getObjectByProperty( 'uuid', level.object );
46740
46741				if ( child !== undefined ) {
46742
46743					object.addLevel( child, level.distance, level.hysteresis );
46744
46745				}
46746
46747			}
46748
46749		}
46750
46751		return object;
46752
46753	}
46754
46755	bindSkeletons( object, skeletons ) {
46756
46757		if ( Object.keys( skeletons ).length === 0 ) return;
46758
46759		object.traverse( function ( child ) {
46760
46761			if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
46762
46763				const skeleton = skeletons[ child.skeleton ];
46764
46765				if ( skeleton === undefined ) {
46766
46767					console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
46768
46769				} else {
46770
46771					child.bind( skeleton, child.bindMatrix );
46772
46773				}
46774
46775			}
46776
46777		} );
46778
46779	}
46780
46781}
46782
46783const TEXTURE_MAPPING = {
46784	UVMapping: UVMapping,
46785	CubeReflectionMapping: CubeReflectionMapping,
46786	CubeRefractionMapping: CubeRefractionMapping,
46787	EquirectangularReflectionMapping: EquirectangularReflectionMapping,
46788	EquirectangularRefractionMapping: EquirectangularRefractionMapping,
46789	CubeUVReflectionMapping: CubeUVReflectionMapping
46790};
46791
46792const TEXTURE_WRAPPING = {
46793	RepeatWrapping: RepeatWrapping,
46794	ClampToEdgeWrapping: ClampToEdgeWrapping,
46795	MirroredRepeatWrapping: MirroredRepeatWrapping
46796};
46797
46798const TEXTURE_FILTER = {
46799	NearestFilter: NearestFilter,
46800	NearestMipmapNearestFilter: NearestMipmapNearestFilter,
46801	NearestMipmapLinearFilter: NearestMipmapLinearFilter,
46802	LinearFilter: LinearFilter,
46803	LinearMipmapNearestFilter: LinearMipmapNearestFilter,
46804	LinearMipmapLinearFilter: LinearMipmapLinearFilter
46805};
46806
46807class ImageBitmapLoader extends Loader {
46808
46809	constructor( manager ) {
46810
46811		super( manager );
46812
46813		this.isImageBitmapLoader = true;
46814
46815		if ( typeof createImageBitmap === 'undefined' ) {
46816
46817			console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
46818
46819		}
46820
46821		if ( typeof fetch === 'undefined' ) {
46822
46823			console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
46824
46825		}
46826
46827		this.options = { premultiplyAlpha: 'none' };
46828
46829	}
46830
46831	setOptions( options ) {
46832
46833		this.options = options;
46834
46835		return this;
46836
46837	}
46838
46839	load( url, onLoad, onProgress, onError ) {
46840
46841		if ( url === undefined ) url = '';
46842
46843		if ( this.path !== undefined ) url = this.path + url;
46844
46845		url = this.manager.resolveURL( url );
46846
46847		const scope = this;
46848
46849		const cached = Cache.get( url );
46850
46851		if ( cached !== undefined ) {
46852
46853			scope.manager.itemStart( url );
46854
46855			// If cached is a promise, wait for it to resolve
46856			if ( cached.then ) {
46857
46858				cached.then( imageBitmap => {
46859
46860					if ( onLoad ) onLoad( imageBitmap );
46861
46862					scope.manager.itemEnd( url );
46863
46864				} ).catch( e => {
46865
46866					if ( onError ) onError( e );
46867
46868				} );
46869				return;
46870
46871			}
46872
46873			// If cached is not a promise (i.e., it's already an imageBitmap)
46874			setTimeout( function () {
46875
46876				if ( onLoad ) onLoad( cached );
46877
46878				scope.manager.itemEnd( url );
46879
46880			}, 0 );
46881
46882			return cached;
46883
46884		}
46885
46886		const fetchOptions = {};
46887		fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
46888		fetchOptions.headers = this.requestHeader;
46889
46890		const promise = fetch( url, fetchOptions ).then( function ( res ) {
46891
46892			return res.blob();
46893
46894		} ).then( function ( blob ) {
46895
46896			return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );
46897
46898		} ).then( function ( imageBitmap ) {
46899
46900			Cache.add( url, imageBitmap );
46901
46902			if ( onLoad ) onLoad( imageBitmap );
46903
46904			scope.manager.itemEnd( url );
46905
46906			return imageBitmap;
46907
46908		} ).catch( function ( e ) {
46909
46910			if ( onError ) onError( e );
46911
46912			Cache.remove( url );
46913
46914			scope.manager.itemError( url );
46915			scope.manager.itemEnd( url );
46916
46917		} );
46918
46919		Cache.add( url, promise );
46920		scope.manager.itemStart( url );
46921
46922	}
46923
46924}
46925
46926let _context;
46927
46928class AudioContext {
46929
46930	static getContext() {
46931
46932		if ( _context === undefined ) {
46933
46934			_context = new ( window.AudioContext || window.webkitAudioContext )();
46935
46936		}
46937
46938		return _context;
46939
46940	}
46941
46942	static setContext( value ) {
46943
46944		_context = value;
46945
46946	}
46947
46948}
46949
46950class AudioLoader extends Loader {
46951
46952	constructor( manager ) {
46953
46954		super( manager );
46955
46956	}
46957
46958	load( url, onLoad, onProgress, onError ) {
46959
46960		const scope = this;
46961
46962		const loader = new FileLoader( this.manager );
46963		loader.setResponseType( 'arraybuffer' );
46964		loader.setPath( this.path );
46965		loader.setRequestHeader( this.requestHeader );
46966		loader.setWithCredentials( this.withCredentials );
46967		loader.load( url, function ( buffer ) {
46968
46969			try {
46970
46971				// Create a copy of the buffer. The `decodeAudioData` method
46972				// detaches the buffer when complete, preventing reuse.
46973				const bufferCopy = buffer.slice( 0 );
46974
46975				const context = AudioContext.getContext();
46976				context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
46977
46978					onLoad( audioBuffer );
46979
46980				} ).catch( handleError );
46981
46982			} catch ( e ) {
46983
46984				handleError( e );
46985
46986			}
46987
46988		}, onProgress, onError );
46989
46990		function handleError( e ) {
46991
46992			if ( onError ) {
46993
46994				onError( e );
46995
46996			} else {
46997
46998				console.error( e );
46999
47000			}
47001
47002			scope.manager.itemError( url );
47003
47004		}
47005
47006	}
47007
47008}
47009
47010const _eyeRight = /*@__PURE__*/ new Matrix4();
47011const _eyeLeft = /*@__PURE__*/ new Matrix4();
47012const _projectionMatrix = /*@__PURE__*/ new Matrix4();
47013
47014class StereoCamera {
47015
47016	constructor() {
47017
47018		this.type = 'StereoCamera';
47019
47020		this.aspect = 1;
47021
47022		this.eyeSep = 0.064;
47023
47024		this.cameraL = new PerspectiveCamera();
47025		this.cameraL.layers.enable( 1 );
47026		this.cameraL.matrixAutoUpdate = false;
47027
47028		this.cameraR = new PerspectiveCamera();
47029		this.cameraR.layers.enable( 2 );
47030		this.cameraR.matrixAutoUpdate = false;
47031
47032		this._cache = {
47033			focus: null,
47034			fov: null,
47035			aspect: null,
47036			near: null,
47037			far: null,
47038			zoom: null,
47039			eyeSep: null
47040		};
47041
47042	}
47043
47044	update( camera ) {
47045
47046		const cache = this._cache;
47047
47048		const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
47049			cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
47050			cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
47051
47052		if ( needsUpdate ) {
47053
47054			cache.focus = camera.focus;
47055			cache.fov = camera.fov;
47056			cache.aspect = camera.aspect * this.aspect;
47057			cache.near = camera.near;
47058			cache.far = camera.far;
47059			cache.zoom = camera.zoom;
47060			cache.eyeSep = this.eyeSep;
47061
47062			// Off-axis stereoscopic effect based on
47063			// http://paulbourke.net/stereographics/stereorender/
47064
47065			_projectionMatrix.copy( camera.projectionMatrix );
47066			const eyeSepHalf = cache.eyeSep / 2;
47067			const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
47068			const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
47069			let xmin, xmax;
47070
47071			// translate xOffset
47072
47073			_eyeLeft.elements[ 12 ] = - eyeSepHalf;
47074			_eyeRight.elements[ 12 ] = eyeSepHalf;
47075
47076			// for left eye
47077
47078			xmin = - ymax * cache.aspect + eyeSepOnProjection;
47079			xmax = ymax * cache.aspect + eyeSepOnProjection;
47080
47081			_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47082			_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47083
47084			this.cameraL.projectionMatrix.copy( _projectionMatrix );
47085
47086			// for right eye
47087
47088			xmin = - ymax * cache.aspect - eyeSepOnProjection;
47089			xmax = ymax * cache.aspect - eyeSepOnProjection;
47090
47091			_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47092			_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47093
47094			this.cameraR.projectionMatrix.copy( _projectionMatrix );
47095
47096		}
47097
47098		this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
47099		this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
47100
47101	}
47102
47103}
47104
47105class Clock {
47106
47107	constructor( autoStart = true ) {
47108
47109		this.autoStart = autoStart;
47110
47111		this.startTime = 0;
47112		this.oldTime = 0;
47113		this.elapsedTime = 0;
47114
47115		this.running = false;
47116
47117	}
47118
47119	start() {
47120
47121		this.startTime = now();
47122
47123		this.oldTime = this.startTime;
47124		this.elapsedTime = 0;
47125		this.running = true;
47126
47127	}
47128
47129	stop() {
47130
47131		this.getElapsedTime();
47132		this.running = false;
47133		this.autoStart = false;
47134
47135	}
47136
47137	getElapsedTime() {
47138
47139		this.getDelta();
47140		return this.elapsedTime;
47141
47142	}
47143
47144	getDelta() {
47145
47146		let diff = 0;
47147
47148		if ( this.autoStart && ! this.running ) {
47149
47150			this.start();
47151			return 0;
47152
47153		}
47154
47155		if ( this.running ) {
47156
47157			const newTime = now();
47158
47159			diff = ( newTime - this.oldTime ) / 1000;
47160			this.oldTime = newTime;
47161
47162			this.elapsedTime += diff;
47163
47164		}
47165
47166		return diff;
47167
47168	}
47169
47170}
47171
47172function now() {
47173
47174	return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
47175
47176}
47177
47178const _position$1 = /*@__PURE__*/ new Vector3();
47179const _quaternion$1 = /*@__PURE__*/ new Quaternion();
47180const _scale$1 = /*@__PURE__*/ new Vector3();
47181const _orientation$1 = /*@__PURE__*/ new Vector3();
47182
47183class AudioListener extends Object3D {
47184
47185	constructor() {
47186
47187		super();
47188
47189		this.type = 'AudioListener';
47190
47191		this.context = AudioContext.getContext();
47192
47193		this.gain = this.context.createGain();
47194		this.gain.connect( this.context.destination );
47195
47196		this.filter = null;
47197
47198		this.timeDelta = 0;
47199
47200		// private
47201
47202		this._clock = new Clock();
47203
47204	}
47205
47206	getInput() {
47207
47208		return this.gain;
47209
47210	}
47211
47212	removeFilter() {
47213
47214		if ( this.filter !== null ) {
47215
47216			this.gain.disconnect( this.filter );
47217			this.filter.disconnect( this.context.destination );
47218			this.gain.connect( this.context.destination );
47219			this.filter = null;
47220
47221		}
47222
47223		return this;
47224
47225	}
47226
47227	getFilter() {
47228
47229		return this.filter;
47230
47231	}
47232
47233	setFilter( value ) {
47234
47235		if ( this.filter !== null ) {
47236
47237			this.gain.disconnect( this.filter );
47238			this.filter.disconnect( this.context.destination );
47239
47240		} else {
47241
47242			this.gain.disconnect( this.context.destination );
47243
47244		}
47245
47246		this.filter = value;
47247		this.gain.connect( this.filter );
47248		this.filter.connect( this.context.destination );
47249
47250		return this;
47251
47252	}
47253
47254	getMasterVolume() {
47255
47256		return this.gain.gain.value;
47257
47258	}
47259
47260	setMasterVolume( value ) {
47261
47262		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47263
47264		return this;
47265
47266	}
47267
47268	updateMatrixWorld( force ) {
47269
47270		super.updateMatrixWorld( force );
47271
47272		const listener = this.context.listener;
47273		const up = this.up;
47274
47275		this.timeDelta = this._clock.getDelta();
47276
47277		this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );
47278
47279		_orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 );
47280
47281		if ( listener.positionX ) {
47282
47283			// code path for Chrome (see #14393)
47284
47285			const endTime = this.context.currentTime + this.timeDelta;
47286
47287			listener.positionX.linearRampToValueAtTime( _position$1.x, endTime );
47288			listener.positionY.linearRampToValueAtTime( _position$1.y, endTime );
47289			listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );
47290			listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime );
47291			listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime );
47292			listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime );
47293			listener.upX.linearRampToValueAtTime( up.x, endTime );
47294			listener.upY.linearRampToValueAtTime( up.y, endTime );
47295			listener.upZ.linearRampToValueAtTime( up.z, endTime );
47296
47297		} else {
47298
47299			listener.setPosition( _position$1.x, _position$1.y, _position$1.z );
47300			listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z );
47301
47302		}
47303
47304	}
47305
47306}
47307
47308class Audio extends Object3D {
47309
47310	constructor( listener ) {
47311
47312		super();
47313
47314		this.type = 'Audio';
47315
47316		this.listener = listener;
47317		this.context = listener.context;
47318
47319		this.gain = this.context.createGain();
47320		this.gain.connect( listener.getInput() );
47321
47322		this.autoplay = false;
47323
47324		this.buffer = null;
47325		this.detune = 0;
47326		this.loop = false;
47327		this.loopStart = 0;
47328		this.loopEnd = 0;
47329		this.offset = 0;
47330		this.duration = undefined;
47331		this.playbackRate = 1;
47332		this.isPlaying = false;
47333		this.hasPlaybackControl = true;
47334		this.source = null;
47335		this.sourceType = 'empty';
47336
47337		this._startedAt = 0;
47338		this._progress = 0;
47339		this._connected = false;
47340
47341		this.filters = [];
47342
47343	}
47344
47345	getOutput() {
47346
47347		return this.gain;
47348
47349	}
47350
47351	setNodeSource( audioNode ) {
47352
47353		this.hasPlaybackControl = false;
47354		this.sourceType = 'audioNode';
47355		this.source = audioNode;
47356		this.connect();
47357
47358		return this;
47359
47360	}
47361
47362	setMediaElementSource( mediaElement ) {
47363
47364		this.hasPlaybackControl = false;
47365		this.sourceType = 'mediaNode';
47366		this.source = this.context.createMediaElementSource( mediaElement );
47367		this.connect();
47368
47369		return this;
47370
47371	}
47372
47373	setMediaStreamSource( mediaStream ) {
47374
47375		this.hasPlaybackControl = false;
47376		this.sourceType = 'mediaStreamNode';
47377		this.source = this.context.createMediaStreamSource( mediaStream );
47378		this.connect();
47379
47380		return this;
47381
47382	}
47383
47384	setBuffer( audioBuffer ) {
47385
47386		this.buffer = audioBuffer;
47387		this.sourceType = 'buffer';
47388
47389		if ( this.autoplay ) this.play();
47390
47391		return this;
47392
47393	}
47394
47395	play( delay = 0 ) {
47396
47397		if ( this.isPlaying === true ) {
47398
47399			console.warn( 'THREE.Audio: Audio is already playing.' );
47400			return;
47401
47402		}
47403
47404		if ( this.hasPlaybackControl === false ) {
47405
47406			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47407			return;
47408
47409		}
47410
47411		this._startedAt = this.context.currentTime + delay;
47412
47413		const source = this.context.createBufferSource();
47414		source.buffer = this.buffer;
47415		source.loop = this.loop;
47416		source.loopStart = this.loopStart;
47417		source.loopEnd = this.loopEnd;
47418		source.onended = this.onEnded.bind( this );
47419		source.start( this._startedAt, this._progress + this.offset, this.duration );
47420
47421		this.isPlaying = true;
47422
47423		this.source = source;
47424
47425		this.setDetune( this.detune );
47426		this.setPlaybackRate( this.playbackRate );
47427
47428		return this.connect();
47429
47430	}
47431
47432	pause() {
47433
47434		if ( this.hasPlaybackControl === false ) {
47435
47436			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47437			return;
47438
47439		}
47440
47441		if ( this.isPlaying === true ) {
47442
47443			// update current progress
47444
47445			this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
47446
47447			if ( this.loop === true ) {
47448
47449				// ensure _progress does not exceed duration with looped audios
47450
47451				this._progress = this._progress % ( this.duration || this.buffer.duration );
47452
47453			}
47454
47455			this.source.stop();
47456			this.source.onended = null;
47457
47458			this.isPlaying = false;
47459
47460		}
47461
47462		return this;
47463
47464	}
47465
47466	stop() {
47467
47468		if ( this.hasPlaybackControl === false ) {
47469
47470			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47471			return;
47472
47473		}
47474
47475		this._progress = 0;
47476
47477		if ( this.source !== null ) {
47478
47479			this.source.stop();
47480			this.source.onended = null;
47481
47482		}
47483
47484		this.isPlaying = false;
47485
47486		return this;
47487
47488	}
47489
47490	connect() {
47491
47492		if ( this.filters.length > 0 ) {
47493
47494			this.source.connect( this.filters[ 0 ] );
47495
47496			for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47497
47498				this.filters[ i - 1 ].connect( this.filters[ i ] );
47499
47500			}
47501
47502			this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
47503
47504		} else {
47505
47506			this.source.connect( this.getOutput() );
47507
47508		}
47509
47510		this._connected = true;
47511
47512		return this;
47513
47514	}
47515
47516	disconnect() {
47517
47518		if ( this._connected === false ) {
47519
47520			return;
47521
47522		}
47523
47524		if ( this.filters.length > 0 ) {
47525
47526			this.source.disconnect( this.filters[ 0 ] );
47527
47528			for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47529
47530				this.filters[ i - 1 ].disconnect( this.filters[ i ] );
47531
47532			}
47533
47534			this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
47535
47536		} else {
47537
47538			this.source.disconnect( this.getOutput() );
47539
47540		}
47541
47542		this._connected = false;
47543
47544		return this;
47545
47546	}
47547
47548	getFilters() {
47549
47550		return this.filters;
47551
47552	}
47553
47554	setFilters( value ) {
47555
47556		if ( ! value ) value = [];
47557
47558		if ( this._connected === true ) {
47559
47560			this.disconnect();
47561			this.filters = value.slice();
47562			this.connect();
47563
47564		} else {
47565
47566			this.filters = value.slice();
47567
47568		}
47569
47570		return this;
47571
47572	}
47573
47574	setDetune( value ) {
47575
47576		this.detune = value;
47577
47578		if ( this.source.detune === undefined ) return; // only set detune when available
47579
47580		if ( this.isPlaying === true ) {
47581
47582			this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
47583
47584		}
47585
47586		return this;
47587
47588	}
47589
47590	getDetune() {
47591
47592		return this.detune;
47593
47594	}
47595
47596	getFilter() {
47597
47598		return this.getFilters()[ 0 ];
47599
47600	}
47601
47602	setFilter( filter ) {
47603
47604		return this.setFilters( filter ? [ filter ] : [] );
47605
47606	}
47607
47608	setPlaybackRate( value ) {
47609
47610		if ( this.hasPlaybackControl === false ) {
47611
47612			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47613			return;
47614
47615		}
47616
47617		this.playbackRate = value;
47618
47619		if ( this.isPlaying === true ) {
47620
47621			this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
47622
47623		}
47624
47625		return this;
47626
47627	}
47628
47629	getPlaybackRate() {
47630
47631		return this.playbackRate;
47632
47633	}
47634
47635	onEnded() {
47636
47637		this.isPlaying = false;
47638
47639	}
47640
47641	getLoop() {
47642
47643		if ( this.hasPlaybackControl === false ) {
47644
47645			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47646			return false;
47647
47648		}
47649
47650		return this.loop;
47651
47652	}
47653
47654	setLoop( value ) {
47655
47656		if ( this.hasPlaybackControl === false ) {
47657
47658			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47659			return;
47660
47661		}
47662
47663		this.loop = value;
47664
47665		if ( this.isPlaying === true ) {
47666
47667			this.source.loop = this.loop;
47668
47669		}
47670
47671		return this;
47672
47673	}
47674
47675	setLoopStart( value ) {
47676
47677		this.loopStart = value;
47678
47679		return this;
47680
47681	}
47682
47683	setLoopEnd( value ) {
47684
47685		this.loopEnd = value;
47686
47687		return this;
47688
47689	}
47690
47691	getVolume() {
47692
47693		return this.gain.gain.value;
47694
47695	}
47696
47697	setVolume( value ) {
47698
47699		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47700
47701		return this;
47702
47703	}
47704
47705}
47706
47707const _position = /*@__PURE__*/ new Vector3();
47708const _quaternion = /*@__PURE__*/ new Quaternion();
47709const _scale = /*@__PURE__*/ new Vector3();
47710const _orientation = /*@__PURE__*/ new Vector3();
47711
47712class PositionalAudio extends Audio {
47713
47714	constructor( listener ) {
47715
47716		super( listener );
47717
47718		this.panner = this.context.createPanner();
47719		this.panner.panningModel = 'HRTF';
47720		this.panner.connect( this.gain );
47721
47722	}
47723
47724	connect() {
47725
47726		super.connect();
47727
47728		this.panner.connect( this.gain );
47729
47730	}
47731
47732	disconnect() {
47733
47734		super.disconnect();
47735
47736		this.panner.disconnect( this.gain );
47737
47738	}
47739
47740	getOutput() {
47741
47742		return this.panner;
47743
47744	}
47745
47746	getRefDistance() {
47747
47748		return this.panner.refDistance;
47749
47750	}
47751
47752	setRefDistance( value ) {
47753
47754		this.panner.refDistance = value;
47755
47756		return this;
47757
47758	}
47759
47760	getRolloffFactor() {
47761
47762		return this.panner.rolloffFactor;
47763
47764	}
47765
47766	setRolloffFactor( value ) {
47767
47768		this.panner.rolloffFactor = value;
47769
47770		return this;
47771
47772	}
47773
47774	getDistanceModel() {
47775
47776		return this.panner.distanceModel;
47777
47778	}
47779
47780	setDistanceModel( value ) {
47781
47782		this.panner.distanceModel = value;
47783
47784		return this;
47785
47786	}
47787
47788	getMaxDistance() {
47789
47790		return this.panner.maxDistance;
47791
47792	}
47793
47794	setMaxDistance( value ) {
47795
47796		this.panner.maxDistance = value;
47797
47798		return this;
47799
47800	}
47801
47802	setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
47803
47804		this.panner.coneInnerAngle = coneInnerAngle;
47805		this.panner.coneOuterAngle = coneOuterAngle;
47806		this.panner.coneOuterGain = coneOuterGain;
47807
47808		return this;
47809
47810	}
47811
47812	updateMatrixWorld( force ) {
47813
47814		super.updateMatrixWorld( force );
47815
47816		if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
47817
47818		this.matrixWorld.decompose( _position, _quaternion, _scale );
47819
47820		_orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );
47821
47822		const panner = this.panner;
47823
47824		if ( panner.positionX ) {
47825
47826			// code path for Chrome and Firefox (see #14393)
47827
47828			const endTime = this.context.currentTime + this.listener.timeDelta;
47829
47830			panner.positionX.linearRampToValueAtTime( _position.x, endTime );
47831			panner.positionY.linearRampToValueAtTime( _position.y, endTime );
47832			panner.positionZ.linearRampToValueAtTime( _position.z, endTime );
47833			panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );
47834			panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );
47835			panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );
47836
47837		} else {
47838
47839			panner.setPosition( _position.x, _position.y, _position.z );
47840			panner.setOrientation( _orientation.x, _orientation.y, _orientation.z );
47841
47842		}
47843
47844	}
47845
47846}
47847
47848class AudioAnalyser {
47849
47850	constructor( audio, fftSize = 2048 ) {
47851
47852		this.analyser = audio.context.createAnalyser();
47853		this.analyser.fftSize = fftSize;
47854
47855		this.data = new Uint8Array( this.analyser.frequencyBinCount );
47856
47857		audio.getOutput().connect( this.analyser );
47858
47859	}
47860
47861
47862	getFrequencyData() {
47863
47864		this.analyser.getByteFrequencyData( this.data );
47865
47866		return this.data;
47867
47868	}
47869
47870	getAverageFrequency() {
47871
47872		let value = 0;
47873		const data = this.getFrequencyData();
47874
47875		for ( let i = 0; i < data.length; i ++ ) {
47876
47877			value += data[ i ];
47878
47879		}
47880
47881		return value / data.length;
47882
47883	}
47884
47885}
47886
47887class PropertyMixer {
47888
47889	constructor( binding, typeName, valueSize ) {
47890
47891		this.binding = binding;
47892		this.valueSize = valueSize;
47893
47894		let mixFunction,
47895			mixFunctionAdditive,
47896			setIdentity;
47897
47898		// buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
47899		//
47900		// interpolators can use .buffer as their .result
47901		// the data then goes to 'incoming'
47902		//
47903		// 'accu0' and 'accu1' are used frame-interleaved for
47904		// the cumulative result and are compared to detect
47905		// changes
47906		//
47907		// 'orig' stores the original state of the property
47908		//
47909		// 'add' is used for additive cumulative results
47910		//
47911		// 'work' is optional and is only present for quaternion types. It is used
47912		// to store intermediate quaternion multiplication results
47913
47914		switch ( typeName ) {
47915
47916			case 'quaternion':
47917				mixFunction = this._slerp;
47918				mixFunctionAdditive = this._slerpAdditive;
47919				setIdentity = this._setAdditiveIdentityQuaternion;
47920
47921				this.buffer = new Float64Array( valueSize * 6 );
47922				this._workIndex = 5;
47923				break;
47924
47925			case 'string':
47926			case 'bool':
47927				mixFunction = this._select;
47928
47929				// Use the regular mix function and for additive on these types,
47930				// additive is not relevant for non-numeric types
47931				mixFunctionAdditive = this._select;
47932
47933				setIdentity = this._setAdditiveIdentityOther;
47934
47935				this.buffer = new Array( valueSize * 5 );
47936				break;
47937
47938			default:
47939				mixFunction = this._lerp;
47940				mixFunctionAdditive = this._lerpAdditive;
47941				setIdentity = this._setAdditiveIdentityNumeric;
47942
47943				this.buffer = new Float64Array( valueSize * 5 );
47944
47945		}
47946
47947		this._mixBufferRegion = mixFunction;
47948		this._mixBufferRegionAdditive = mixFunctionAdditive;
47949		this._setIdentity = setIdentity;
47950		this._origIndex = 3;
47951		this._addIndex = 4;
47952
47953		this.cumulativeWeight = 0;
47954		this.cumulativeWeightAdditive = 0;
47955
47956		this.useCount = 0;
47957		this.referenceCount = 0;
47958
47959	}
47960
47961	// accumulate data in the 'incoming' region into 'accu<i>'
47962	accumulate( accuIndex, weight ) {
47963
47964		// note: happily accumulating nothing when weight = 0, the caller knows
47965		// the weight and shouldn't have made the call in the first place
47966
47967		const buffer = this.buffer,
47968			stride = this.valueSize,
47969			offset = accuIndex * stride + stride;
47970
47971		let currentWeight = this.cumulativeWeight;
47972
47973		if ( currentWeight === 0 ) {
47974
47975			// accuN := incoming * weight
47976
47977			for ( let i = 0; i !== stride; ++ i ) {
47978
47979				buffer[ offset + i ] = buffer[ i ];
47980
47981			}
47982
47983			currentWeight = weight;
47984
47985		} else {
47986
47987			// accuN := accuN + incoming * weight
47988
47989			currentWeight += weight;
47990			const mix = weight / currentWeight;
47991			this._mixBufferRegion( buffer, offset, 0, mix, stride );
47992
47993		}
47994
47995		this.cumulativeWeight = currentWeight;
47996
47997	}
47998
47999	// accumulate data in the 'incoming' region into 'add'
48000	accumulateAdditive( weight ) {
48001
48002		const buffer = this.buffer,
48003			stride = this.valueSize,
48004			offset = stride * this._addIndex;
48005
48006		if ( this.cumulativeWeightAdditive === 0 ) {
48007
48008			// add = identity
48009
48010			this._setIdentity();
48011
48012		}
48013
48014		// add := add + incoming * weight
48015
48016		this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
48017		this.cumulativeWeightAdditive += weight;
48018
48019	}
48020
48021	// apply the state of 'accu<i>' to the binding when accus differ
48022	apply( accuIndex ) {
48023
48024		const stride = this.valueSize,
48025			buffer = this.buffer,
48026			offset = accuIndex * stride + stride,
48027
48028			weight = this.cumulativeWeight,
48029			weightAdditive = this.cumulativeWeightAdditive,
48030
48031			binding = this.binding;
48032
48033		this.cumulativeWeight = 0;
48034		this.cumulativeWeightAdditive = 0;
48035
48036		if ( weight < 1 ) {
48037
48038			// accuN := accuN + original * ( 1 - cumulativeWeight )
48039
48040			const originalValueOffset = stride * this._origIndex;
48041
48042			this._mixBufferRegion(
48043				buffer, offset, originalValueOffset, 1 - weight, stride );
48044
48045		}
48046
48047		if ( weightAdditive > 0 ) {
48048
48049			// accuN := accuN + additive accuN
48050
48051			this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
48052
48053		}
48054
48055		for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
48056
48057			if ( buffer[ i ] !== buffer[ i + stride ] ) {
48058
48059				// value has changed -> update scene graph
48060
48061				binding.setValue( buffer, offset );
48062				break;
48063
48064			}
48065
48066		}
48067
48068	}
48069
48070	// remember the state of the bound property and copy it to both accus
48071	saveOriginalState() {
48072
48073		const binding = this.binding;
48074
48075		const buffer = this.buffer,
48076			stride = this.valueSize,
48077
48078			originalValueOffset = stride * this._origIndex;
48079
48080		binding.getValue( buffer, originalValueOffset );
48081
48082		// accu[0..1] := orig -- initially detect changes against the original
48083		for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
48084
48085			buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
48086
48087		}
48088
48089		// Add to identity for additive
48090		this._setIdentity();
48091
48092		this.cumulativeWeight = 0;
48093		this.cumulativeWeightAdditive = 0;
48094
48095	}
48096
48097	// apply the state previously taken via 'saveOriginalState' to the binding
48098	restoreOriginalState() {
48099
48100		const originalValueOffset = this.valueSize * 3;
48101		this.binding.setValue( this.buffer, originalValueOffset );
48102
48103	}
48104
48105	_setAdditiveIdentityNumeric() {
48106
48107		const startIndex = this._addIndex * this.valueSize;
48108		const endIndex = startIndex + this.valueSize;
48109
48110		for ( let i = startIndex; i < endIndex; i ++ ) {
48111
48112			this.buffer[ i ] = 0;
48113
48114		}
48115
48116	}
48117
48118	_setAdditiveIdentityQuaternion() {
48119
48120		this._setAdditiveIdentityNumeric();
48121		this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
48122
48123	}
48124
48125	_setAdditiveIdentityOther() {
48126
48127		const startIndex = this._origIndex * this.valueSize;
48128		const targetIndex = this._addIndex * this.valueSize;
48129
48130		for ( let i = 0; i < this.valueSize; i ++ ) {
48131
48132			this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
48133
48134		}
48135
48136	}
48137
48138
48139	// mix functions
48140
48141	_select( buffer, dstOffset, srcOffset, t, stride ) {
48142
48143		if ( t >= 0.5 ) {
48144
48145			for ( let i = 0; i !== stride; ++ i ) {
48146
48147				buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
48148
48149			}
48150
48151		}
48152
48153	}
48154
48155	_slerp( buffer, dstOffset, srcOffset, t ) {
48156
48157		Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
48158
48159	}
48160
48161	_slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48162
48163		const workOffset = this._workIndex * stride;
48164
48165		// Store result in intermediate buffer offset
48166		Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
48167
48168		// Slerp to the intermediate result
48169		Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
48170
48171	}
48172
48173	_lerp( buffer, dstOffset, srcOffset, t, stride ) {
48174
48175		const s = 1 - t;
48176
48177		for ( let i = 0; i !== stride; ++ i ) {
48178
48179			const j = dstOffset + i;
48180
48181			buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
48182
48183		}
48184
48185	}
48186
48187	_lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48188
48189		for ( let i = 0; i !== stride; ++ i ) {
48190
48191			const j = dstOffset + i;
48192
48193			buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
48194
48195		}
48196
48197	}
48198
48199}
48200
48201// Characters [].:/ are reserved for track binding syntax.
48202const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
48203const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
48204
48205// Attempts to allow node names from any language. ES5's `\w` regexp matches
48206// only latin characters, and the unicode \p{L} is not yet supported. So
48207// instead, we exclude reserved characters and match everything else.
48208const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
48209const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
48210
48211// Parent directories, delimited by '/' or ':'. Currently unused, but must
48212// be matched to parse the rest of the track name.
48213const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
48214
48215// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
48216const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
48217
48218// Object on target node, and accessor. May not contain reserved
48219// characters. Accessor may contain any character except closing bracket.
48220const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
48221
48222// Property and accessor. May not contain reserved characters. Accessor may
48223// contain any non-bracket characters.
48224const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
48225
48226const _trackRe = new RegExp( ''
48227	+ '^'
48228	+ _directoryRe
48229	+ _nodeRe
48230	+ _objectRe
48231	+ _propertyRe
48232	+ '$'
48233);
48234
48235const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ];
48236
48237class Composite {
48238
48239	constructor( targetGroup, path, optionalParsedPath ) {
48240
48241		const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
48242
48243		this._targetGroup = targetGroup;
48244		this._bindings = targetGroup.subscribe_( path, parsedPath );
48245
48246	}
48247
48248	getValue( array, offset ) {
48249
48250		this.bind(); // bind all binding
48251
48252		const firstValidIndex = this._targetGroup.nCachedObjects_,
48253			binding = this._bindings[ firstValidIndex ];
48254
48255		// and only call .getValue on the first
48256		if ( binding !== undefined ) binding.getValue( array, offset );
48257
48258	}
48259
48260	setValue( array, offset ) {
48261
48262		const bindings = this._bindings;
48263
48264		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48265
48266			bindings[ i ].setValue( array, offset );
48267
48268		}
48269
48270	}
48271
48272	bind() {
48273
48274		const bindings = this._bindings;
48275
48276		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48277
48278			bindings[ i ].bind();
48279
48280		}
48281
48282	}
48283
48284	unbind() {
48285
48286		const bindings = this._bindings;
48287
48288		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48289
48290			bindings[ i ].unbind();
48291
48292		}
48293
48294	}
48295
48296}
48297
48298// Note: This class uses a State pattern on a per-method basis:
48299// 'bind' sets 'this.getValue' / 'setValue' and shadows the
48300// prototype version of these methods with one that represents
48301// the bound state. When the property is not found, the methods
48302// become no-ops.
48303class PropertyBinding {
48304
48305	constructor( rootNode, path, parsedPath ) {
48306
48307		this.path = path;
48308		this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
48309
48310		this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName );
48311
48312		this.rootNode = rootNode;
48313
48314		// initial state of these methods that calls 'bind'
48315		this.getValue = this._getValue_unbound;
48316		this.setValue = this._setValue_unbound;
48317
48318	}
48319
48320
48321	static create( root, path, parsedPath ) {
48322
48323		if ( ! ( root && root.isAnimationObjectGroup ) ) {
48324
48325			return new PropertyBinding( root, path, parsedPath );
48326
48327		} else {
48328
48329			return new PropertyBinding.Composite( root, path, parsedPath );
48330
48331		}
48332
48333	}
48334
48335	/**
48336	 * Replaces spaces with underscores and removes unsupported characters from
48337	 * node names, to ensure compatibility with parseTrackName().
48338	 *
48339	 * @param {string} name Node name to be sanitized.
48340	 * @return {string}
48341	 */
48342	static sanitizeNodeName( name ) {
48343
48344		return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
48345
48346	}
48347
48348	static parseTrackName( trackName ) {
48349
48350		const matches = _trackRe.exec( trackName );
48351
48352		if ( matches === null ) {
48353
48354			throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
48355
48356		}
48357
48358		const results = {
48359			// directoryName: matches[ 1 ], // (tschw) currently unused
48360			nodeName: matches[ 2 ],
48361			objectName: matches[ 3 ],
48362			objectIndex: matches[ 4 ],
48363			propertyName: matches[ 5 ], // required
48364			propertyIndex: matches[ 6 ]
48365		};
48366
48367		const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
48368
48369		if ( lastDot !== undefined && lastDot !== - 1 ) {
48370
48371			const objectName = results.nodeName.substring( lastDot + 1 );
48372
48373			// Object names must be checked against an allowlist. Otherwise, there
48374			// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
48375			// 'bar' could be the objectName, or part of a nodeName (which can
48376			// include '.' characters).
48377			if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
48378
48379				results.nodeName = results.nodeName.substring( 0, lastDot );
48380				results.objectName = objectName;
48381
48382			}
48383
48384		}
48385
48386		if ( results.propertyName === null || results.propertyName.length === 0 ) {
48387
48388			throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
48389
48390		}
48391
48392		return results;
48393
48394	}
48395
48396	static findNode( root, nodeName ) {
48397
48398		if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
48399
48400			return root;
48401
48402		}
48403
48404		// search into skeleton bones.
48405		if ( root.skeleton ) {
48406
48407			const bone = root.skeleton.getBoneByName( nodeName );
48408
48409			if ( bone !== undefined ) {
48410
48411				return bone;
48412
48413			}
48414
48415		}
48416
48417		// search into node subtree.
48418		if ( root.children ) {
48419
48420			const searchNodeSubtree = function ( children ) {
48421
48422				for ( let i = 0; i < children.length; i ++ ) {
48423
48424					const childNode = children[ i ];
48425
48426					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
48427
48428						return childNode;
48429
48430					}
48431
48432					const result = searchNodeSubtree( childNode.children );
48433
48434					if ( result ) return result;
48435
48436				}
48437
48438				return null;
48439
48440			};
48441
48442			const subTreeNode = searchNodeSubtree( root.children );
48443
48444			if ( subTreeNode ) {
48445
48446				return subTreeNode;
48447
48448			}
48449
48450		}
48451
48452		return null;
48453
48454	}
48455
48456	// these are used to "bind" a nonexistent property
48457	_getValue_unavailable() {}
48458	_setValue_unavailable() {}
48459
48460	// Getters
48461
48462	_getValue_direct( buffer, offset ) {
48463
48464		buffer[ offset ] = this.targetObject[ this.propertyName ];
48465
48466	}
48467
48468	_getValue_array( buffer, offset ) {
48469
48470		const source = this.resolvedProperty;
48471
48472		for ( let i = 0, n = source.length; i !== n; ++ i ) {
48473
48474			buffer[ offset ++ ] = source[ i ];
48475
48476		}
48477
48478	}
48479
48480	_getValue_arrayElement( buffer, offset ) {
48481
48482		buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
48483
48484	}
48485
48486	_getValue_toArray( buffer, offset ) {
48487
48488		this.resolvedProperty.toArray( buffer, offset );
48489
48490	}
48491
48492	// Direct
48493
48494	_setValue_direct( buffer, offset ) {
48495
48496		this.targetObject[ this.propertyName ] = buffer[ offset ];
48497
48498	}
48499
48500	_setValue_direct_setNeedsUpdate( buffer, offset ) {
48501
48502		this.targetObject[ this.propertyName ] = buffer[ offset ];
48503		this.targetObject.needsUpdate = true;
48504
48505	}
48506
48507	_setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
48508
48509		this.targetObject[ this.propertyName ] = buffer[ offset ];
48510		this.targetObject.matrixWorldNeedsUpdate = true;
48511
48512	}
48513
48514	// EntireArray
48515
48516	_setValue_array( buffer, offset ) {
48517
48518		const dest = this.resolvedProperty;
48519
48520		for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48521
48522			dest[ i ] = buffer[ offset ++ ];
48523
48524		}
48525
48526	}
48527
48528	_setValue_array_setNeedsUpdate( buffer, offset ) {
48529
48530		const dest = this.resolvedProperty;
48531
48532		for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48533
48534			dest[ i ] = buffer[ offset ++ ];
48535
48536		}
48537
48538		this.targetObject.needsUpdate = true;
48539
48540	}
48541
vendor: 7,885 bytes, lines 48542-48873
48542	_setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
48543
48544		const dest = this.resolvedProperty;
48545
48546		for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48547
48548			dest[ i ] = buffer[ offset ++ ];
48549
48550		}
48551
48552		this.targetObject.matrixWorldNeedsUpdate = true;
48553
48554	}
48555
48556	// ArrayElement
48557
48558	_setValue_arrayElement( buffer, offset ) {
48559
48560		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48561
48562	}
48563
48564	_setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
48565
48566		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48567		this.targetObject.needsUpdate = true;
48568
48569	}
48570
48571	_setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
48572
48573		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48574		this.targetObject.matrixWorldNeedsUpdate = true;
48575
48576	}
48577
48578	// HasToFromArray
48579
48580	_setValue_fromArray( buffer, offset ) {
48581
48582		this.resolvedProperty.fromArray( buffer, offset );
48583
48584	}
48585
48586	_setValue_fromArray_setNeedsUpdate( buffer, offset ) {
48587
48588		this.resolvedProperty.fromArray( buffer, offset );
48589		this.targetObject.needsUpdate = true;
48590
48591	}
48592
48593	_setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
48594
48595		this.resolvedProperty.fromArray( buffer, offset );
48596		this.targetObject.matrixWorldNeedsUpdate = true;
48597
48598	}
48599
48600	_getValue_unbound( targetArray, offset ) {
48601
48602		this.bind();
48603		this.getValue( targetArray, offset );
48604
48605	}
48606
48607	_setValue_unbound( sourceArray, offset ) {
48608
48609		this.bind();
48610		this.setValue( sourceArray, offset );
48611
48612	}
48613
48614	// create getter / setter pair for a property in the scene graph
48615	bind() {
48616
48617		let targetObject = this.node;
48618		const parsedPath = this.parsedPath;
48619
48620		const objectName = parsedPath.objectName;
48621		const propertyName = parsedPath.propertyName;
48622		let propertyIndex = parsedPath.propertyIndex;
48623
48624		if ( ! targetObject ) {
48625
48626			targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName );
48627
48628			this.node = targetObject;
48629
48630		}
48631
48632		// set fail state so we can just 'return' on error
48633		this.getValue = this._getValue_unavailable;
48634		this.setValue = this._setValue_unavailable;
48635
48636		// ensure there is a value node
48637		if ( ! targetObject ) {
48638
48639			console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' );
48640			return;
48641
48642		}
48643
48644		if ( objectName ) {
48645
48646			let objectIndex = parsedPath.objectIndex;
48647
48648			// special cases were we need to reach deeper into the hierarchy to get the face materials....
48649			switch ( objectName ) {
48650
48651				case 'materials':
48652
48653					if ( ! targetObject.material ) {
48654
48655						console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48656						return;
48657
48658					}
48659
48660					if ( ! targetObject.material.materials ) {
48661
48662						console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
48663						return;
48664
48665					}
48666
48667					targetObject = targetObject.material.materials;
48668
48669					break;
48670
48671				case 'bones':
48672
48673					if ( ! targetObject.skeleton ) {
48674
48675						console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
48676						return;
48677
48678					}
48679
48680					// potential future optimization: skip this if propertyIndex is already an integer
48681					// and convert the integer string to a true integer.
48682
48683					targetObject = targetObject.skeleton.bones;
48684
48685					// support resolving morphTarget names into indices.
48686					for ( let i = 0; i < targetObject.length; i ++ ) {
48687
48688						if ( targetObject[ i ].name === objectIndex ) {
48689
48690							objectIndex = i;
48691							break;
48692
48693						}
48694
48695					}
48696
48697					break;
48698
48699				case 'map':
48700
48701					if ( 'map' in targetObject ) {
48702
48703						targetObject = targetObject.map;
48704						break;
48705
48706					}
48707
48708					if ( ! targetObject.material ) {
48709
48710						console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48711						return;
48712
48713					}
48714
48715					if ( ! targetObject.material.map ) {
48716
48717						console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this );
48718						return;
48719
48720					}
48721
48722					targetObject = targetObject.material.map;
48723					break;
48724
48725				default:
48726
48727					if ( targetObject[ objectName ] === undefined ) {
48728
48729						console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
48730						return;
48731
48732					}
48733
48734					targetObject = targetObject[ objectName ];
48735
48736			}
48737
48738
48739			if ( objectIndex !== undefined ) {
48740
48741				if ( targetObject[ objectIndex ] === undefined ) {
48742
48743					console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
48744					return;
48745
48746				}
48747
48748				targetObject = targetObject[ objectIndex ];
48749
48750			}
48751
48752		}
48753
48754		// resolve property
48755		const nodeProperty = targetObject[ propertyName ];
48756
48757		if ( nodeProperty === undefined ) {
48758
48759			const nodeName = parsedPath.nodeName;
48760
48761			console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
48762				'.' + propertyName + ' but it wasn\'t found.', targetObject );
48763			return;
48764
48765		}
48766
48767		// determine versioning scheme
48768		let versioning = this.Versioning.None;
48769
48770		this.targetObject = targetObject;
48771
48772		if ( targetObject.needsUpdate !== undefined ) { // material
48773
48774			versioning = this.Versioning.NeedsUpdate;
48775
48776		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
48777
48778			versioning = this.Versioning.MatrixWorldNeedsUpdate;
48779
48780		}
48781
48782		// determine how the property gets bound
48783		let bindingType = this.BindingType.Direct;
48784
48785		if ( propertyIndex !== undefined ) {
48786
48787			// access a sub element of the property array (only primitives are supported right now)
48788
48789			if ( propertyName === 'morphTargetInfluences' ) {
48790
48791				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
48792
48793				// support resolving morphTarget names into indices.
48794				if ( ! targetObject.geometry ) {
48795
48796					console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
48797					return;
48798
48799				}
48800
48801				if ( ! targetObject.geometry.morphAttributes ) {
48802
48803					console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
48804					return;
48805
48806				}
48807
48808				if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
48809
48810					propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
48811
48812				}
48813
48814			}
48815
48816			bindingType = this.BindingType.ArrayElement;
48817
48818			this.resolvedProperty = nodeProperty;
48819			this.propertyIndex = propertyIndex;
48820
48821		} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
48822
48823			// must use copy for Object3D.Euler/Quaternion
48824
48825			bindingType = this.BindingType.HasFromToArray;
48826
48827			this.resolvedProperty = nodeProperty;
48828
48829		} else if ( Array.isArray( nodeProperty ) ) {
48830
48831			bindingType = this.BindingType.EntireArray;
48832
48833			this.resolvedProperty = nodeProperty;
48834
48835		} else {
48836
48837			this.propertyName = propertyName;
48838
48839		}
48840
48841		// select getter / setter
48842		this.getValue = this.GetterByBindingType[ bindingType ];
48843		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
48844
48845	}
48846
48847	unbind() {
48848
48849		this.node = null;
48850
48851		// back to the prototype version of getValue / setValue
48852		// note: avoiding to mutate the shape of 'this' via 'delete'
48853		this.getValue = this._getValue_unbound;
48854		this.setValue = this._setValue_unbound;
48855
48856	}
48857
48858}
48859
48860PropertyBinding.Composite = Composite;
48861
48862PropertyBinding.prototype.BindingType = {
48863	Direct: 0,
48864	EntireArray: 1,
48865	ArrayElement: 2,
48866	HasFromToArray: 3
48867};
48868
48869PropertyBinding.prototype.Versioning = {
48870	None: 0,
48871	NeedsUpdate: 1,
48872	MatrixWorldNeedsUpdate: 2
48873};
vendor: 4,442 bytes, lines 48874-49054
48874
48875PropertyBinding.prototype.GetterByBindingType = [
48876
48877	PropertyBinding.prototype._getValue_direct,
48878	PropertyBinding.prototype._getValue_array,
48879	PropertyBinding.prototype._getValue_arrayElement,
48880	PropertyBinding.prototype._getValue_toArray,
48881
48882];
48883
48884PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [
48885
48886	[
48887		// Direct
48888		PropertyBinding.prototype._setValue_direct,
48889		PropertyBinding.prototype._setValue_direct_setNeedsUpdate,
48890		PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,
48891
48892	], [
48893
48894		// EntireArray
48895
48896		PropertyBinding.prototype._setValue_array,
48897		PropertyBinding.prototype._setValue_array_setNeedsUpdate,
48898		PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,
48899
48900	], [
48901
48902		// ArrayElement
48903		PropertyBinding.prototype._setValue_arrayElement,
48904		PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,
48905		PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,
48906
48907	], [
48908
48909		// HasToFromArray
48910		PropertyBinding.prototype._setValue_fromArray,
48911		PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,
48912		PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,
48913
48914	]
48915
48916];
48917
48918/**
48919 *
48920 * A group of objects that receives a shared animation state.
48921 *
48922 * Usage:
48923 *
48924 *  - Add objects you would otherwise pass as 'root' to the
48925 *    constructor or the .clipAction method of AnimationMixer.
48926 *
48927 *  - Instead pass this object as 'root'.
48928 *
48929 *  - You can also add and remove objects later when the mixer
48930 *    is running.
48931 *
48932 * Note:
48933 *
48934 *    Objects of this class appear as one object to the mixer,
48935 *    so cache control of the individual objects must be done
48936 *    on the group.
48937 *
48938 * Limitation:
48939 *
48940 *  - The animated properties must be compatible among the
48941 *    all objects in the group.
48942 *
48943 *  - A single property can either be controlled through a
48944 *    target group or directly, but not both.
48945 */
48946
48947class AnimationObjectGroup {
48948
48949	constructor() {
48950
48951		this.isAnimationObjectGroup = true;
48952
48953		this.uuid = generateUUID();
48954
48955		// cached objects followed by the active ones
48956		this._objects = Array.prototype.slice.call( arguments );
48957
48958		this.nCachedObjects_ = 0; // threshold
48959		// note: read by PropertyBinding.Composite
48960
48961		const indices = {};
48962		this._indicesByUUID = indices; // for bookkeeping
48963
48964		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
48965
48966			indices[ arguments[ i ].uuid ] = i;
48967
48968		}
48969
48970		this._paths = []; // inside: string
48971		this._parsedPaths = []; // inside: { we don't care, here }
48972		this._bindings = []; // inside: Array< PropertyBinding >
48973		this._bindingsIndicesByPath = {}; // inside: indices in these arrays
48974
48975		const scope = this;
48976
48977		this.stats = {
48978
48979			objects: {
48980				get total() {
48981
48982					return scope._objects.length;
48983
48984				},
48985				get inUse() {
48986
48987					return this.total - scope.nCachedObjects_;
48988
48989				}
48990			},
48991			get bindingsPerObject() {
48992
48993				return scope._bindings.length;
48994
48995			}
48996
48997		};
48998
48999	}
49000
49001	add() {
49002
49003		const objects = this._objects,
49004			indicesByUUID = this._indicesByUUID,
49005			paths = this._paths,
49006			parsedPaths = this._parsedPaths,
49007			bindings = this._bindings,
49008			nBindings = bindings.length;
49009
49010		let knownObject = undefined,
49011			nObjects = objects.length,
49012			nCachedObjects = this.nCachedObjects_;
49013
49014		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49015
49016			const object = arguments[ i ],
49017				uuid = object.uuid;
49018			let index = indicesByUUID[ uuid ];
49019
49020			if ( index === undefined ) {
49021
49022				// unknown object -> add it to the ACTIVE region
49023
49024				index = nObjects ++;
49025				indicesByUUID[ uuid ] = index;
49026				objects.push( object );
49027
49028				// accounting is done, now do the same for all bindings
49029
49030				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49031
49032					bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
49033
49034				}
49035
49036			} else if ( index < nCachedObjects ) {
49037
49038				knownObject = objects[ index ];
49039
49040				// move existing object to the ACTIVE region
49041
49042				const firstActiveIndex = -- nCachedObjects,
49043					lastCachedObject = objects[ firstActiveIndex ];
49044
49045				indicesByUUID[ lastCachedObject.uuid ] = index;
49046				objects[ index ] = lastCachedObject;
49047
49048				indicesByUUID[ uuid ] = firstActiveIndex;
49049				objects[ firstActiveIndex ] = object;
49050
49051				// accounting is done, now do the same for all bindings
49052
49053				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49054
vendor: 4,084 bytes, lines 49055-49210
49055					const bindingsForPath = bindings[ j ],
49056						lastCached = bindingsForPath[ firstActiveIndex ];
49057
49058					let binding = bindingsForPath[ index ];
49059
49060					bindingsForPath[ index ] = lastCached;
49061
49062					if ( binding === undefined ) {
49063
49064						// since we do not bother to create new bindings
49065						// for objects that are cached, the binding may
49066						// or may not exist
49067
49068						binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
49069
49070					}
49071
49072					bindingsForPath[ firstActiveIndex ] = binding;
49073
49074				}
49075
49076			} else if ( objects[ index ] !== knownObject ) {
49077
49078				console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
49079					'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
49080
49081			} // else the object is already where we want it to be
49082
49083		} // for arguments
49084
49085		this.nCachedObjects_ = nCachedObjects;
49086
49087	}
49088
49089	remove() {
49090
49091		const objects = this._objects,
49092			indicesByUUID = this._indicesByUUID,
49093			bindings = this._bindings,
49094			nBindings = bindings.length;
49095
49096		let nCachedObjects = this.nCachedObjects_;
49097
49098		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49099
49100			const object = arguments[ i ],
49101				uuid = object.uuid,
49102				index = indicesByUUID[ uuid ];
49103
49104			if ( index !== undefined && index >= nCachedObjects ) {
49105
49106				// move existing object into the CACHED region
49107
49108				const lastCachedIndex = nCachedObjects ++,
49109					firstActiveObject = objects[ lastCachedIndex ];
49110
49111				indicesByUUID[ firstActiveObject.uuid ] = index;
49112				objects[ index ] = firstActiveObject;
49113
49114				indicesByUUID[ uuid ] = lastCachedIndex;
49115				objects[ lastCachedIndex ] = object;
49116
49117				// accounting is done, now do the same for all bindings
49118
49119				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49120
49121					const bindingsForPath = bindings[ j ],
49122						firstActive = bindingsForPath[ lastCachedIndex ],
49123						binding = bindingsForPath[ index ];
49124
49125					bindingsForPath[ index ] = firstActive;
49126					bindingsForPath[ lastCachedIndex ] = binding;
49127
49128				}
49129
49130			}
49131
49132		} // for arguments
49133
49134		this.nCachedObjects_ = nCachedObjects;
49135
49136	}
49137
49138	// remove & forget
49139	uncache() {
49140
49141		const objects = this._objects,
49142			indicesByUUID = this._indicesByUUID,
49143			bindings = this._bindings,
49144			nBindings = bindings.length;
49145
49146		let nCachedObjects = this.nCachedObjects_,
49147			nObjects = objects.length;
49148
49149		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49150
49151			const object = arguments[ i ],
49152				uuid = object.uuid,
49153				index = indicesByUUID[ uuid ];
49154
49155			if ( index !== undefined ) {
49156
49157				delete indicesByUUID[ uuid ];
49158
49159				if ( index < nCachedObjects ) {
49160
49161					// object is cached, shrink the CACHED region
49162
49163					const firstActiveIndex = -- nCachedObjects,
49164						lastCachedObject = objects[ firstActiveIndex ],
49165						lastIndex = -- nObjects,
49166						lastObject = objects[ lastIndex ];
49167
49168					// last cached object takes this object's place
49169					indicesByUUID[ lastCachedObject.uuid ] = index;
49170					objects[ index ] = lastCachedObject;
49171
49172					// last object goes to the activated slot and pop
49173					indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
49174					objects[ firstActiveIndex ] = lastObject;
49175					objects.pop();
49176
49177					// accounting is done, now do the same for all bindings
49178
49179					for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49180
49181						const bindingsForPath = bindings[ j ],
49182							lastCached = bindingsForPath[ firstActiveIndex ],
49183							last = bindingsForPath[ lastIndex ];
49184
49185						bindingsForPath[ index ] = lastCached;
49186						bindingsForPath[ firstActiveIndex ] = last;
49187						bindingsForPath.pop();
49188
49189					}
49190
49191				} else {
49192
49193					// object is active, just swap with the last and pop
49194
49195					const lastIndex = -- nObjects,
49196						lastObject = objects[ lastIndex ];
49197
49198					if ( lastIndex > 0 ) {
49199
49200						indicesByUUID[ lastObject.uuid ] = index;
49201
49202					}
49203
49204					objects[ index ] = lastObject;
49205					objects.pop();
49206
49207					// accounting is done, now do the same for all bindings
49208
49209					for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49210
vendor: 8,887 bytes, lines 49211-49639
49211						const bindingsForPath = bindings[ j ];
49212
49213						bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
49214						bindingsForPath.pop();
49215
49216					}
49217
49218				} // cached or active
49219
49220			} // if object is known
49221
49222		} // for arguments
49223
49224		this.nCachedObjects_ = nCachedObjects;
49225
49226	}
49227
49228	// Internal interface used by befriended PropertyBinding.Composite:
49229
49230	subscribe_( path, parsedPath ) {
49231
49232		// returns an array of bindings for the given path that is changed
49233		// according to the contained objects in the group
49234
49235		const indicesByPath = this._bindingsIndicesByPath;
49236		let index = indicesByPath[ path ];
49237		const bindings = this._bindings;
49238
49239		if ( index !== undefined ) return bindings[ index ];
49240
49241		const paths = this._paths,
49242			parsedPaths = this._parsedPaths,
49243			objects = this._objects,
49244			nObjects = objects.length,
49245			nCachedObjects = this.nCachedObjects_,
49246			bindingsForPath = new Array( nObjects );
49247
49248		index = bindings.length;
49249
49250		indicesByPath[ path ] = index;
49251
49252		paths.push( path );
49253		parsedPaths.push( parsedPath );
49254		bindings.push( bindingsForPath );
49255
49256		for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
49257
49258			const object = objects[ i ];
49259			bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
49260
49261		}
49262
49263		return bindingsForPath;
49264
49265	}
49266
49267	unsubscribe_( path ) {
49268
49269		// tells the group to forget about a property path and no longer
49270		// update the array previously obtained with 'subscribe_'
49271
49272		const indicesByPath = this._bindingsIndicesByPath,
49273			index = indicesByPath[ path ];
49274
49275		if ( index !== undefined ) {
49276
49277			const paths = this._paths,
49278				parsedPaths = this._parsedPaths,
49279				bindings = this._bindings,
49280				lastBindingsIndex = bindings.length - 1,
49281				lastBindings = bindings[ lastBindingsIndex ],
49282				lastBindingsPath = path[ lastBindingsIndex ];
49283
49284			indicesByPath[ lastBindingsPath ] = index;
49285
49286			bindings[ index ] = lastBindings;
49287			bindings.pop();
49288
49289			parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
49290			parsedPaths.pop();
49291
49292			paths[ index ] = paths[ lastBindingsIndex ];
49293			paths.pop();
49294
49295		}
49296
49297	}
49298
49299}
49300
49301class AnimationAction {
49302
49303	constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
49304
49305		this._mixer = mixer;
49306		this._clip = clip;
49307		this._localRoot = localRoot;
49308		this.blendMode = blendMode;
49309
49310		const tracks = clip.tracks,
49311			nTracks = tracks.length,
49312			interpolants = new Array( nTracks );
49313
49314		const interpolantSettings = {
49315			endingStart: ZeroCurvatureEnding,
49316			endingEnd: ZeroCurvatureEnding
49317		};
49318
49319		for ( let i = 0; i !== nTracks; ++ i ) {
49320
49321			const interpolant = tracks[ i ].createInterpolant( null );
49322			interpolants[ i ] = interpolant;
49323			interpolant.settings = interpolantSettings;
49324
49325		}
49326
49327		this._interpolantSettings = interpolantSettings;
49328
49329		this._interpolants = interpolants; // bound by the mixer
49330
49331		// inside: PropertyMixer (managed by the mixer)
49332		this._propertyBindings = new Array( nTracks );
49333
49334		this._cacheIndex = null; // for the memory manager
49335		this._byClipCacheIndex = null; // for the memory manager
49336
49337		this._timeScaleInterpolant = null;
49338		this._weightInterpolant = null;
49339
49340		this.loop = LoopRepeat;
49341		this._loopCount = - 1;
49342
49343		// global mixer time when the action is to be started
49344		// it's set back to 'null' upon start of the action
49345		this._startTime = null;
49346
49347		// scaled local time of the action
49348		// gets clamped or wrapped to 0..clip.duration according to loop
49349		this.time = 0;
49350
49351		this.timeScale = 1;
49352		this._effectiveTimeScale = 1;
49353
49354		this.weight = 1;
49355		this._effectiveWeight = 1;
49356
49357		this.repetitions = Infinity; // no. of repetitions when looping
49358
49359		this.paused = false; // true -> zero effective time scale
49360		this.enabled = true; // false -> zero effective weight
49361
49362		this.clampWhenFinished = false;// keep feeding the last frame?
49363
49364		this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
49365		this.zeroSlopeAtEnd = true;// clips for start, loop and end
49366
49367	}
49368
49369	// State & Scheduling
49370
49371	play() {
49372
49373		this._mixer._activateAction( this );
49374
49375		return this;
49376
49377	}
49378
49379	stop() {
49380
49381		this._mixer._deactivateAction( this );
49382
49383		return this.reset();
49384
49385	}
49386
49387	reset() {
49388
49389		this.paused = false;
49390		this.enabled = true;
49391
49392		this.time = 0; // restart clip
49393		this._loopCount = - 1;// forget previous loops
49394		this._startTime = null;// forget scheduling
49395
49396		return this.stopFading().stopWarping();
49397
49398	}
49399
49400	isRunning() {
49401
49402		return this.enabled && ! this.paused && this.timeScale !== 0 &&
49403			this._startTime === null && this._mixer._isActiveAction( this );
49404
49405	}
49406
49407	// return true when play has been called
49408	isScheduled() {
49409
49410		return this._mixer._isActiveAction( this );
49411
49412	}
49413
49414	startAt( time ) {
49415
49416		this._startTime = time;
49417
49418		return this;
49419
49420	}
49421
49422	setLoop( mode, repetitions ) {
49423
49424		this.loop = mode;
49425		this.repetitions = repetitions;
49426
49427		return this;
49428
49429	}
49430
49431	// Weight
49432
49433	// set the weight stopping any scheduled fading
49434	// although .enabled = false yields an effective weight of zero, this
49435	// method does *not* change .enabled, because it would be confusing
49436	setEffectiveWeight( weight ) {
49437
49438		this.weight = weight;
49439
49440		// note: same logic as when updated at runtime
49441		this._effectiveWeight = this.enabled ? weight : 0;
49442
49443		return this.stopFading();
49444
49445	}
49446
49447	// return the weight considering fading and .enabled
49448	getEffectiveWeight() {
49449
49450		return this._effectiveWeight;
49451
49452	}
49453
49454	fadeIn( duration ) {
49455
49456		return this._scheduleFading( duration, 0, 1 );
49457
49458	}
49459
49460	fadeOut( duration ) {
49461
49462		return this._scheduleFading( duration, 1, 0 );
49463
49464	}
49465
49466	crossFadeFrom( fadeOutAction, duration, warp ) {
49467
49468		fadeOutAction.fadeOut( duration );
49469		this.fadeIn( duration );
49470
49471		if ( warp ) {
49472
49473			const fadeInDuration = this._clip.duration,
49474				fadeOutDuration = fadeOutAction._clip.duration,
49475
49476				startEndRatio = fadeOutDuration / fadeInDuration,
49477				endStartRatio = fadeInDuration / fadeOutDuration;
49478
49479			fadeOutAction.warp( 1.0, startEndRatio, duration );
49480			this.warp( endStartRatio, 1.0, duration );
49481
49482		}
49483
49484		return this;
49485
49486	}
49487
49488	crossFadeTo( fadeInAction, duration, warp ) {
49489
49490		return fadeInAction.crossFadeFrom( this, duration, warp );
49491
49492	}
49493
49494	stopFading() {
49495
49496		const weightInterpolant = this._weightInterpolant;
49497
49498		if ( weightInterpolant !== null ) {
49499
49500			this._weightInterpolant = null;
49501			this._mixer._takeBackControlInterpolant( weightInterpolant );
49502
49503		}
49504
49505		return this;
49506
49507	}
49508
49509	// Time Scale Control
49510
49511	// set the time scale stopping any scheduled warping
49512	// although .paused = true yields an effective time scale of zero, this
49513	// method does *not* change .paused, because it would be confusing
49514	setEffectiveTimeScale( timeScale ) {
49515
49516		this.timeScale = timeScale;
49517		this._effectiveTimeScale = this.paused ? 0 : timeScale;
49518
49519		return this.stopWarping();
49520
49521	}
49522
49523	// return the time scale considering warping and .paused
49524	getEffectiveTimeScale() {
49525
49526		return this._effectiveTimeScale;
49527
49528	}
49529
49530	setDuration( duration ) {
49531
49532		this.timeScale = this._clip.duration / duration;
49533
49534		return this.stopWarping();
49535
49536	}
49537
49538	syncWith( action ) {
49539
49540		this.time = action.time;
49541		this.timeScale = action.timeScale;
49542
49543		return this.stopWarping();
49544
49545	}
49546
49547	halt( duration ) {
49548
49549		return this.warp( this._effectiveTimeScale, 0, duration );
49550
49551	}
49552
49553	warp( startTimeScale, endTimeScale, duration ) {
49554
49555		const mixer = this._mixer,
49556			now = mixer.time,
49557			timeScale = this.timeScale;
49558
49559		let interpolant = this._timeScaleInterpolant;
49560
49561		if ( interpolant === null ) {
49562
49563			interpolant = mixer._lendControlInterpolant();
49564			this._timeScaleInterpolant = interpolant;
49565
49566		}
49567
49568		const times = interpolant.parameterPositions,
49569			values = interpolant.sampleValues;
49570
49571		times[ 0 ] = now;
49572		times[ 1 ] = now + duration;
49573
49574		values[ 0 ] = startTimeScale / timeScale;
49575		values[ 1 ] = endTimeScale / timeScale;
49576
49577		return this;
49578
49579	}
49580
49581	stopWarping() {
49582
49583		const timeScaleInterpolant = this._timeScaleInterpolant;
49584
49585		if ( timeScaleInterpolant !== null ) {
49586
49587			this._timeScaleInterpolant = null;
49588			this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
49589
49590		}
49591
49592		return this;
49593
49594	}
49595
49596	// Object Accessors
49597
49598	getMixer() {
49599
49600		return this._mixer;
49601
49602	}
49603
49604	getClip() {
49605
49606		return this._clip;
49607
49608	}
49609
49610	getRoot() {
49611
49612		return this._localRoot || this._mixer._root;
49613
49614	}
49615
49616	// Interna
49617
49618	_update( time, deltaTime, timeDirection, accuIndex ) {
49619
49620		// called by the mixer
49621
49622		if ( ! this.enabled ) {
49623
49624			// call ._updateWeight() to update ._effectiveWeight
49625
49626			this._updateWeight( time );
49627			return;
49628
49629		}
49630
49631		const startTime = this._startTime;
49632
49633		if ( startTime !== null ) {
49634
49635			// check for scheduled start of action
49636
49637			const timeRunning = ( time - startTime ) * timeDirection;
49638			if ( timeRunning < 0 || timeDirection === 0 ) {
49639
vendor: 6,403 bytes, lines 49640-49998
49640				deltaTime = 0;
49641
49642			} else {
49643
49644
49645				this._startTime = null; // unschedule
49646				deltaTime = timeDirection * timeRunning;
49647
49648			}
49649
49650		}
49651
49652		// apply time scale and advance time
49653
49654		deltaTime *= this._updateTimeScale( time );
49655		const clipTime = this._updateTime( deltaTime );
49656
49657		// note: _updateTime may disable the action resulting in
49658		// an effective weight of 0
49659
49660		const weight = this._updateWeight( time );
49661
49662		if ( weight > 0 ) {
49663
49664			const interpolants = this._interpolants;
49665			const propertyMixers = this._propertyBindings;
49666
49667			switch ( this.blendMode ) {
49668
49669				case AdditiveAnimationBlendMode:
49670
49671					for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49672
49673						interpolants[ j ].evaluate( clipTime );
49674						propertyMixers[ j ].accumulateAdditive( weight );
49675
49676					}
49677
49678					break;
49679
49680				case NormalAnimationBlendMode:
49681				default:
49682
49683					for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49684
49685						interpolants[ j ].evaluate( clipTime );
49686						propertyMixers[ j ].accumulate( accuIndex, weight );
49687
49688					}
49689
49690			}
49691
49692		}
49693
49694	}
49695
49696	_updateWeight( time ) {
49697
49698		let weight = 0;
49699
49700		if ( this.enabled ) {
49701
49702			weight = this.weight;
49703			const interpolant = this._weightInterpolant;
49704
49705			if ( interpolant !== null ) {
49706
49707				const interpolantValue = interpolant.evaluate( time )[ 0 ];
49708
49709				weight *= interpolantValue;
49710
49711				if ( time > interpolant.parameterPositions[ 1 ] ) {
49712
49713					this.stopFading();
49714
49715					if ( interpolantValue === 0 ) {
49716
49717						// faded out, disable
49718						this.enabled = false;
49719
49720					}
49721
49722				}
49723
49724			}
49725
49726		}
49727
49728		this._effectiveWeight = weight;
49729		return weight;
49730
49731	}
49732
49733	_updateTimeScale( time ) {
49734
49735		let timeScale = 0;
49736
49737		if ( ! this.paused ) {
49738
49739			timeScale = this.timeScale;
49740
49741			const interpolant = this._timeScaleInterpolant;
49742
49743			if ( interpolant !== null ) {
49744
49745				const interpolantValue = interpolant.evaluate( time )[ 0 ];
49746
49747				timeScale *= interpolantValue;
49748
49749				if ( time > interpolant.parameterPositions[ 1 ] ) {
49750
49751					this.stopWarping();
49752
49753					if ( timeScale === 0 ) {
49754
49755						// motion has halted, pause
49756						this.paused = true;
49757
49758					} else {
49759
49760						// warp done - apply final time scale
49761						this.timeScale = timeScale;
49762
49763					}
49764
49765				}
49766
49767			}
49768
49769		}
49770
49771		this._effectiveTimeScale = timeScale;
49772		return timeScale;
49773
49774	}
49775
49776	_updateTime( deltaTime ) {
49777
49778		const duration = this._clip.duration;
49779		const loop = this.loop;
49780
49781		let time = this.time + deltaTime;
49782		let loopCount = this._loopCount;
49783
49784		const pingPong = ( loop === LoopPingPong );
49785
49786		if ( deltaTime === 0 ) {
49787
49788			if ( loopCount === - 1 ) return time;
49789
49790			return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
49791
49792		}
49793
49794		if ( loop === LoopOnce ) {
49795
49796			if ( loopCount === - 1 ) {
49797
49798				// just started
49799
49800				this._loopCount = 0;
49801				this._setEndings( true, true, false );
49802
49803			}
49804
49805			handle_stop: {
49806
49807				if ( time >= duration ) {
49808
49809					time = duration;
49810
49811				} else if ( time < 0 ) {
49812
49813					time = 0;
49814
49815				} else {
49816
49817					this.time = time;
49818
49819					break handle_stop;
49820
49821				}
49822
49823				if ( this.clampWhenFinished ) this.paused = true;
49824				else this.enabled = false;
49825
49826				this.time = time;
49827
49828				this._mixer.dispatchEvent( {
49829					type: 'finished', action: this,
49830					direction: deltaTime < 0 ? - 1 : 1
49831				} );
49832
49833			}
49834
49835		} else { // repetitive Repeat or PingPong
49836
49837			if ( loopCount === - 1 ) {
49838
49839				// just started
49840
49841				if ( deltaTime >= 0 ) {
49842
49843					loopCount = 0;
49844
49845					this._setEndings( true, this.repetitions === 0, pingPong );
49846
49847				} else {
49848
49849					// when looping in reverse direction, the initial
49850					// transition through zero counts as a repetition,
49851					// so leave loopCount at -1
49852
49853					this._setEndings( this.repetitions === 0, true, pingPong );
49854
49855				}
49856
49857			}
49858
49859			if ( time >= duration || time < 0 ) {
49860
49861				// wrap around
49862
49863				const loopDelta = Math.floor( time / duration ); // signed
49864				time -= duration * loopDelta;
49865
49866				loopCount += Math.abs( loopDelta );
49867
49868				const pending = this.repetitions - loopCount;
49869
49870				if ( pending <= 0 ) {
49871
49872					// have to stop (switch state, clamp time, fire event)
49873
49874					if ( this.clampWhenFinished ) this.paused = true;
49875					else this.enabled = false;
49876
49877					time = deltaTime > 0 ? duration : 0;
49878
49879					this.time = time;
49880
49881					this._mixer.dispatchEvent( {
49882						type: 'finished', action: this,
49883						direction: deltaTime > 0 ? 1 : - 1
49884					} );
49885
49886				} else {
49887
49888					// keep running
49889
49890					if ( pending === 1 ) {
49891
49892						// entering the last round
49893
49894						const atStart = deltaTime < 0;
49895						this._setEndings( atStart, ! atStart, pingPong );
49896
49897					} else {
49898
49899						this._setEndings( false, false, pingPong );
49900
49901					}
49902
49903					this._loopCount = loopCount;
49904
49905					this.time = time;
49906
49907					this._mixer.dispatchEvent( {
49908						type: 'loop', action: this, loopDelta: loopDelta
49909					} );
49910
49911				}
49912
49913			} else {
49914
49915				this.time = time;
49916
49917			}
49918
49919			if ( pingPong && ( loopCount & 1 ) === 1 ) {
49920
49921				// invert time for the "pong round"
49922
49923				return duration - time;
49924
49925			}
49926
49927		}
49928
49929		return time;
49930
49931	}
49932
49933	_setEndings( atStart, atEnd, pingPong ) {
49934
49935		const settings = this._interpolantSettings;
49936
49937		if ( pingPong ) {
49938
49939			settings.endingStart = ZeroSlopeEnding;
49940			settings.endingEnd = ZeroSlopeEnding;
49941
49942		} else {
49943
49944			// assuming for LoopOnce atStart == atEnd == true
49945
49946			if ( atStart ) {
49947
49948				settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
49949
49950			} else {
49951
49952				settings.endingStart = WrapAroundEnding;
49953
49954			}
49955
49956			if ( atEnd ) {
49957
49958				settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
49959
49960			} else {
49961
49962				settings.endingEnd 	 = WrapAroundEnding;
49963
49964			}
49965
49966		}
49967
49968	}
49969
49970	_scheduleFading( duration, weightNow, weightThen ) {
49971
49972		const mixer = this._mixer, now = mixer.time;
49973		let interpolant = this._weightInterpolant;
49974
49975		if ( interpolant === null ) {
49976
49977			interpolant = mixer._lendControlInterpolant();
49978			this._weightInterpolant = interpolant;
49979
49980		}
49981
49982		const times = interpolant.parameterPositions,
49983			values = interpolant.sampleValues;
49984
49985		times[ 0 ] = now;
49986		values[ 0 ] = weightNow;
49987		times[ 1 ] = now + duration;
49988		values[ 1 ] = weightThen;
49989
49990		return this;
49991
49992	}
49993
49994}
49995
49996const _controlInterpolantsResultBuffer = new Float32Array( 1 );
49997
49998
vendor: 13,903 bytes, lines 49999-50629
49999class AnimationMixer extends EventDispatcher {
50000
50001	constructor( root ) {
50002
50003		super();
50004
50005		this._root = root;
50006		this._initMemoryManager();
50007		this._accuIndex = 0;
50008		this.time = 0;
50009		this.timeScale = 1.0;
50010
50011	}
50012
50013	_bindAction( action, prototypeAction ) {
50014
50015		const root = action._localRoot || this._root,
50016			tracks = action._clip.tracks,
50017			nTracks = tracks.length,
50018			bindings = action._propertyBindings,
50019			interpolants = action._interpolants,
50020			rootUuid = root.uuid,
50021			bindingsByRoot = this._bindingsByRootAndName;
50022
50023		let bindingsByName = bindingsByRoot[ rootUuid ];
50024
50025		if ( bindingsByName === undefined ) {
50026
50027			bindingsByName = {};
50028			bindingsByRoot[ rootUuid ] = bindingsByName;
50029
50030		}
50031
50032		for ( let i = 0; i !== nTracks; ++ i ) {
50033
50034			const track = tracks[ i ],
50035				trackName = track.name;
50036
50037			let binding = bindingsByName[ trackName ];
50038
50039			if ( binding !== undefined ) {
50040
50041				++ binding.referenceCount;
50042				bindings[ i ] = binding;
50043
50044			} else {
50045
50046				binding = bindings[ i ];
50047
50048				if ( binding !== undefined ) {
50049
50050					// existing binding, make sure the cache knows
50051
50052					if ( binding._cacheIndex === null ) {
50053
50054						++ binding.referenceCount;
50055						this._addInactiveBinding( binding, rootUuid, trackName );
50056
50057					}
50058
50059					continue;
50060
50061				}
50062
50063				const path = prototypeAction && prototypeAction.
50064					_propertyBindings[ i ].binding.parsedPath;
50065
50066				binding = new PropertyMixer(
50067					PropertyBinding.create( root, trackName, path ),
50068					track.ValueTypeName, track.getValueSize() );
50069
50070				++ binding.referenceCount;
50071				this._addInactiveBinding( binding, rootUuid, trackName );
50072
50073				bindings[ i ] = binding;
50074
50075			}
50076
50077			interpolants[ i ].resultBuffer = binding.buffer;
50078
50079		}
50080
50081	}
50082
50083	_activateAction( action ) {
50084
50085		if ( ! this._isActiveAction( action ) ) {
50086
50087			if ( action._cacheIndex === null ) {
50088
50089				// this action has been forgotten by the cache, but the user
50090				// appears to be still using it -> rebind
50091
50092				const rootUuid = ( action._localRoot || this._root ).uuid,
50093					clipUuid = action._clip.uuid,
50094					actionsForClip = this._actionsByClip[ clipUuid ];
50095
50096				this._bindAction( action,
50097					actionsForClip && actionsForClip.knownActions[ 0 ] );
50098
50099				this._addInactiveAction( action, clipUuid, rootUuid );
50100
50101			}
50102
50103			const bindings = action._propertyBindings;
50104
50105			// increment reference counts / sort out state
50106			for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50107
50108				const binding = bindings[ i ];
50109
50110				if ( binding.useCount ++ === 0 ) {
50111
50112					this._lendBinding( binding );
50113					binding.saveOriginalState();
50114
50115				}
50116
50117			}
50118
50119			this._lendAction( action );
50120
50121		}
50122
50123	}
50124
50125	_deactivateAction( action ) {
50126
50127		if ( this._isActiveAction( action ) ) {
50128
50129			const bindings = action._propertyBindings;
50130
50131			// decrement reference counts / sort out state
50132			for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50133
50134				const binding = bindings[ i ];
50135
50136				if ( -- binding.useCount === 0 ) {
50137
50138					binding.restoreOriginalState();
50139					this._takeBackBinding( binding );
50140
50141				}
50142
50143			}
50144
50145			this._takeBackAction( action );
50146
50147		}
50148
50149	}
50150
50151	// Memory manager
50152
50153	_initMemoryManager() {
50154
50155		this._actions = []; // 'nActiveActions' followed by inactive ones
50156		this._nActiveActions = 0;
50157
50158		this._actionsByClip = {};
50159		// inside:
50160		// {
50161		// 	knownActions: Array< AnimationAction > - used as prototypes
50162		// 	actionByRoot: AnimationAction - lookup
50163		// }
50164
50165
50166		this._bindings = []; // 'nActiveBindings' followed by inactive ones
50167		this._nActiveBindings = 0;
50168
50169		this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
50170
50171
50172		this._controlInterpolants = []; // same game as above
50173		this._nActiveControlInterpolants = 0;
50174
50175		const scope = this;
50176
50177		this.stats = {
50178
50179			actions: {
50180				get total() {
50181
50182					return scope._actions.length;
50183
50184				},
50185				get inUse() {
50186
50187					return scope._nActiveActions;
50188
50189				}
50190			},
50191			bindings: {
50192				get total() {
50193
50194					return scope._bindings.length;
50195
50196				},
50197				get inUse() {
50198
50199					return scope._nActiveBindings;
50200
50201				}
50202			},
50203			controlInterpolants: {
50204				get total() {
50205
50206					return scope._controlInterpolants.length;
50207
50208				},
50209				get inUse() {
50210
50211					return scope._nActiveControlInterpolants;
50212
50213				}
50214			}
50215
50216		};
50217
50218	}
50219
50220	// Memory management for AnimationAction objects
50221
50222	_isActiveAction( action ) {
50223
50224		const index = action._cacheIndex;
50225		return index !== null && index < this._nActiveActions;
50226
50227	}
50228
50229	_addInactiveAction( action, clipUuid, rootUuid ) {
50230
50231		const actions = this._actions,
50232			actionsByClip = this._actionsByClip;
50233
50234		let actionsForClip = actionsByClip[ clipUuid ];
50235
50236		if ( actionsForClip === undefined ) {
50237
50238			actionsForClip = {
50239
50240				knownActions: [ action ],
50241				actionByRoot: {}
50242
50243			};
50244
50245			action._byClipCacheIndex = 0;
50246
50247			actionsByClip[ clipUuid ] = actionsForClip;
50248
50249		} else {
50250
50251			const knownActions = actionsForClip.knownActions;
50252
50253			action._byClipCacheIndex = knownActions.length;
50254			knownActions.push( action );
50255
50256		}
50257
50258		action._cacheIndex = actions.length;
50259		actions.push( action );
50260
50261		actionsForClip.actionByRoot[ rootUuid ] = action;
50262
50263	}
50264
50265	_removeInactiveAction( action ) {
50266
50267		const actions = this._actions,
50268			lastInactiveAction = actions[ actions.length - 1 ],
50269			cacheIndex = action._cacheIndex;
50270
50271		lastInactiveAction._cacheIndex = cacheIndex;
50272		actions[ cacheIndex ] = lastInactiveAction;
50273		actions.pop();
50274
50275		action._cacheIndex = null;
50276
50277
50278		const clipUuid = action._clip.uuid,
50279			actionsByClip = this._actionsByClip,
50280			actionsForClip = actionsByClip[ clipUuid ],
50281			knownActionsForClip = actionsForClip.knownActions,
50282
50283			lastKnownAction =
50284				knownActionsForClip[ knownActionsForClip.length - 1 ],
50285
50286			byClipCacheIndex = action._byClipCacheIndex;
50287
50288		lastKnownAction._byClipCacheIndex = byClipCacheIndex;
50289		knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
50290		knownActionsForClip.pop();
50291
50292		action._byClipCacheIndex = null;
50293
50294
50295		const actionByRoot = actionsForClip.actionByRoot,
50296			rootUuid = ( action._localRoot || this._root ).uuid;
50297
50298		delete actionByRoot[ rootUuid ];
50299
50300		if ( knownActionsForClip.length === 0 ) {
50301
50302			delete actionsByClip[ clipUuid ];
50303
50304		}
50305
50306		this._removeInactiveBindingsForAction( action );
50307
50308	}
50309
50310	_removeInactiveBindingsForAction( action ) {
50311
50312		const bindings = action._propertyBindings;
50313
50314		for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50315
50316			const binding = bindings[ i ];
50317
50318			if ( -- binding.referenceCount === 0 ) {
50319
50320				this._removeInactiveBinding( binding );
50321
50322			}
50323
50324		}
50325
50326	}
50327
50328	_lendAction( action ) {
50329
50330		// [ active actions |  inactive actions  ]
50331		// [  active actions >| inactive actions ]
50332		//                 s        a
50333		//                  <-swap->
50334		//                 a        s
50335
50336		const actions = this._actions,
50337			prevIndex = action._cacheIndex,
50338
50339			lastActiveIndex = this._nActiveActions ++,
50340
50341			firstInactiveAction = actions[ lastActiveIndex ];
50342
50343		action._cacheIndex = lastActiveIndex;
50344		actions[ lastActiveIndex ] = action;
50345
50346		firstInactiveAction._cacheIndex = prevIndex;
50347		actions[ prevIndex ] = firstInactiveAction;
50348
50349	}
50350
50351	_takeBackAction( action ) {
50352
50353		// [  active actions  | inactive actions ]
50354		// [ active actions |< inactive actions  ]
50355		//        a        s
50356		//         <-swap->
50357		//        s        a
50358
50359		const actions = this._actions,
50360			prevIndex = action._cacheIndex,
50361
50362			firstInactiveIndex = -- this._nActiveActions,
50363
50364			lastActiveAction = actions[ firstInactiveIndex ];
50365
50366		action._cacheIndex = firstInactiveIndex;
50367		actions[ firstInactiveIndex ] = action;
50368
50369		lastActiveAction._cacheIndex = prevIndex;
50370		actions[ prevIndex ] = lastActiveAction;
50371
50372	}
50373
50374	// Memory management for PropertyMixer objects
50375
50376	_addInactiveBinding( binding, rootUuid, trackName ) {
50377
50378		const bindingsByRoot = this._bindingsByRootAndName,
50379			bindings = this._bindings;
50380
50381		let bindingByName = bindingsByRoot[ rootUuid ];
50382
50383		if ( bindingByName === undefined ) {
50384
50385			bindingByName = {};
50386			bindingsByRoot[ rootUuid ] = bindingByName;
50387
50388		}
50389
50390		bindingByName[ trackName ] = binding;
50391
50392		binding._cacheIndex = bindings.length;
50393		bindings.push( binding );
50394
50395	}
50396
50397	_removeInactiveBinding( binding ) {
50398
50399		const bindings = this._bindings,
50400			propBinding = binding.binding,
50401			rootUuid = propBinding.rootNode.uuid,
50402			trackName = propBinding.path,
50403			bindingsByRoot = this._bindingsByRootAndName,
50404			bindingByName = bindingsByRoot[ rootUuid ],
50405
50406			lastInactiveBinding = bindings[ bindings.length - 1 ],
50407			cacheIndex = binding._cacheIndex;
50408
50409		lastInactiveBinding._cacheIndex = cacheIndex;
50410		bindings[ cacheIndex ] = lastInactiveBinding;
50411		bindings.pop();
50412
50413		delete bindingByName[ trackName ];
50414
50415		if ( Object.keys( bindingByName ).length === 0 ) {
50416
50417			delete bindingsByRoot[ rootUuid ];
50418
50419		}
50420
50421	}
50422
50423	_lendBinding( binding ) {
50424
50425		const bindings = this._bindings,
50426			prevIndex = binding._cacheIndex,
50427
50428			lastActiveIndex = this._nActiveBindings ++,
50429
50430			firstInactiveBinding = bindings[ lastActiveIndex ];
50431
50432		binding._cacheIndex = lastActiveIndex;
50433		bindings[ lastActiveIndex ] = binding;
50434
50435		firstInactiveBinding._cacheIndex = prevIndex;
50436		bindings[ prevIndex ] = firstInactiveBinding;
50437
50438	}
50439
50440	_takeBackBinding( binding ) {
50441
50442		const bindings = this._bindings,
50443			prevIndex = binding._cacheIndex,
50444
50445			firstInactiveIndex = -- this._nActiveBindings,
50446
50447			lastActiveBinding = bindings[ firstInactiveIndex ];
50448
50449		binding._cacheIndex = firstInactiveIndex;
50450		bindings[ firstInactiveIndex ] = binding;
50451
50452		lastActiveBinding._cacheIndex = prevIndex;
50453		bindings[ prevIndex ] = lastActiveBinding;
50454
50455	}
50456
50457
50458	// Memory management of Interpolants for weight and time scale
50459
50460	_lendControlInterpolant() {
50461
50462		const interpolants = this._controlInterpolants,
50463			lastActiveIndex = this._nActiveControlInterpolants ++;
50464
50465		let interpolant = interpolants[ lastActiveIndex ];
50466
50467		if ( interpolant === undefined ) {
50468
50469			interpolant = new LinearInterpolant(
50470				new Float32Array( 2 ), new Float32Array( 2 ),
50471				1, _controlInterpolantsResultBuffer );
50472
50473			interpolant.__cacheIndex = lastActiveIndex;
50474			interpolants[ lastActiveIndex ] = interpolant;
50475
50476		}
50477
50478		return interpolant;
50479
50480	}
50481
50482	_takeBackControlInterpolant( interpolant ) {
50483
50484		const interpolants = this._controlInterpolants,
50485			prevIndex = interpolant.__cacheIndex,
50486
50487			firstInactiveIndex = -- this._nActiveControlInterpolants,
50488
50489			lastActiveInterpolant = interpolants[ firstInactiveIndex ];
50490
50491		interpolant.__cacheIndex = firstInactiveIndex;
50492		interpolants[ firstInactiveIndex ] = interpolant;
50493
50494		lastActiveInterpolant.__cacheIndex = prevIndex;
50495		interpolants[ prevIndex ] = lastActiveInterpolant;
50496
50497	}
50498
50499	// return an action for a clip optionally using a custom root target
50500	// object (this method allocates a lot of dynamic memory in case a
50501	// previously unknown clip/root combination is specified)
50502	clipAction( clip, optionalRoot, blendMode ) {
50503
50504		const root = optionalRoot || this._root,
50505			rootUuid = root.uuid;
50506
50507		let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
50508
50509		const clipUuid = clipObject !== null ? clipObject.uuid : clip;
50510
50511		const actionsForClip = this._actionsByClip[ clipUuid ];
50512		let prototypeAction = null;
50513
50514		if ( blendMode === undefined ) {
50515
50516			if ( clipObject !== null ) {
50517
50518
50519				blendMode = clipObject.blendMode;
50520
50521			} else {
50522
50523				blendMode = NormalAnimationBlendMode;
50524
50525			}
50526
50527		}
50528
50529		if ( actionsForClip !== undefined ) {
50530
50531			const existingAction = actionsForClip.actionByRoot[ rootUuid ];
50532
50533			if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
50534
50535				return existingAction;
50536
50537			}
50538
50539			// we know the clip, so we don't have to parse all
50540			// the bindings again but can just copy
50541			prototypeAction = actionsForClip.knownActions[ 0 ];
50542
50543			// also, take the clip from the prototype action
50544			if ( clipObject === null )
50545				clipObject = prototypeAction._clip;
50546
50547		}
50548
50549		// clip must be known when specified via string
50550		if ( clipObject === null ) return null;
50551
50552		// allocate all resources required to run it
50553		const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
50554
50555		this._bindAction( newAction, prototypeAction );
50556
50557		// and make the action known to the memory manager
50558		this._addInactiveAction( newAction, clipUuid, rootUuid );
50559
50560		return newAction;
50561
50562	}
50563
50564	// get an existing action
50565	existingAction( clip, optionalRoot ) {
50566
50567		const root = optionalRoot || this._root,
50568			rootUuid = root.uuid,
50569
50570			clipObject = typeof clip === 'string' ?
50571				AnimationClip.findByName( root, clip ) : clip,
50572
50573			clipUuid = clipObject ? clipObject.uuid : clip,
50574
50575			actionsForClip = this._actionsByClip[ clipUuid ];
50576
50577		if ( actionsForClip !== undefined ) {
50578
50579			return actionsForClip.actionByRoot[ rootUuid ] || null;
50580
50581		}
50582
50583		return null;
50584
50585	}
50586
50587	// deactivates all previously scheduled actions
50588	stopAllAction() {
50589
50590		const actions = this._actions,
50591			nActions = this._nActiveActions;
50592
50593		for ( let i = nActions - 1; i >= 0; -- i ) {
50594
50595			actions[ i ].stop();
50596
50597		}
50598
50599		return this;
50600
50601	}
50602
50603	// advance the time and update apply the animation
50604	update( deltaTime ) {
50605
50606		deltaTime *= this.timeScale;
50607
50608		const actions = this._actions,
50609			nActions = this._nActiveActions,
50610
50611			time = this.time += deltaTime,
50612			timeDirection = Math.sign( deltaTime ),
50613
50614			accuIndex = this._accuIndex ^= 1;
50615
50616		// run active actions
50617
50618		for ( let i = 0; i !== nActions; ++ i ) {
50619
50620			const action = actions[ i ];
50621
50622			action._update( time, deltaTime, timeDirection, accuIndex );
50623
50624		}
50625
50626		// update scene graph
50627
50628		const bindings = this._bindings,
50629			nBindings = this._nActiveBindings;
vendor: 3,018 bytes, lines 50630-50774
50630
50631		for ( let i = 0; i !== nBindings; ++ i ) {
50632
50633			bindings[ i ].apply( accuIndex );
50634
50635		}
50636
50637		return this;
50638
50639	}
50640
50641	// Allows you to seek to a specific time in an animation.
50642	setTime( timeInSeconds ) {
50643
50644		this.time = 0; // Zero out time attribute for AnimationMixer object;
50645		for ( let i = 0; i < this._actions.length; i ++ ) {
50646
50647			this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
50648
50649		}
50650
50651		return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
50652
50653	}
50654
50655	// return this mixer's root target object
50656	getRoot() {
50657
50658		return this._root;
50659
50660	}
50661
50662	// free all resources specific to a particular clip
50663	uncacheClip( clip ) {
50664
50665		const actions = this._actions,
50666			clipUuid = clip.uuid,
50667			actionsByClip = this._actionsByClip,
50668			actionsForClip = actionsByClip[ clipUuid ];
50669
50670		if ( actionsForClip !== undefined ) {
50671
50672			// note: just calling _removeInactiveAction would mess up the
50673			// iteration state and also require updating the state we can
50674			// just throw away
50675
50676			const actionsToRemove = actionsForClip.knownActions;
50677
50678			for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
50679
50680				const action = actionsToRemove[ i ];
50681
50682				this._deactivateAction( action );
50683
50684				const cacheIndex = action._cacheIndex,
50685					lastInactiveAction = actions[ actions.length - 1 ];
50686
50687				action._cacheIndex = null;
50688				action._byClipCacheIndex = null;
50689
50690				lastInactiveAction._cacheIndex = cacheIndex;
50691				actions[ cacheIndex ] = lastInactiveAction;
50692				actions.pop();
50693
50694				this._removeInactiveBindingsForAction( action );
50695
50696			}
50697
50698			delete actionsByClip[ clipUuid ];
50699
50700		}
50701
50702	}
50703
50704	// free all resources specific to a particular root target object
50705	uncacheRoot( root ) {
50706
50707		const rootUuid = root.uuid,
50708			actionsByClip = this._actionsByClip;
50709
50710		for ( const clipUuid in actionsByClip ) {
50711
50712			const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
50713				action = actionByRoot[ rootUuid ];
50714
50715			if ( action !== undefined ) {
50716
50717				this._deactivateAction( action );
50718				this._removeInactiveAction( action );
50719
50720			}
50721
50722		}
50723
50724		const bindingsByRoot = this._bindingsByRootAndName,
50725			bindingByName = bindingsByRoot[ rootUuid ];
50726
50727		if ( bindingByName !== undefined ) {
50728
50729			for ( const trackName in bindingByName ) {
50730
50731				const binding = bindingByName[ trackName ];
50732				binding.restoreOriginalState();
50733				this._removeInactiveBinding( binding );
50734
50735			}
50736
50737		}
50738
50739	}
50740
50741	// remove a targeted clip from the cache
50742	uncacheAction( clip, optionalRoot ) {
50743
50744		const action = this.existingAction( clip, optionalRoot );
50745
50746		if ( action !== null ) {
50747
50748			this._deactivateAction( action );
50749			this._removeInactiveAction( action );
50750
50751		}
50752
50753	}
50754
50755}
50756
50757class Uniform {
50758
50759	constructor( value ) {
50760
50761		this.value = value;
50762
50763	}
50764
50765	clone() {
50766
50767		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
50768
50769	}
50770
50771}
50772
50773let _id = 0;
50774
vendor: 5,238 bytes, lines 50775-51086
50775class UniformsGroup extends EventDispatcher {
50776
50777	constructor() {
50778
50779		super();
50780
50781		this.isUniformsGroup = true;
50782
50783		Object.defineProperty( this, 'id', { value: _id ++ } );
50784
50785		this.name = '';
50786
50787		this.usage = StaticDrawUsage;
50788		this.uniforms = [];
50789
50790	}
50791
50792	add( uniform ) {
50793
50794		this.uniforms.push( uniform );
50795
50796		return this;
50797
50798	}
50799
50800	remove( uniform ) {
50801
50802		const index = this.uniforms.indexOf( uniform );
50803
50804		if ( index !== - 1 ) this.uniforms.splice( index, 1 );
50805
50806		return this;
50807
50808	}
50809
50810	setName( name ) {
50811
50812		this.name = name;
50813
50814		return this;
50815
50816	}
50817
50818	setUsage( value ) {
50819
50820		this.usage = value;
50821
50822		return this;
50823
50824	}
50825
50826	dispose() {
50827
50828		this.dispatchEvent( { type: 'dispose' } );
50829
50830		return this;
50831
50832	}
50833
50834	copy( source ) {
50835
50836		this.name = source.name;
50837		this.usage = source.usage;
50838
50839		const uniformsSource = source.uniforms;
50840
50841		this.uniforms.length = 0;
50842
50843		for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) {
50844
50845			const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ];
50846
50847			for ( let j = 0; j < uniforms.length; j ++ ) {
50848
50849				this.uniforms.push( uniforms[ j ].clone() );
50850
50851			}
50852
50853		}
50854
50855		return this;
50856
50857	}
50858
50859	clone() {
50860
50861		return new this.constructor().copy( this );
50862
50863	}
50864
50865}
50866
50867class InstancedInterleavedBuffer extends InterleavedBuffer {
50868
50869	constructor( array, stride, meshPerAttribute = 1 ) {
50870
50871		super( array, stride );
50872
50873		this.isInstancedInterleavedBuffer = true;
50874
50875		this.meshPerAttribute = meshPerAttribute;
50876
50877	}
50878
50879	copy( source ) {
50880
50881		super.copy( source );
50882
50883		this.meshPerAttribute = source.meshPerAttribute;
50884
50885		return this;
50886
50887	}
50888
50889	clone( data ) {
50890
50891		const ib = super.clone( data );
50892
50893		ib.meshPerAttribute = this.meshPerAttribute;
50894
50895		return ib;
50896
50897	}
50898
50899	toJSON( data ) {
50900
50901		const json = super.toJSON( data );
50902
50903		json.isInstancedInterleavedBuffer = true;
50904		json.meshPerAttribute = this.meshPerAttribute;
50905
50906		return json;
50907
50908	}
50909
50910}
50911
50912class GLBufferAttribute {
50913
50914	constructor( buffer, type, itemSize, elementSize, count ) {
50915
50916		this.isGLBufferAttribute = true;
50917
50918		this.name = '';
50919
50920		this.buffer = buffer;
50921		this.type = type;
50922		this.itemSize = itemSize;
50923		this.elementSize = elementSize;
50924		this.count = count;
50925
50926		this.version = 0;
50927
50928	}
50929
50930	set needsUpdate( value ) {
50931
50932		if ( value === true ) this.version ++;
50933
50934	}
50935
50936	setBuffer( buffer ) {
50937
50938		this.buffer = buffer;
50939
50940		return this;
50941
50942	}
50943
50944	setType( type, elementSize ) {
50945
50946		this.type = type;
50947		this.elementSize = elementSize;
50948
50949		return this;
50950
50951	}
50952
50953	setItemSize( itemSize ) {
50954
50955		this.itemSize = itemSize;
50956
50957		return this;
50958
50959	}
50960
50961	setCount( count ) {
50962
50963		this.count = count;
50964
50965		return this;
50966
50967	}
50968
50969}
50970
50971class Raycaster {
50972
50973	constructor( origin, direction, near = 0, far = Infinity ) {
50974
50975		this.ray = new Ray( origin, direction );
50976		// direction is assumed to be normalized (for accurate distance calculations)
50977
50978		this.near = near;
50979		this.far = far;
50980		this.camera = null;
50981		this.layers = new Layers();
50982
50983		this.params = {
50984			Mesh: {},
50985			Line: { threshold: 1 },
50986			LOD: {},
50987			Points: { threshold: 1 },
50988			Sprite: {}
50989		};
50990
50991	}
50992
50993	set( origin, direction ) {
50994
50995		// direction is assumed to be normalized (for accurate distance calculations)
50996
50997		this.ray.set( origin, direction );
50998
50999	}
51000
51001	setFromCamera( coords, camera ) {
51002
51003		if ( camera.isPerspectiveCamera ) {
51004
51005			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
51006			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
51007			this.camera = camera;
51008
51009		} else if ( camera.isOrthographicCamera ) {
51010
51011			this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
51012			this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
51013			this.camera = camera;
51014
51015		} else {
51016
51017			console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
51018
51019		}
51020
51021	}
51022
51023	intersectObject( object, recursive = true, intersects = [] ) {
51024
51025		intersectObject( object, this, intersects, recursive );
51026
51027		intersects.sort( ascSort );
51028
51029		return intersects;
51030
51031	}
51032
51033	intersectObjects( objects, recursive = true, intersects = [] ) {
51034
51035		for ( let i = 0, l = objects.length; i < l; i ++ ) {
51036
51037			intersectObject( objects[ i ], this, intersects, recursive );
51038
51039		}
51040
51041		intersects.sort( ascSort );
51042
51043		return intersects;
51044
51045	}
51046
51047}
51048
51049function ascSort( a, b ) {
51050
51051	return a.distance - b.distance;
51052
51053}
51054
51055function intersectObject( object, raycaster, intersects, recursive ) {
51056
51057	if ( object.layers.test( raycaster.layers ) ) {
51058
51059		object.raycast( raycaster, intersects );
51060
51061	}
51062
51063	if ( recursive === true ) {
51064
51065		const children = object.children;
51066
51067		for ( let i = 0, l = children.length; i < l; i ++ ) {
51068
51069			intersectObject( children[ i ], raycaster, intersects, true );
51070
51071		}
51072
51073	}
51074
51075}
51076
51077/**
51078 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
51079 *
51080 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
51081 * The azimuthal angle (theta) is measured from the positive z-axis.
51082 */
51083
51084
51085class Spherical {
51086
vendor: 25,811 bytes, lines 51087-52296
51087	constructor( radius = 1, phi = 0, theta = 0 ) {
51088
51089		this.radius = radius;
51090		this.phi = phi; // polar angle
51091		this.theta = theta; // azimuthal angle
51092
51093		return this;
51094
51095	}
51096
51097	set( radius, phi, theta ) {
51098
51099		this.radius = radius;
51100		this.phi = phi;
51101		this.theta = theta;
51102
51103		return this;
51104
51105	}
51106
51107	copy( other ) {
51108
51109		this.radius = other.radius;
51110		this.phi = other.phi;
51111		this.theta = other.theta;
51112
51113		return this;
51114
51115	}
51116
51117	// restrict phi to be between EPS and PI-EPS
51118	makeSafe() {
51119
51120		const EPS = 0.000001;
51121		this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
51122
51123		return this;
51124
51125	}
51126
51127	setFromVector3( v ) {
51128
51129		return this.setFromCartesianCoords( v.x, v.y, v.z );
51130
51131	}
51132
51133	setFromCartesianCoords( x, y, z ) {
51134
51135		this.radius = Math.sqrt( x * x + y * y + z * z );
51136
51137		if ( this.radius === 0 ) {
51138
51139			this.theta = 0;
51140			this.phi = 0;
51141
51142		} else {
51143
51144			this.theta = Math.atan2( x, z );
51145			this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) );
51146
51147		}
51148
51149		return this;
51150
51151	}
51152
51153	clone() {
51154
51155		return new this.constructor().copy( this );
51156
51157	}
51158
51159}
51160
51161/**
51162 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
51163 */
51164
51165class Cylindrical {
51166
51167	constructor( radius = 1, theta = 0, y = 0 ) {
51168
51169		this.radius = radius; // distance from the origin to a point in the x-z plane
51170		this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
51171		this.y = y; // height above the x-z plane
51172
51173		return this;
51174
51175	}
51176
51177	set( radius, theta, y ) {
51178
51179		this.radius = radius;
51180		this.theta = theta;
51181		this.y = y;
51182
51183		return this;
51184
51185	}
51186
51187	copy( other ) {
51188
51189		this.radius = other.radius;
51190		this.theta = other.theta;
51191		this.y = other.y;
51192
51193		return this;
51194
51195	}
51196
51197	setFromVector3( v ) {
51198
51199		return this.setFromCartesianCoords( v.x, v.y, v.z );
51200
51201	}
51202
51203	setFromCartesianCoords( x, y, z ) {
51204
51205		this.radius = Math.sqrt( x * x + z * z );
51206		this.theta = Math.atan2( x, z );
51207		this.y = y;
51208
51209		return this;
51210
51211	}
51212
51213	clone() {
51214
51215		return new this.constructor().copy( this );
51216
51217	}
51218
51219}
51220
51221const _vector$4 = /*@__PURE__*/ new Vector2();
51222
51223class Box2 {
51224
51225	constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) {
51226
51227		this.isBox2 = true;
51228
51229		this.min = min;
51230		this.max = max;
51231
51232	}
51233
51234	set( min, max ) {
51235
51236		this.min.copy( min );
51237		this.max.copy( max );
51238
51239		return this;
51240
51241	}
51242
51243	setFromPoints( points ) {
51244
51245		this.makeEmpty();
51246
51247		for ( let i = 0, il = points.length; i < il; i ++ ) {
51248
51249			this.expandByPoint( points[ i ] );
51250
51251		}
51252
51253		return this;
51254
51255	}
51256
51257	setFromCenterAndSize( center, size ) {
51258
51259		const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 );
51260		this.min.copy( center ).sub( halfSize );
51261		this.max.copy( center ).add( halfSize );
51262
51263		return this;
51264
51265	}
51266
51267	clone() {
51268
51269		return new this.constructor().copy( this );
51270
51271	}
51272
51273	copy( box ) {
51274
51275		this.min.copy( box.min );
51276		this.max.copy( box.max );
51277
51278		return this;
51279
51280	}
51281
51282	makeEmpty() {
51283
51284		this.min.x = this.min.y = + Infinity;
51285		this.max.x = this.max.y = - Infinity;
51286
51287		return this;
51288
51289	}
51290
51291	isEmpty() {
51292
51293		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
51294
51295		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
51296
51297	}
51298
51299	getCenter( target ) {
51300
51301		return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
51302
51303	}
51304
51305	getSize( target ) {
51306
51307		return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
51308
51309	}
51310
51311	expandByPoint( point ) {
51312
51313		this.min.min( point );
51314		this.max.max( point );
51315
51316		return this;
51317
51318	}
51319
51320	expandByVector( vector ) {
51321
51322		this.min.sub( vector );
51323		this.max.add( vector );
51324
51325		return this;
51326
51327	}
51328
51329	expandByScalar( scalar ) {
51330
51331		this.min.addScalar( - scalar );
51332		this.max.addScalar( scalar );
51333
51334		return this;
51335
51336	}
51337
51338	containsPoint( point ) {
51339
51340		return point.x < this.min.x || point.x > this.max.x ||
51341			point.y < this.min.y || point.y > this.max.y ? false : true;
51342
51343	}
51344
51345	containsBox( box ) {
51346
51347		return this.min.x <= box.min.x && box.max.x <= this.max.x &&
51348			this.min.y <= box.min.y && box.max.y <= this.max.y;
51349
51350	}
51351
51352	getParameter( point, target ) {
51353
51354		// This can potentially have a divide by zero if the box
51355		// has a size dimension of 0.
51356
51357		return target.set(
51358			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
51359			( point.y - this.min.y ) / ( this.max.y - this.min.y )
51360		);
51361
51362	}
51363
51364	intersectsBox( box ) {
51365
51366		// using 4 splitting planes to rule out intersections
51367
51368		return box.max.x < this.min.x || box.min.x > this.max.x ||
51369			box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
51370
51371	}
51372
51373	clampPoint( point, target ) {
51374
51375		return target.copy( point ).clamp( this.min, this.max );
51376
51377	}
51378
51379	distanceToPoint( point ) {
51380
51381		return this.clampPoint( point, _vector$4 ).distanceTo( point );
51382
51383	}
51384
51385	intersect( box ) {
51386
51387		this.min.max( box.min );
51388		this.max.min( box.max );
51389
51390		if ( this.isEmpty() ) this.makeEmpty();
51391
51392		return this;
51393
51394	}
51395
51396	union( box ) {
51397
51398		this.min.min( box.min );
51399		this.max.max( box.max );
51400
51401		return this;
51402
51403	}
51404
51405	translate( offset ) {
51406
51407		this.min.add( offset );
51408		this.max.add( offset );
51409
51410		return this;
51411
51412	}
51413
51414	equals( box ) {
51415
51416		return box.min.equals( this.min ) && box.max.equals( this.max );
51417
51418	}
51419
51420}
51421
51422const _startP = /*@__PURE__*/ new Vector3();
51423const _startEnd = /*@__PURE__*/ new Vector3();
51424
51425class Line3 {
51426
51427	constructor( start = new Vector3(), end = new Vector3() ) {
51428
51429		this.start = start;
51430		this.end = end;
51431
51432	}
51433
51434	set( start, end ) {
51435
51436		this.start.copy( start );
51437		this.end.copy( end );
51438
51439		return this;
51440
51441	}
51442
51443	copy( line ) {
51444
51445		this.start.copy( line.start );
51446		this.end.copy( line.end );
51447
51448		return this;
51449
51450	}
51451
51452	getCenter( target ) {
51453
51454		return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
51455
51456	}
51457
51458	delta( target ) {
51459
51460		return target.subVectors( this.end, this.start );
51461
51462	}
51463
51464	distanceSq() {
51465
51466		return this.start.distanceToSquared( this.end );
51467
51468	}
51469
51470	distance() {
51471
51472		return this.start.distanceTo( this.end );
51473
51474	}
51475
51476	at( t, target ) {
51477
51478		return this.delta( target ).multiplyScalar( t ).add( this.start );
51479
51480	}
51481
51482	closestPointToPointParameter( point, clampToLine ) {
51483
51484		_startP.subVectors( point, this.start );
51485		_startEnd.subVectors( this.end, this.start );
51486
51487		const startEnd2 = _startEnd.dot( _startEnd );
51488		const startEnd_startP = _startEnd.dot( _startP );
51489
51490		let t = startEnd_startP / startEnd2;
51491
51492		if ( clampToLine ) {
51493
51494			t = clamp( t, 0, 1 );
51495
51496		}
51497
51498		return t;
51499
51500	}
51501
51502	closestPointToPoint( point, clampToLine, target ) {
51503
51504		const t = this.closestPointToPointParameter( point, clampToLine );
51505
51506		return this.delta( target ).multiplyScalar( t ).add( this.start );
51507
51508	}
51509
51510	applyMatrix4( matrix ) {
51511
51512		this.start.applyMatrix4( matrix );
51513		this.end.applyMatrix4( matrix );
51514
51515		return this;
51516
51517	}
51518
51519	equals( line ) {
51520
51521		return line.start.equals( this.start ) && line.end.equals( this.end );
51522
51523	}
51524
51525	clone() {
51526
51527		return new this.constructor().copy( this );
51528
51529	}
51530
51531}
51532
51533const _vector$3 = /*@__PURE__*/ new Vector3();
51534
51535class SpotLightHelper extends Object3D {
51536
51537	constructor( light, color ) {
51538
51539		super();
51540
51541		this.light = light;
51542
51543		this.matrix = light.matrixWorld;
51544		this.matrixAutoUpdate = false;
51545
51546		this.color = color;
51547
51548		this.type = 'SpotLightHelper';
51549
51550		const geometry = new BufferGeometry();
51551
51552		const positions = [
51553			0, 0, 0, 	0, 0, 1,
51554			0, 0, 0, 	1, 0, 1,
51555			0, 0, 0,	- 1, 0, 1,
51556			0, 0, 0, 	0, 1, 1,
51557			0, 0, 0, 	0, - 1, 1
51558		];
51559
51560		for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
51561
51562			const p1 = ( i / l ) * Math.PI * 2;
51563			const p2 = ( j / l ) * Math.PI * 2;
51564
51565			positions.push(
51566				Math.cos( p1 ), Math.sin( p1 ), 1,
51567				Math.cos( p2 ), Math.sin( p2 ), 1
51568			);
51569
51570		}
51571
51572		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
51573
51574		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
51575
51576		this.cone = new LineSegments( geometry, material );
51577		this.add( this.cone );
51578
51579		this.update();
51580
51581	}
51582
51583	dispose() {
51584
51585		this.cone.geometry.dispose();
51586		this.cone.material.dispose();
51587
51588	}
51589
51590	update() {
51591
51592		this.light.updateWorldMatrix( true, false );
51593		this.light.target.updateWorldMatrix( true, false );
51594
51595		const coneLength = this.light.distance ? this.light.distance : 1000;
51596		const coneWidth = coneLength * Math.tan( this.light.angle );
51597
51598		this.cone.scale.set( coneWidth, coneWidth, coneLength );
51599
51600		_vector$3.setFromMatrixPosition( this.light.target.matrixWorld );
51601
51602		this.cone.lookAt( _vector$3 );
51603
51604		if ( this.color !== undefined ) {
51605
51606			this.cone.material.color.set( this.color );
51607
51608		} else {
51609
51610			this.cone.material.color.copy( this.light.color );
51611
51612		}
51613
51614	}
51615
51616}
51617
51618const _vector$2 = /*@__PURE__*/ new Vector3();
51619const _boneMatrix = /*@__PURE__*/ new Matrix4();
51620const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
51621
51622
51623class SkeletonHelper extends LineSegments {
51624
51625	constructor( object ) {
51626
51627		const bones = getBoneList( object );
51628
51629		const geometry = new BufferGeometry();
51630
51631		const vertices = [];
51632		const colors = [];
51633
51634		const color1 = new Color( 0, 0, 1 );
51635		const color2 = new Color( 0, 1, 0 );
51636
51637		for ( let i = 0; i < bones.length; i ++ ) {
51638
51639			const bone = bones[ i ];
51640
51641			if ( bone.parent && bone.parent.isBone ) {
51642
51643				vertices.push( 0, 0, 0 );
51644				vertices.push( 0, 0, 0 );
51645				colors.push( color1.r, color1.g, color1.b );
51646				colors.push( color2.r, color2.g, color2.b );
51647
51648			}
51649
51650		}
51651
51652		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51653		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51654
51655		const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
51656
51657		super( geometry, material );
51658
51659		this.isSkeletonHelper = true;
51660
51661		this.type = 'SkeletonHelper';
51662
51663		this.root = object;
51664		this.bones = bones;
51665
51666		this.matrix = object.matrixWorld;
51667		this.matrixAutoUpdate = false;
51668
51669	}
51670
51671	updateMatrixWorld( force ) {
51672
51673		const bones = this.bones;
51674
51675		const geometry = this.geometry;
51676		const position = geometry.getAttribute( 'position' );
51677
51678		_matrixWorldInv.copy( this.root.matrixWorld ).invert();
51679
51680		for ( let i = 0, j = 0; i < bones.length; i ++ ) {
51681
51682			const bone = bones[ i ];
51683
51684			if ( bone.parent && bone.parent.isBone ) {
51685
51686				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
51687				_vector$2.setFromMatrixPosition( _boneMatrix );
51688				position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );
51689
51690				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
51691				_vector$2.setFromMatrixPosition( _boneMatrix );
51692				position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );
51693
51694				j += 2;
51695
51696			}
51697
51698		}
51699
51700		geometry.getAttribute( 'position' ).needsUpdate = true;
51701
51702		super.updateMatrixWorld( force );
51703
51704	}
51705
51706	dispose() {
51707
51708		this.geometry.dispose();
51709		this.material.dispose();
51710
51711	}
51712
51713}
51714
51715
51716function getBoneList( object ) {
51717
51718	const boneList = [];
51719
51720	if ( object.isBone === true ) {
51721
51722		boneList.push( object );
51723
51724	}
51725
51726	for ( let i = 0; i < object.children.length; i ++ ) {
51727
51728		boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
51729
51730	}
51731
51732	return boneList;
51733
51734}
51735
51736class PointLightHelper extends Mesh {
51737
51738	constructor( light, sphereSize, color ) {
51739
51740		const geometry = new SphereGeometry( sphereSize, 4, 2 );
51741		const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51742
51743		super( geometry, material );
51744
51745		this.light = light;
51746
51747		this.color = color;
51748
51749		this.type = 'PointLightHelper';
51750
51751		this.matrix = this.light.matrixWorld;
51752		this.matrixAutoUpdate = false;
51753
51754		this.update();
51755
51756
51757		/*
51758	// TODO: delete this comment?
51759	const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
51760	const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
51761
51762	this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
51763	this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
51764
51765	const d = light.distance;
51766
51767	if ( d === 0.0 ) {
51768
51769		this.lightDistance.visible = false;
51770
51771	} else {
51772
51773		this.lightDistance.scale.set( d, d, d );
51774
51775	}
51776
51777	this.add( this.lightDistance );
51778	*/
51779
51780	}
51781
51782	dispose() {
51783
51784		this.geometry.dispose();
51785		this.material.dispose();
51786
51787	}
51788
51789	update() {
51790
51791		this.light.updateWorldMatrix( true, false );
51792
51793		if ( this.color !== undefined ) {
51794
51795			this.material.color.set( this.color );
51796
51797		} else {
51798
51799			this.material.color.copy( this.light.color );
51800
51801		}
51802
51803		/*
51804		const d = this.light.distance;
51805
51806		if ( d === 0.0 ) {
51807
51808			this.lightDistance.visible = false;
51809
51810		} else {
51811
51812			this.lightDistance.visible = true;
51813			this.lightDistance.scale.set( d, d, d );
51814
51815		}
51816		*/
51817
51818	}
51819
51820}
51821
51822const _vector$1 = /*@__PURE__*/ new Vector3();
51823const _color1 = /*@__PURE__*/ new Color();
51824const _color2 = /*@__PURE__*/ new Color();
51825
51826class HemisphereLightHelper extends Object3D {
51827
51828	constructor( light, size, color ) {
51829
51830		super();
51831
51832		this.light = light;
51833
51834		this.matrix = light.matrixWorld;
51835		this.matrixAutoUpdate = false;
51836
51837		this.color = color;
51838
51839		this.type = 'HemisphereLightHelper';
51840
51841		const geometry = new OctahedronGeometry( size );
51842		geometry.rotateY( Math.PI * 0.5 );
51843
51844		this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51845		if ( this.color === undefined ) this.material.vertexColors = true;
51846
51847		const position = geometry.getAttribute( 'position' );
51848		const colors = new Float32Array( position.count * 3 );
51849
51850		geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
51851
51852		this.add( new Mesh( geometry, this.material ) );
51853
51854		this.update();
51855
51856	}
51857
51858	dispose() {
51859
51860		this.children[ 0 ].geometry.dispose();
51861		this.children[ 0 ].material.dispose();
51862
51863	}
51864
51865	update() {
51866
51867		const mesh = this.children[ 0 ];
51868
51869		if ( this.color !== undefined ) {
51870
51871			this.material.color.set( this.color );
51872
51873		} else {
51874
51875			const colors = mesh.geometry.getAttribute( 'color' );
51876
51877			_color1.copy( this.light.color );
51878			_color2.copy( this.light.groundColor );
51879
51880			for ( let i = 0, l = colors.count; i < l; i ++ ) {
51881
51882				const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
51883
51884				colors.setXYZ( i, color.r, color.g, color.b );
51885
51886			}
51887
51888			colors.needsUpdate = true;
51889
51890		}
51891
51892		this.light.updateWorldMatrix( true, false );
51893
51894		mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() );
51895
51896	}
51897
51898}
51899
51900class GridHelper extends LineSegments {
51901
51902	constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
51903
51904		color1 = new Color( color1 );
51905		color2 = new Color( color2 );
51906
51907		const center = divisions / 2;
51908		const step = size / divisions;
51909		const halfSize = size / 2;
51910
51911		const vertices = [], colors = [];
51912
51913		for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
51914
51915			vertices.push( - halfSize, 0, k, halfSize, 0, k );
51916			vertices.push( k, 0, - halfSize, k, 0, halfSize );
51917
51918			const color = i === center ? color1 : color2;
51919
51920			color.toArray( colors, j ); j += 3;
51921			color.toArray( colors, j ); j += 3;
51922			color.toArray( colors, j ); j += 3;
51923			color.toArray( colors, j ); j += 3;
51924
51925		}
51926
51927		const geometry = new BufferGeometry();
51928		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51929		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51930
51931		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
51932
51933		super( geometry, material );
51934
51935		this.type = 'GridHelper';
51936
51937	}
51938
51939	dispose() {
51940
51941		this.geometry.dispose();
51942		this.material.dispose();
51943
51944	}
51945
51946}
51947
51948class PolarGridHelper extends LineSegments {
51949
51950	constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
51951
51952		color1 = new Color( color1 );
51953		color2 = new Color( color2 );
51954
51955		const vertices = [];
51956		const colors = [];
51957
51958		// create the sectors
51959
51960		if ( sectors > 1 ) {
51961
51962			for ( let i = 0; i < sectors; i ++ ) {
51963
51964				const v = ( i / sectors ) * ( Math.PI * 2 );
51965
51966				const x = Math.sin( v ) * radius;
51967				const z = Math.cos( v ) * radius;
51968
51969				vertices.push( 0, 0, 0 );
51970				vertices.push( x, 0, z );
51971
51972				const color = ( i & 1 ) ? color1 : color2;
51973
51974				colors.push( color.r, color.g, color.b );
51975				colors.push( color.r, color.g, color.b );
51976
51977			}
51978
51979		}
51980
51981		// create the rings
51982
51983		for ( let i = 0; i < rings; i ++ ) {
51984
51985			const color = ( i & 1 ) ? color1 : color2;
51986
51987			const r = radius - ( radius / rings * i );
51988
51989			for ( let j = 0; j < divisions; j ++ ) {
51990
51991				// first vertex
51992
51993				let v = ( j / divisions ) * ( Math.PI * 2 );
51994
51995				let x = Math.sin( v ) * r;
51996				let z = Math.cos( v ) * r;
51997
51998				vertices.push( x, 0, z );
51999				colors.push( color.r, color.g, color.b );
52000
52001				// second vertex
52002
52003				v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
52004
52005				x = Math.sin( v ) * r;
52006				z = Math.cos( v ) * r;
52007
52008				vertices.push( x, 0, z );
52009				colors.push( color.r, color.g, color.b );
52010
52011			}
52012
52013		}
52014
52015		const geometry = new BufferGeometry();
52016		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52017		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52018
52019		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52020
52021		super( geometry, material );
52022
52023		this.type = 'PolarGridHelper';
52024
52025	}
52026
52027	dispose() {
52028
52029		this.geometry.dispose();
52030		this.material.dispose();
52031
52032	}
52033
52034}
52035
52036const _v1 = /*@__PURE__*/ new Vector3();
52037const _v2 = /*@__PURE__*/ new Vector3();
52038const _v3 = /*@__PURE__*/ new Vector3();
52039
52040class DirectionalLightHelper extends Object3D {
52041
52042	constructor( light, size, color ) {
52043
52044		super();
52045
52046		this.light = light;
52047
52048		this.matrix = light.matrixWorld;
52049		this.matrixAutoUpdate = false;
52050
52051		this.color = color;
52052
52053		this.type = 'DirectionalLightHelper';
52054
52055		if ( size === undefined ) size = 1;
52056
52057		let geometry = new BufferGeometry();
52058		geometry.setAttribute( 'position', new Float32BufferAttribute( [
52059			- size, size, 0,
52060			size, size, 0,
52061			size, - size, 0,
52062			- size, - size, 0,
52063			- size, size, 0
52064		], 3 ) );
52065
52066		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
52067
52068		this.lightPlane = new Line( geometry, material );
52069		this.add( this.lightPlane );
52070
52071		geometry = new BufferGeometry();
52072		geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
52073
52074		this.targetLine = new Line( geometry, material );
52075		this.add( this.targetLine );
52076
52077		this.update();
52078
52079	}
52080
52081	dispose() {
52082
52083		this.lightPlane.geometry.dispose();
52084		this.lightPlane.material.dispose();
52085		this.targetLine.geometry.dispose();
52086		this.targetLine.material.dispose();
52087
52088	}
52089
52090	update() {
52091
52092		this.light.updateWorldMatrix( true, false );
52093		this.light.target.updateWorldMatrix( true, false );
52094
52095		_v1.setFromMatrixPosition( this.light.matrixWorld );
52096		_v2.setFromMatrixPosition( this.light.target.matrixWorld );
52097		_v3.subVectors( _v2, _v1 );
52098
52099		this.lightPlane.lookAt( _v2 );
52100
52101		if ( this.color !== undefined ) {
52102
52103			this.lightPlane.material.color.set( this.color );
52104			this.targetLine.material.color.set( this.color );
52105
52106		} else {
52107
52108			this.lightPlane.material.color.copy( this.light.color );
52109			this.targetLine.material.color.copy( this.light.color );
52110
52111		}
52112
52113		this.targetLine.lookAt( _v2 );
52114		this.targetLine.scale.z = _v3.length();
52115
52116	}
52117
52118}
52119
52120const _vector = /*@__PURE__*/ new Vector3();
52121const _camera = /*@__PURE__*/ new Camera();
52122
52123/**
52124 *	- shows frustum, line of sight and up of the camera
52125 *	- suitable for fast updates
52126 * 	- based on frustum visualization in lightgl.js shadowmap example
52127 *		https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html
52128 */
52129
52130class CameraHelper extends LineSegments {
52131
52132	constructor( camera ) {
52133
52134		const geometry = new BufferGeometry();
52135		const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
52136
52137		const vertices = [];
52138		const colors = [];
52139
52140		const pointMap = {};
52141
52142		// near
52143
52144		addLine( 'n1', 'n2' );
52145		addLine( 'n2', 'n4' );
52146		addLine( 'n4', 'n3' );
52147		addLine( 'n3', 'n1' );
52148
52149		// far
52150
52151		addLine( 'f1', 'f2' );
52152		addLine( 'f2', 'f4' );
52153		addLine( 'f4', 'f3' );
52154		addLine( 'f3', 'f1' );
52155
52156		// sides
52157
52158		addLine( 'n1', 'f1' );
52159		addLine( 'n2', 'f2' );
52160		addLine( 'n3', 'f3' );
52161		addLine( 'n4', 'f4' );
52162
52163		// cone
52164
52165		addLine( 'p', 'n1' );
52166		addLine( 'p', 'n2' );
52167		addLine( 'p', 'n3' );
52168		addLine( 'p', 'n4' );
52169
52170		// up
52171
52172		addLine( 'u1', 'u2' );
52173		addLine( 'u2', 'u3' );
52174		addLine( 'u3', 'u1' );
52175
52176		// target
52177
52178		addLine( 'c', 't' );
52179		addLine( 'p', 'c' );
52180
52181		// cross
52182
52183		addLine( 'cn1', 'cn2' );
52184		addLine( 'cn3', 'cn4' );
52185
52186		addLine( 'cf1', 'cf2' );
52187		addLine( 'cf3', 'cf4' );
52188
52189		function addLine( a, b ) {
52190
52191			addPoint( a );
52192			addPoint( b );
52193
52194		}
52195
52196		function addPoint( id ) {
52197
52198			vertices.push( 0, 0, 0 );
52199			colors.push( 0, 0, 0 );
52200
52201			if ( pointMap[ id ] === undefined ) {
52202
52203				pointMap[ id ] = [];
52204
52205			}
52206
52207			pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
52208
52209		}
52210
52211		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52212		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52213
52214		super( geometry, material );
52215
52216		this.type = 'CameraHelper';
52217
52218		this.camera = camera;
52219		if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
52220
52221		this.matrix = camera.matrixWorld;
52222		this.matrixAutoUpdate = false;
52223
52224		this.pointMap = pointMap;
52225
52226		this.update();
52227
52228		// colors
52229
52230		const colorFrustum = new Color( 0xffaa00 );
52231		const colorCone = new Color( 0xff0000 );
52232		const colorUp = new Color( 0x00aaff );
52233		const colorTarget = new Color( 0xffffff );
52234		const colorCross = new Color( 0x333333 );
52235
52236		this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross );
52237
52238	}
52239
52240	setColors( frustum, cone, up, target, cross ) {
52241
52242		const geometry = this.geometry;
52243
52244		const colorAttribute = geometry.getAttribute( 'color' );
52245
52246		// near
52247
52248		colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2
52249		colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4
52250		colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3
52251		colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1
52252
52253		// far
52254
52255		colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2
52256		colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4
52257		colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3
52258		colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1
52259
52260		// sides
52261
52262		colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1
52263		colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2
52264		colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3
52265		colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4
52266
52267		// cone
52268
52269		colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1
52270		colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2
52271		colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3
52272		colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4
52273
52274		// up
52275
52276		colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2
52277		colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3
52278		colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1
52279
52280		// target
52281
52282		colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t
52283		colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c
52284
52285		// cross
52286
52287		colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2
52288		colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4
52289
52290		colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2
52291		colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4
52292
52293		colorAttribute.needsUpdate = true;
52294
52295	}
52296
vendor: 20,967 bytes, lines 52297-53057
52297	update() {
52298
52299		const geometry = this.geometry;
52300		const pointMap = this.pointMap;
52301
52302		const w = 1, h = 1;
52303
52304		// we need just camera projection matrix inverse
52305		// world matrix must be identity
52306
52307		_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
52308
52309		// center / target
52310
52311		setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
52312		setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
52313
52314		// near
52315
52316		setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
52317		setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
52318		setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
52319		setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
52320
52321		// far
52322
52323		setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
52324		setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
52325		setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
52326		setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
52327
52328		// up
52329
52330		setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
52331		setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
52332		setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
52333
52334		// cross
52335
52336		setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
52337		setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
52338		setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
52339		setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
52340
52341		setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
52342		setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
52343		setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
52344		setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
52345
52346		geometry.getAttribute( 'position' ).needsUpdate = true;
52347
52348	}
52349
52350	dispose() {
52351
52352		this.geometry.dispose();
52353		this.material.dispose();
52354
52355	}
52356
52357}
52358
52359
52360function setPoint( point, pointMap, geometry, camera, x, y, z ) {
52361
52362	_vector.set( x, y, z ).unproject( camera );
52363
52364	const points = pointMap[ point ];
52365
52366	if ( points !== undefined ) {
52367
52368		const position = geometry.getAttribute( 'position' );
52369
52370		for ( let i = 0, l = points.length; i < l; i ++ ) {
52371
52372			position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z );
52373
52374		}
52375
52376	}
52377
52378}
52379
52380const _box = /*@__PURE__*/ new Box3();
52381
52382class BoxHelper extends LineSegments {
52383
52384	constructor( object, color = 0xffff00 ) {
52385
52386		const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
52387		const positions = new Float32Array( 8 * 3 );
52388
52389		const geometry = new BufferGeometry();
52390		geometry.setIndex( new BufferAttribute( indices, 1 ) );
52391		geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
52392
52393		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52394
52395		this.object = object;
52396		this.type = 'BoxHelper';
52397
52398		this.matrixAutoUpdate = false;
52399
52400		this.update();
52401
52402	}
52403
52404	update( object ) {
52405
52406		if ( object !== undefined ) {
52407
52408			console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
52409
52410		}
52411
52412		if ( this.object !== undefined ) {
52413
52414			_box.setFromObject( this.object );
52415
52416		}
52417
52418		if ( _box.isEmpty() ) return;
52419
52420		const min = _box.min;
52421		const max = _box.max;
52422
52423		/*
52424			5____4
52425		1/___0/|
52426		| 6__|_7
52427		2/___3/
52428
52429		0: max.x, max.y, max.z
52430		1: min.x, max.y, max.z
52431		2: min.x, min.y, max.z
52432		3: max.x, min.y, max.z
52433		4: max.x, max.y, min.z
52434		5: min.x, max.y, min.z
52435		6: min.x, min.y, min.z
52436		7: max.x, min.y, min.z
52437		*/
52438
52439		const position = this.geometry.attributes.position;
52440		const array = position.array;
52441
52442		array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
52443		array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
52444		array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
52445		array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
52446		array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
52447		array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
52448		array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
52449		array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
52450
52451		position.needsUpdate = true;
52452
52453		this.geometry.computeBoundingSphere();
52454
52455	}
52456
52457	setFromObject( object ) {
52458
52459		this.object = object;
52460		this.update();
52461
52462		return this;
52463
52464	}
52465
52466	copy( source, recursive ) {
52467
52468		super.copy( source, recursive );
52469
52470		this.object = source.object;
52471
52472		return this;
52473
52474	}
52475
52476	dispose() {
52477
52478		this.geometry.dispose();
52479		this.material.dispose();
52480
52481	}
52482
52483}
52484
52485class Box3Helper extends LineSegments {
52486
52487	constructor( box, color = 0xffff00 ) {
52488
52489		const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
52490
52491		const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
52492
52493		const geometry = new BufferGeometry();
52494
52495		geometry.setIndex( new BufferAttribute( indices, 1 ) );
52496
52497		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52498
52499		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52500
52501		this.box = box;
52502
52503		this.type = 'Box3Helper';
52504
52505		this.geometry.computeBoundingSphere();
52506
52507	}
52508
52509	updateMatrixWorld( force ) {
52510
52511		const box = this.box;
52512
52513		if ( box.isEmpty() ) return;
52514
52515		box.getCenter( this.position );
52516
52517		box.getSize( this.scale );
52518
52519		this.scale.multiplyScalar( 0.5 );
52520
52521		super.updateMatrixWorld( force );
52522
52523	}
52524
52525	dispose() {
52526
52527		this.geometry.dispose();
52528		this.material.dispose();
52529
52530	}
52531
52532}
52533
52534class PlaneHelper extends Line {
52535
52536	constructor( plane, size = 1, hex = 0xffff00 ) {
52537
52538		const color = hex;
52539
52540		const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ];
52541
52542		const geometry = new BufferGeometry();
52543		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52544		geometry.computeBoundingSphere();
52545
52546		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52547
52548		this.type = 'PlaneHelper';
52549
52550		this.plane = plane;
52551
52552		this.size = size;
52553
52554		const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];
52555
52556		const geometry2 = new BufferGeometry();
52557		geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
52558		geometry2.computeBoundingSphere();
52559
52560		this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
52561
52562	}
52563
52564	updateMatrixWorld( force ) {
52565
52566		this.position.set( 0, 0, 0 );
52567
52568		this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 );
52569
52570		this.lookAt( this.plane.normal );
52571
52572		this.translateZ( - this.plane.constant );
52573
52574		super.updateMatrixWorld( force );
52575
52576	}
52577
52578	dispose() {
52579
52580		this.geometry.dispose();
52581		this.material.dispose();
52582		this.children[ 0 ].geometry.dispose();
52583		this.children[ 0 ].material.dispose();
52584
52585	}
52586
52587}
52588
52589const _axis = /*@__PURE__*/ new Vector3();
52590let _lineGeometry, _coneGeometry;
52591
52592class ArrowHelper extends Object3D {
52593
52594	// dir is assumed to be normalized
52595
52596	constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) {
52597
52598		super();
52599
52600		this.type = 'ArrowHelper';
52601
52602		if ( _lineGeometry === undefined ) {
52603
52604			_lineGeometry = new BufferGeometry();
52605			_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
52606
52607			_coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );
52608			_coneGeometry.translate( 0, - 0.5, 0 );
52609
52610		}
52611
52612		this.position.copy( origin );
52613
52614		this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52615		this.line.matrixAutoUpdate = false;
52616		this.add( this.line );
52617
52618		this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
52619		this.cone.matrixAutoUpdate = false;
52620		this.add( this.cone );
52621
52622		this.setDirection( dir );
52623		this.setLength( length, headLength, headWidth );
52624
52625	}
52626
52627	setDirection( dir ) {
52628
52629		// dir is assumed to be normalized
52630
52631		if ( dir.y > 0.99999 ) {
52632
52633			this.quaternion.set( 0, 0, 0, 1 );
52634
52635		} else if ( dir.y < - 0.99999 ) {
52636
52637			this.quaternion.set( 1, 0, 0, 0 );
52638
52639		} else {
52640
52641			_axis.set( dir.z, 0, - dir.x ).normalize();
52642
52643			const radians = Math.acos( dir.y );
52644
52645			this.quaternion.setFromAxisAngle( _axis, radians );
52646
52647		}
52648
52649	}
52650
52651	setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) {
52652
52653		this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
52654		this.line.updateMatrix();
52655
52656		this.cone.scale.set( headWidth, headLength, headWidth );
52657		this.cone.position.y = length;
52658		this.cone.updateMatrix();
52659
52660	}
52661
52662	setColor( color ) {
52663
52664		this.line.material.color.set( color );
52665		this.cone.material.color.set( color );
52666
52667	}
52668
52669	copy( source ) {
52670
52671		super.copy( source, false );
52672
52673		this.line.copy( source.line );
52674		this.cone.copy( source.cone );
52675
52676		return this;
52677
52678	}
52679
52680	dispose() {
52681
52682		this.line.geometry.dispose();
52683		this.line.material.dispose();
52684		this.cone.geometry.dispose();
52685		this.cone.material.dispose();
52686
52687	}
52688
52689}
52690
52691class AxesHelper extends LineSegments {
52692
52693	constructor( size = 1 ) {
52694
52695		const vertices = [
52696			0, 0, 0,	size, 0, 0,
52697			0, 0, 0,	0, size, 0,
52698			0, 0, 0,	0, 0, size
52699		];
52700
52701		const colors = [
52702			1, 0, 0,	1, 0.6, 0,
52703			0, 1, 0,	0.6, 1, 0,
52704			0, 0, 1,	0, 0.6, 1
52705		];
52706
52707		const geometry = new BufferGeometry();
52708		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52709		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52710
52711		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52712
52713		super( geometry, material );
52714
52715		this.type = 'AxesHelper';
52716
52717	}
52718
52719	setColors( xAxisColor, yAxisColor, zAxisColor ) {
52720
52721		const color = new Color();
52722		const array = this.geometry.attributes.color.array;
52723
52724		color.set( xAxisColor );
52725		color.toArray( array, 0 );
52726		color.toArray( array, 3 );
52727
52728		color.set( yAxisColor );
52729		color.toArray( array, 6 );
52730		color.toArray( array, 9 );
52731
52732		color.set( zAxisColor );
52733		color.toArray( array, 12 );
52734		color.toArray( array, 15 );
52735
52736		this.geometry.attributes.color.needsUpdate = true;
52737
52738		return this;
52739
52740	}
52741
52742	dispose() {
52743
52744		this.geometry.dispose();
52745		this.material.dispose();
52746
52747	}
52748
52749}
52750
52751class ShapePath {
52752
52753	constructor() {
52754
52755		this.type = 'ShapePath';
52756
52757		this.color = new Color();
52758
52759		this.subPaths = [];
52760		this.currentPath = null;
52761
52762	}
52763
52764	moveTo( x, y ) {
52765
52766		this.currentPath = new Path();
52767		this.subPaths.push( this.currentPath );
52768		this.currentPath.moveTo( x, y );
52769
52770		return this;
52771
52772	}
52773
52774	lineTo( x, y ) {
52775
52776		this.currentPath.lineTo( x, y );
52777
52778		return this;
52779
52780	}
52781
52782	quadraticCurveTo( aCPx, aCPy, aX, aY ) {
52783
52784		this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
52785
52786		return this;
52787
52788	}
52789
52790	bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
52791
52792		this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
52793
52794		return this;
52795
52796	}
52797
52798	splineThru( pts ) {
52799
52800		this.currentPath.splineThru( pts );
52801
52802		return this;
52803
52804	}
52805
52806	toShapes( isCCW ) {
52807
52808		function toShapesNoHoles( inSubpaths ) {
52809
52810			const shapes = [];
52811
52812			for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
52813
52814				const tmpPath = inSubpaths[ i ];
52815
52816				const tmpShape = new Shape();
52817				tmpShape.curves = tmpPath.curves;
52818
52819				shapes.push( tmpShape );
52820
52821			}
52822
52823			return shapes;
52824
52825		}
52826
52827		function isPointInsidePolygon( inPt, inPolygon ) {
52828
52829			const polyLen = inPolygon.length;
52830
52831			// inPt on polygon contour => immediate success    or
52832			// toggling of inside/outside at every single! intersection point of an edge
52833			//  with the horizontal line through inPt, left of inPt
52834			//  not counting lowerY endpoints of edges and whole edges on that line
52835			let inside = false;
52836			for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
52837
52838				let edgeLowPt = inPolygon[ p ];
52839				let edgeHighPt = inPolygon[ q ];
52840
52841				let edgeDx = edgeHighPt.x - edgeLowPt.x;
52842				let edgeDy = edgeHighPt.y - edgeLowPt.y;
52843
52844				if ( Math.abs( edgeDy ) > Number.EPSILON ) {
52845
52846					// not parallel
52847					if ( edgeDy < 0 ) {
52848
52849						edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
52850						edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
52851
52852					}
52853
52854					if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;
52855
52856					if ( inPt.y === edgeLowPt.y ) {
52857
52858						if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
52859						// continue;				// no intersection or edgeLowPt => doesn't count !!!
52860
52861					} else {
52862
52863						const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
52864						if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
52865						if ( perpEdge < 0 ) 				continue;
52866						inside = ! inside;		// true intersection left of inPt
52867
52868					}
52869
52870				} else {
52871
52872					// parallel or collinear
52873					if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
52874					// edge lies on the same horizontal line as inPt
52875					if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
52876						 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
52877					// continue;
52878
52879				}
52880
52881			}
52882
52883			return	inside;
52884
52885		}
52886
52887		const isClockWise = ShapeUtils.isClockWise;
52888
52889		const subPaths = this.subPaths;
52890		if ( subPaths.length === 0 ) return [];
52891
52892		let solid, tmpPath, tmpShape;
52893		const shapes = [];
52894
52895		if ( subPaths.length === 1 ) {
52896
52897			tmpPath = subPaths[ 0 ];
52898			tmpShape = new Shape();
52899			tmpShape.curves = tmpPath.curves;
52900			shapes.push( tmpShape );
52901			return shapes;
52902
52903		}
52904
52905		let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
52906		holesFirst = isCCW ? ! holesFirst : holesFirst;
52907
52908		// console.log("Holes first", holesFirst);
52909
52910		const betterShapeHoles = [];
52911		const newShapes = [];
52912		let newShapeHoles = [];
52913		let mainIdx = 0;
52914		let tmpPoints;
52915
52916		newShapes[ mainIdx ] = undefined;
52917		newShapeHoles[ mainIdx ] = [];
52918
52919		for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
52920
52921			tmpPath = subPaths[ i ];
52922			tmpPoints = tmpPath.getPoints();
52923			solid = isClockWise( tmpPoints );
52924			solid = isCCW ? ! solid : solid;
52925
52926			if ( solid ) {
52927
52928				if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )	mainIdx ++;
52929
52930				newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
52931				newShapes[ mainIdx ].s.curves = tmpPath.curves;
52932
52933				if ( holesFirst )	mainIdx ++;
52934				newShapeHoles[ mainIdx ] = [];
52935
52936				//console.log('cw', i);
52937
52938			} else {
52939
52940				newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
52941
52942				//console.log('ccw', i);
52943
52944			}
52945
52946		}
52947
52948		// only Holes? -> probably all Shapes with wrong orientation
52949		if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
52950
52951
52952		if ( newShapes.length > 1 ) {
52953
52954			let ambiguous = false;
52955			let toChange = 0;
52956
52957			for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52958
52959				betterShapeHoles[ sIdx ] = [];
52960
52961			}
52962
52963			for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52964
52965				const sho = newShapeHoles[ sIdx ];
52966
52967				for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
52968
52969					const ho = sho[ hIdx ];
52970					let hole_unassigned = true;
52971
52972					for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
52973
52974						if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
52975
52976							if ( sIdx !== s2Idx )	toChange ++;
52977
52978							if ( hole_unassigned ) {
52979
52980								hole_unassigned = false;
52981								betterShapeHoles[ s2Idx ].push( ho );
52982
52983							} else {
52984
52985								ambiguous = true;
52986
52987							}
52988
52989						}
52990
52991					}
52992
52993					if ( hole_unassigned ) {
52994
52995						betterShapeHoles[ sIdx ].push( ho );
52996
52997					}
52998
52999				}
53000
53001			}
53002
53003			if ( toChange > 0 && ambiguous === false ) {
53004
53005				newShapeHoles = betterShapeHoles;
53006
53007			}
53008
53009		}
53010
53011		let tmpHoles;
53012
53013		for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
53014
53015			tmpShape = newShapes[ i ].s;
53016			shapes.push( tmpShape );
53017			tmpHoles = newShapeHoles[ i ];
53018
53019			for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
53020
53021				tmpShape.holes.push( tmpHoles[ j ].h );
53022
53023			}
53024
53025		}
53026
53027		//console.log("shape", shapes);
53028
53029		return shapes;
53030
53031	}
53032
53033}
53034
53035if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
53036
53037	__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
53038		revision: REVISION,
53039	} } ) );
53040
53041}
53042
53043if ( typeof window !== 'undefined' ) {
53044
53045	if ( window.__THREE__ ) {
53046
53047		console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
53048
53049	} else {
53050
53051		window.__THREE__ = REVISION;
53052
53053	}
53054
53055}
53056
53057export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Float64BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearEncoding, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, Orthogra
53057phicCamera, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, 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, Ray, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderChunk, ShaderLib, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, TwoPassDoubleSide, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoTexture, WebGL1Renderer, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, _SRGBAFormat, createCanvasElement, sRGBEncoding };

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.