PageSourceSearch

https://www.stillmakingstuff.com/js/lib/three.module.js

js stillmakingstuff.com collected 2026-10-06 13:37:49 UTC 1,272,972 bytes, 53,044 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;
vendor: 8,389 bytes, lines 140-434
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 names 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: 7,916 bytes, lines 435-1010
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
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, - 
vendor: 7,768 bytes, lines 1010-1522
10101, 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 ],
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
vendor: 8,505 bytes, lines 1523-1953
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
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: 6,087 bytes, lines 1954-2258
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;
vendor: 10,756 bytes, lines 2258-2935
2258
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
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		
2935if ( 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
vendor: 24,564 bytes, lines 3040-4475
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: 1,851 bytes, lines 4476-4598
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
vendor: 11,889 bytes, lines 4598-5154
4598;
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
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 = -
vendor: 3,824 bytes, lines 5154-5400
5154 1 ) {
5155
5156		this.isSphere = true;
5157
5158		this.center = center;
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, - 
vendor: 8,510 bytes, lines 5400-5806
54001 ) ) {
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
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 = -
5806 
vendor: 16,979 bytes, lines 5806-6624
58061;
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.
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;
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		const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
6430		const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
6431		const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
6432
6433		return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
6434
6435	}
6436
6437	makeTranslation( x, y, z ) {
6438
6439		if ( x.isVector3 ) {
6440
6441			this.set(
6442
6443				1, 0, 0, x.x,
6444				0, 1, 0, x.y,
6445				0, 0, 1, x.z,
6446				0, 0, 0, 1
6447
6448			);
6449
6450		} else {
6451
6452			this.set(
6453
6454				1, 0, 0, x,
6455				0, 1, 0, y,
6456				0, 0, 1, z,
6457				0, 0, 0, 1
6458
6459			);
6460
6461		}
6462
6463		return this;
6464
6465	}
6466
6467	makeRotationX( theta ) {
6468
6469		const c = Math.cos( theta ), s = Math.sin( theta );
6470
6471		this.set(
6472
6473			1, 0, 0, 0,
6474			0, c, - s, 0,
6475			0, s, c, 0,
6476			0, 0, 0, 1
6477
6478		);
6479
6480		return this;
6481
6482	}
6483
6484	makeRotationY( theta ) {
6485
6486		const c = Math.cos( theta ), s = Math.sin( theta );
6487
6488		this.set(
6489
6490			 c, 0, s, 0,
6491			 0, 1, 0, 0,
6492			- s, 0, c, 0,
6493			 0, 0, 0, 1
6494
6495		);
6496
6497		return this;
6498
6499	}
6500
6501	makeRotationZ( theta ) {
6502
6503		const c = Math.cos( theta ), s = Math.sin( theta );
6504
6505		this.set(
6506
6507			c, - s, 0, 0,
6508			s, c, 0, 0,
6509			0, 0, 1, 0,
6510			0, 0, 0, 1
6511
6512		);
6513
6514		return this;
6515
6516	}
6517
6518	makeRotationAxis( axis, angle ) {
6519
6520		// Based on http://www.gamedev.net/reference/articles/article1199.asp
6521
6522		const c = Math.cos( angle );
6523		const s = Math.sin( angle );
6524		const t = 1 - c;
6525		const x = axis.x, y = axis.y, z = axis.z;
6526		const tx = t * x, ty = t * y;
6527
6528		this.set(
6529
6530			tx * x + c, tx * y - s * z, tx * z + s * y, 0,
6531			tx * y + s * z, ty * y + c, ty * z - s * x, 0,
6532			tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
6533			0, 0, 0, 1
6534
6535		);
6536
6537		return this;
6538
6539	}
6540
6541	makeScale( x, y, z ) {
6542
6543		this.set(
6544
6545			x, 0, 0, 0,
6546			0, y, 0, 0,
6547			0, 0, z, 0,
6548			0, 0, 0, 1
6549
6550		);
6551
6552		return this;
6553
6554	}
6555
6556	makeShear( xy, xz, yx, yz, zx, zy ) {
6557
6558		this.set(
6559
6560			1, yx, zx, 0,
6561			xy, 1, zy, 0,
6562			xz, yz, 1, 0,
6563			0, 0, 0, 1
6564
6565		);
6566
6567		return this;
6568
6569	}
6570
6571	compose( position, quaternion, scale ) {
6572
6573		const te = this.elements;
6574
6575		const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
6576		const x2 = x + x,	y2 = y + y, z2 = z + z;
6577		const xx = x * x2, xy = x * y2, xz = x * z2;
6578		const yy = y * y2, yz = y * z2, zz = z * z2;
6579		const wx = w * x2, wy = w * y2, wz = w * z2;
6580
6581		const sx = scale.x, sy = scale.y, sz = scale.z;
6582
6583		te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
6584		te[ 1 ] = ( xy + wz ) * sx;
6585		te[ 2 ] = ( xz - wy ) * sx;
6586		te[ 3 ] = 0;
6587
6588		te[ 4 ] = ( xy - wz ) * sy;
6589		te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
6590		te[ 6 ] = ( yz + wx ) * sy;
6591		te[ 7 ] = 0;
6592
6593		te[ 8 ] = ( xz + wy ) * sz;
6594		te[ 9 ] = ( yz - wx ) * sz;
6595		te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
6596		te[ 11 ] = 0;
6597
6598		te[ 12 ] = position.x;
6599		te[ 13 ] = position.y;
6600		te[ 14 ] = position.z;
6601		te[ 15 ] = 1;
6602
6603		return this;
6604
6605	}
6606
6607	decompose( position, quaternion, scale ) {
6608
6609		const te = this.elements;
6610
6611		let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
6612		const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
6613		const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
6614
6615		// if determine is negative, we need to invert one scale
6616		const det = this.determinant();
6617		if ( det < 0 ) sx = - sx;
6618
6619		position.x = te[ 12 ];
6620		position.y = te[ 13 ];
6621		position.z = te[ 14 ];
6622
6623		// scale the rotation part
6624		_m1$
vendor: 16,143 bytes, lines 6624-7569
66242.copy( this );
6625
6626		const invSX = 1 / sx;
6627		const invSY = 1 / sy;
6628		const invSZ = 1 / sz;
6629
6630		_m1$2.elements[ 0 ] *= invSX;
6631		_m1$2.elements[ 1 ] *= invSX;
6632		_m1$2.elements[ 2 ] *= invSX;
6633
6634		_m1$2.elements[ 4 ] *= invSY;
6635		_m1$2.elements[ 5 ] *= invSY;
6636		_m1$2.elements[ 6 ] *= invSY;
6637
6638		_m1$2.elements[ 8 ] *= invSZ;
6639		_m1$2.elements[ 9 ] *= invSZ;
6640		_m1$2.elements[ 10 ] *= invSZ;
6641
6642		quaternion.setFromRotationMatrix( _m1$2 );
6643
6644		scale.x = sx;
6645		scale.y = sy;
6646		scale.z = sz;
6647
6648		return this;
6649
6650	}
6651
6652	makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
6653
6654		const te = this.elements;
6655		const x = 2 * near / ( right - left );
6656		const y = 2 * near / ( top - bottom );
6657
6658		const a = ( right + left ) / ( right - left );
6659		const b = ( top + bottom ) / ( top - bottom );
6660
6661		let c, d;
6662
6663		if ( coordinateSystem === WebGLCoordinateSystem ) {
6664
6665			c = - ( far + near ) / ( far - near );
6666			d = ( - 2 * far * near ) / ( far - near );
6667
6668		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6669
6670			c = - far / ( far - near );
6671			d = ( - far * near ) / ( far - near );
6672
6673		} else {
6674
6675			throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );
6676
6677		}
6678
6679		te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a; 	te[ 12 ] = 0;
6680		te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b; 	te[ 13 ] = 0;
6681		te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c; 	te[ 14 ] = d;
6682		te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = - 1;	te[ 15 ] = 0;
6683
6684		return this;
6685
6686	}
6687
6688	makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
6689
6690		const te = this.elements;
6691		const w = 1.0 / ( right - left );
6692		const h = 1.0 / ( top - bottom );
6693		const p = 1.0 / ( far - near );
6694
6695		const x = ( right + left ) * w;
6696		const y = ( top + bottom ) * h;
6697
6698		let z, zInv;
6699
6700		if ( coordinateSystem === WebGLCoordinateSystem ) {
6701
6702			z = ( far + near ) * p;
6703			zInv = - 2 * p;
6704
6705		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6706
6707			z = near * p;
6708			zInv = - 1 * p;
6709
6710		} else {
6711
6712			throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );
6713
6714		}
6715
6716		te[ 0 ] = 2 * w;	te[ 4 ] = 0;		te[ 8 ] = 0; 		te[ 12 ] = - x;
6717		te[ 1 ] = 0; 		te[ 5 ] = 2 * h;	te[ 9 ] = 0; 		te[ 13 ] = - y;
6718		te[ 2 ] = 0; 		te[ 6 ] = 0;		te[ 10 ] = zInv;	te[ 14 ] = - z;
6719		te[ 3 ] = 0; 		te[ 7 ] = 0;		te[ 11 ] = 0;		te[ 15 ] = 1;
6720
6721		return this;
6722
6723	}
6724
6725	equals( matrix ) {
6726
6727		const te = this.elements;
6728		const me = matrix.elements;
6729
6730		for ( let i = 0; i < 16; i ++ ) {
6731
6732			if ( te[ i ] !== me[ i ] ) return false;
6733
6734		}
6735
6736		return true;
6737
6738	}
6739
6740	fromArray( array, offset = 0 ) {
6741
6742		for ( let i = 0; i < 16; i ++ ) {
6743
6744			this.elements[ i ] = array[ i + offset ];
6745
6746		}
6747
6748		return this;
6749
6750	}
6751
6752	toArray( array = [], offset = 0 ) {
6753
6754		const te = this.elements;
6755
6756		array[ offset ] = te[ 0 ];
6757		array[ offset + 1 ] = te[ 1 ];
6758		array[ offset + 2 ] = te[ 2 ];
6759		array[ offset + 3 ] = te[ 3 ];
6760
6761		array[ offset + 4 ] = te[ 4 ];
6762		array[ offset + 5 ] = te[ 5 ];
6763		array[ offset + 6 ] = te[ 6 ];
6764		array[ offset + 7 ] = te[ 7 ];
6765
6766		array[ offset + 8 ] = te[ 8 ];
6767		array[ offset + 9 ] = te[ 9 ];
6768		array[ offset + 10 ] = te[ 10 ];
6769		array[ offset + 11 ] = te[ 11 ];
6770
6771		array[ offset + 12 ] = te[ 12 ];
6772		array[ offset + 13 ] = te[ 13 ];
6773		array[ offset + 14 ] = te[ 14 ];
6774		array[ offset + 15 ] = te[ 15 ];
6775
6776		return array;
6777
6778	}
6779
6780}
6781
6782const _v1$5 = /*@__PURE__*/ new Vector3();
6783const _m1$2 = /*@__PURE__*/ new Matrix4();
6784const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
6785const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
6786const _x = /*@__PURE__*/ new Vector3();
6787const _y = /*@__PURE__*/ new Vector3();
6788const _z = /*@__PURE__*/ new Vector3();
6789
6790const _matrix$1 = /*@__PURE__*/ new Matrix4();
6791const _quaternion$3 = /*@__PURE__*/ new Quaternion();
6792
6793class Euler {
6794
6795	constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {
6796
6797		this.isEuler = true;
6798
6799		this._x = x;
6800		this._y = y;
6801		this._z = z;
6802		this._order = order;
6803
6804	}
6805
6806	get x() {
6807
6808		return this._x;
6809
6810	}
6811
6812	set x( value ) {
6813
6814		this._x = value;
6815		this._onChangeCallback();
6816
6817	}
6818
6819	get y() {
6820
6821		return this._y;
6822
6823	}
6824
6825	set y( value ) {
6826
6827		this._y = value;
6828		this._onChangeCallback();
6829
6830	}
6831
6832	get z() {
6833
6834		return this._z;
6835
6836	}
6837
6838	set z( value ) {
6839
6840		this._z = value;
6841		this._onChangeCallback();
6842
6843	}
6844
6845	get order() {
6846
6847		return this._order;
6848
6849	}
6850
6851	set order( value ) {
6852
6853		this._order = value;
6854		this._onChangeCallback();
6855
6856	}
6857
6858	set( x, y, z, order = this._order ) {
6859
6860		this._x = x;
6861		this._y = y;
6862		this._z = z;
6863		this._order = order;
6864
6865		this._onChangeCallback();
6866
6867		return this;
6868
6869	}
6870
6871	clone() {
6872
6873		return new this.constructor( this._x, this._y, this._z, this._order );
6874
6875	}
6876
6877	copy( euler ) {
6878
6879		this._x = euler._x;
6880		this._y = euler._y;
6881		this._z = euler._z;
6882		this._order = euler._order;
6883
6884		this._onChangeCallback();
6885
6886		return this;
6887
6888	}
6889
6890	setFromRotationMatrix( m, order = this._order, update = true ) {
6891
6892		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6893
6894		const te = m.elements;
6895		const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
6896		const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
6897		const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6898
6899		switch ( order ) {
6900
6901			case 'XYZ':
6902
6903				this._y = Math.asin( clamp( m13, - 1, 1 ) );
6904
6905				if ( Math.abs( m13 ) < 0.9999999 ) {
6906
6907					this._x = Math.atan2( - m23, m33 );
6908					this._z = Math.atan2( - m12, m11 );
6909
6910				} else {
6911
6912					this._x = Math.atan2( m32, m22 );
6913					this._z = 0;
6914
6915				}
6916
6917				break;
6918
6919			case 'YXZ':
6920
6921				this._x = Math.asin( - clamp( m23, - 1, 1 ) );
6922
6923				if ( Math.abs( m23 ) < 0.9999999 ) {
6924
6925					this._y = Math.atan2( m13, m33 );
6926					this._z = Math.atan2( m21, m22 );
6927
6928				} else {
6929
6930					this._y = Math.atan2( - m31, m11 );
6931					this._z = 0;
6932
6933				}
6934
6935				break;
6936
6937			case 'ZXY':
6938
6939				this._x = Math.asin( clamp( m32, - 1, 1 ) );
6940
6941				if ( Math.abs( m32 ) < 0.9999999 ) {
6942
6943					this._y = Math.atan2( - m31, m33 );
6944					this._z = Math.atan2( - m12, m22 );
6945
6946				} else {
6947
6948					this._y = 0;
6949					this._z = Math.atan2( m21, m11 );
6950
6951				}
6952
6953				break;
6954
6955			case 'ZYX':
6956
6957				this._y = Math.asin( - clamp( m31, - 1, 1 ) );
6958
6959				if ( Math.abs( m31 ) < 0.9999999 ) {
6960
6961					this._x = Math.atan2( m32, m33 );
6962					this._z = Math.atan2( m21, m11 );
6963
6964				} else {
6965
6966					this._x = 0;
6967					this._z = Math.atan2( - m12, m22 );
6968
6969				}
6970
6971				break;
6972
6973			case 'YZX':
6974
6975				this._z = Math.asin( clamp( m21, - 1, 1 ) );
6976
6977				if ( Math.abs( m21 ) < 0.9999999 ) {
6978
6979					this._x = Math.atan2( - m23, m22 );
6980					this._y = Math.atan2( - m31, m11 );
6981
6982				} else {
6983
6984					this._x = 0;
6985					this._y = Math.atan2( m13, m33 );
6986
6987				}
6988
6989				break;
6990
6991			case 'XZY':
6992
6993				this._z = Math.asin( - clamp( m12, - 1, 1 ) );
6994
6995				if ( Math.abs( m12 ) < 0.9999999 ) {
6996
6997					this._x = Math.atan2( m32, m22 );
6998					this._y = Math.atan2( m13, m11 );
6999
7000				} else {
7001
7002					this._x = Math.atan2( - m23, m33 );
7003					this._y = 0;
7004
7005				}
7006
7007				break;
7008
7009			default:
7010
7011				console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
7012
7013		}
7014
7015		this._order = order;
7016
7017		if ( update === true ) this._onChangeCallback();
7018
7019		return this;
7020
7021	}
7022
7023	setFromQuaternion( q, order, update ) {
7024
7025		_matrix$1.makeRotationFromQuaternion( q );
7026
7027		return this.setFromRotationMatrix( _matrix$1, order, update );
7028
7029	}
7030
7031	setFromVector3( v, order = this._order ) {
7032
7033		return this.set( v.x, v.y, v.z, order );
7034
7035	}
7036
7037	reorder( newOrder ) {
7038
7039		// WARNING: this discards revolution information -bhouston
7040
7041		_quaternion$3.setFromEuler( this );
7042
7043		return this.setFromQuaternion( _quaternion$3, newOrder );
7044
7045	}
7046
7047	equals( euler ) {
7048
7049		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
7050
7051	}
7052
7053	fromArray( array ) {
7054
7055		this._x = array[ 0 ];
7056		this._y = array[ 1 ];
7057		this._z = array[ 2 ];
7058		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
7059
7060		this._onChangeCallback();
7061
7062		return this;
7063
7064	}
7065
7066	toArray( array = [], offset = 0 ) {
7067
7068		array[ offset ] = this._x;
7069		array[ offset + 1 ] = this._y;
7070		array[ offset + 2 ] = this._z;
7071		array[ offset + 3 ] = this._order;
7072
7073		return array;
7074
7075	}
7076
7077	_onChange( callback ) {
7078
7079		this._onChangeCallback = callback;
7080
7081		return this;
7082
7083	}
7084
7085	_onChangeCallback() {}
7086
7087	*[ Symbol.iterator ]() {
7088
7089		yield this._x;
7090		yield this._y;
7091		yield this._z;
7092		yield this._order;
7093
7094	}
7095
7096}
7097
7098Euler.DEFAULT_ORDER = 'XYZ';
7099
7100class Layers {
7101
7102	constructor() {
7103
7104		this.mask = 1 | 0;
7105
7106	}
7107
7108	set( channel ) {
7109
7110		this.mask = ( 1 << channel | 0 ) >>> 0;
7111
7112	}
7113
7114	enable( channel ) {
7115
7116		this.mask |= 1 << channel | 0;
7117
7118	}
7119
7120	enableAll() {
7121
7122		this.mask = 0xffffffff | 0;
7123
7124	}
7125
7126	toggle( channel ) {
7127
7128		this.mask ^= 1 << channel | 0;
7129
7130	}
7131
7132	disable( channel ) {
7133
7134		this.mask &= ~ ( 1 << channel | 0 );
7135
7136	}
7137
7138	disableAll() {
7139
7140		this.mask = 0;
7141
7142	}
7143
7144	test( layers ) {
7145
7146		return ( this.mask & layers.mask ) !== 0;
7147
7148	}
7149
7150	isEnabled( channel ) {
7151
7152		return ( this.mask & ( 1 << channel | 0 ) ) !== 0;
7153
7154	}
7155
7156}
7157
7158let _object3DId = 0;
7159
7160const _v1$4 = /*@__PURE__*/ new Vector3();
7161const _q1 = /*@__PURE__*/ new Quaternion();
7162const _m1$1 = /*@__PURE__*/ new Matrix4();
7163const _target = /*@__PURE__*/ new Vector3();
7164
7165const _position$3 = /*@__PURE__*/ new Vector3();
7166const _scale$2 = /*@__PURE__*/ new Vector3();
7167const _quaternion$2 = /*@__PURE__*/ new Quaternion();
7168
7169const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
7170const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
7171const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
7172
7173const _addedEvent = { type: 'added' };
7174const _removedEvent = { type: 'removed' };
7175
7176class Object3D extends EventDispatcher {
7177
7178	constructor() {
7179
7180		super();
7181
7182		this.isObject3D = true;
7183
7184		Object.defineProperty( this, 'id', { value: _object3DId ++ } );
7185
7186		this.uuid = generateUUID();
7187
7188		this.name = '';
7189		this.type = 'Object3D';
7190
7191		this.parent = null;
7192		this.children = [];
7193
7194		this.up = Object3D.DEFAULT_UP.clone();
7195
7196		const position = new Vector3();
7197		const rotation = new Euler();
7198		const quaternion = new Quaternion();
7199		const scale = new Vector3( 1, 1, 1 );
7200
7201		function onRotationChange() {
7202
7203			quaternion.setFromEuler( rotation, false );
7204
7205		}
7206
7207		function onQuaternionChange() {
7208
7209			rotation.setFromQuaternion( quaternion, undefined, false );
7210
7211		}
7212
7213		rotation._onChange( onRotationChange );
7214		quaternion._onChange( onQuaternionChange );
7215
7216		Object.defineProperties( this, {
7217			position: {
7218				configurable: true,
7219				enumerable: true,
7220				value: position
7221			},
7222			rotation: {
7223				configurable: true,
7224				enumerable: true,
7225				value: rotation
7226			},
7227			quaternion: {
7228				configurable: true,
7229				enumerable: true,
7230				value: quaternion
7231			},
7232			scale: {
7233				configurable: true,
7234				enumerable: true,
7235				value: scale
7236			},
7237			modelViewMatrix: {
7238				value: new Matrix4()
7239			},
7240			normalMatrix: {
7241				value: new Matrix3()
7242			}
7243		} );
7244
7245		this.matrix = new Matrix4();
7246		this.matrixWorld = new Matrix4();
7247
7248		this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
7249
7250		this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
7251		this.matrixWorldNeedsUpdate = false;
7252
7253		this.layers = new Layers();
7254		this.visible = true;
7255
7256		this.castShadow = false;
7257		this.receiveShadow = false;
7258
7259		this.frustumCulled = true;
7260		this.renderOrder = 0;
7261
7262		this.animations = [];
7263
7264		this.userData = {};
7265
7266	}
7267
7268	onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7269
7270	onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7271
7272	onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7273
7274	onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7275
7276	applyMatrix4( matrix ) {
7277
7278		if ( this.matrixAutoUpdate ) this.updateMatrix();
7279
7280		this.matrix.premultiply( matrix );
7281
7282		this.matrix.decompose( this.position, this.quaternion, this.scale );
7283
7284	}
7285
7286	applyQuaternion( q ) {
7287
7288		this.quaternion.premultiply( q );
7289
7290		return this;
7291
7292	}
7293
7294	setRotationFromAxisAngle( axis, angle ) {
7295
7296		// assumes axis is normalized
7297
7298		this.quaternion.setFromAxisAngle( axis, angle );
7299
7300	}
7301
7302	setRotationFromEuler( euler ) {
7303
7304		this.quaternion.setFromEuler( euler, true );
7305
7306	}
7307
7308	setRotationFromMatrix( m ) {
7309
7310		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
7311
7312		this.quaternion.setFromRotationMatrix( m );
7313
7314	}
7315
7316	setRotationFromQuaternion( q ) {
7317
7318		// assumes q is normalized
7319
7320		this.quaternion.copy( q );
7321
7322	}
7323
7324	rotateOnAxis( axis, angle ) {
7325
7326		// rotate object on axis in object space
7327		// axis is assumed to be normalized
7328
7329		_q1.setFromAxisAngle( axis, angle );
7330
7331		this.quaternion.multiply( _q1 );
7332
7333		return this;
7334
7335	}
7336
7337	rotateOnWorldAxis( axis, angle ) {
7338
7339		// rotate object on axis in world space
7340		// axis is assumed to be normalized
7341		// method assumes no rotated parent
7342
7343		_q1.setFromAxisAngle( axis, angle );
7344
7345		this.quaternion.premultiply( _q1 );
7346
7347		return this;
7348
7349	}
7350
7351	rotateX( angle ) {
7352
7353		return this.rotateOnAxis( _xAxis, angle );
7354
7355	}
7356
7357	rotateY( angle ) {
7358
7359		return this.rotateOnAxis( _yAxis, angle );
7360
7361	}
7362
7363	rotateZ( angle ) {
7364
7365		return this.rotateOnAxis( _zAxis, angle );
7366
7367	}
7368
7369	translateOnAxis( axis, distance ) {
7370
7371		// translate object by distance along axis in object space
7372		// axis is assumed to be normalized
7373
7374		_v1$4.copy( axis ).applyQuaternion( this.quaternion );
7375
7376		this.position.add( _v1$4.multiplyScalar( distance ) );
7377
7378		return this;
7379
7380	}
7381
7382	translateX( distance ) {
7383
7384		return this.translateOnAxis( _xAxis, distance );
7385
7386	}
7387
7388	translateY( distance ) {
7389
7390		return this.translateOnAxis( _yAxis, distance );
7391
7392	}
7393
7394	translateZ( distance ) {
7395
7396		return this.translateOnAxis( _zAxis, distance );
7397
7398	}
7399
7400	localToWorld( vector ) {
7401
7402		this.updateWorldMatrix( true, false );
7403
7404		return vector.applyMatrix4( this.matrixWorld );
7405
7406	}
7407
7408	worldToLocal( vector ) {
7409
7410		this.updateWorldMatrix( true, false );
7411
7412		return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
7413
7414	}
7415
7416	lookAt( x, y, z ) {
7417
7418		// This method does not support objects having non-uniformly-scaled parent(s)
7419
7420		if ( x.isVector3 ) {
7421
7422			_target.copy( x );
7423
7424		} else {
7425
7426			_target.set( x, y, z );
7427
7428		}
7429
7430		const parent = this.parent;
7431
7432		this.updateWorldMatrix( true, false );
7433
7434		_position$3.setFromMatrixPosition( this.matrixWorld );
7435
7436		if ( this.isCamera || this.isLight ) {
7437
7438			_m1$1.lookAt( _position$3, _target, this.up );
7439
7440		} else {
7441
7442			_m1$1.lookAt( _target, _position$3, this.up );
7443
7444		}
7445
7446		this.quaternion.setFromRotationMatrix( _m1$1 );
7447
7448		if ( parent ) {
7449
7450			_m1$1.extractRotation( parent.matrixWorld );
7451			_q1.setFromRotationMatrix( _m1$1 );
7452			this.quaternion.premultiply( _q1.invert() );
7453
7454		}
7455
7456	}
7457
7458	add( object ) {
7459
7460		if ( arguments.length > 1 ) {
7461
7462			for ( let i = 0; i < arguments.length; i ++ ) {
7463
7464				this.add( arguments[ i ] );
7465
7466			}
7467
7468			return this;
7469
7470		}
7471
7472		if ( object === this ) {
7473
7474			console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
7475			return this;
7476
7477		}
7478
7479		if ( object && object.isObject3D ) {
7480
7481			if ( object.parent !== null ) {
7482
7483				object.parent.remove( object );
7484
7485			}
7486
7487			object.parent = this;
7488			this.children.push( object );
7489
7490			object.dispatchEvent( _addedEvent );
7491
7492		} else {
7493
7494			console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
7495
7496		}
7497
7498		return this;
7499
7500	}
7501
7502	remove( object ) {
7503
7504		if ( arguments.length > 1 ) {
7505
7506			for ( let i = 0; i < arguments.length; i ++ ) {
7507
7508				this.remove( arguments[ i ] );
7509
7510			}
7511
7512			return this;
7513
7514		}
7515
7516		const index = this.children.indexOf( object );
7517
7518		if ( index !== - 1 ) {
7519
7520			object.parent = null;
7521			this.children.splice( index, 1 );
7522
7523			object.dispatchEvent( _removedEvent );
7524
7525		}
7526
7527		return this;
7528
7529	}
7530
7531	removeFromParent() {
7532
7533		const parent = this.parent;
7534
7535		if ( parent !== null ) {
7536
7537			parent.remove( this );
7538
7539		}
7540
7541		return this;
7542
7543	}
7544
7545	clear() {
7546
7547		return this.remove( ... this.children );
7548
7549	}
7550
7551	attach( object ) {
7552
7553		// adds object as a child of this, while maintaining the object's world transform
7554
7555		// Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
7556
7557		this.updateWorldMatrix( true, false );
7558
7559		_m1$1.copy( this.matrixWorld ).invert();
7560
7561		if ( object.parent !== null ) {
7562
7563			object.parent.updateWorldMatrix( true, false );
7564
7565			_m1$1.multiply( object.parent.matrixWorld );
7566
7567		}
7568
7569		object.applyMatrix4( _m1$1
vendor: 11,708 bytes, lines 7569-8159
7569 );
7570
7571		this.add( object );
7572
7573		object.updateWorldMatrix( false, true );
7574
7575		return this;
7576
7577	}
7578
7579	getObjectById( id ) {
7580
7581		return this.getObjectByProperty( 'id', id );
7582
7583	}
7584
7585	getObjectByName( name ) {
7586
7587		return this.getObjectByProperty( 'name', name );
7588
7589	}
7590
7591	getObjectByProperty( name, value ) {
7592
7593		if ( this[ name ] === value ) return this;
7594
7595		for ( let i = 0, l = this.children.length; i < l; i ++ ) {
7596
7597			const child = this.children[ i ];
7598			const object = child.getObjectByProperty( name, value );
7599
7600			if ( object !== undefined ) {
7601
7602				return object;
7603
7604			}
7605
7606		}
7607
7608		return undefined;
7609
7610	}
7611
7612	getObjectsByProperty( name, value, result = [] ) {
7613
7614		if ( this[ name ] === value ) result.push( this );
7615
7616		const children = this.children;
7617
7618		for ( let i = 0, l = children.length; i < l; i ++ ) {
7619
7620			children[ i ].getObjectsByProperty( name, value, result );
7621
7622		}
7623
7624		return result;
7625
7626	}
7627
7628	getWorldPosition( target ) {
7629
7630		this.updateWorldMatrix( true, false );
7631
7632		return target.setFromMatrixPosition( this.matrixWorld );
7633
7634	}
7635
7636	getWorldQuaternion( target ) {
7637
7638		this.updateWorldMatrix( true, false );
7639
7640		this.matrixWorld.decompose( _position$3, target, _scale$2 );
7641
7642		return target;
7643
7644	}
7645
7646	getWorldScale( target ) {
7647
7648		this.updateWorldMatrix( true, false );
7649
7650		this.matrixWorld.decompose( _position$3, _quaternion$2, target );
7651
7652		return target;
7653
7654	}
7655
7656	getWorldDirection( target ) {
7657
7658		this.updateWorldMatrix( true, false );
7659
7660		const e = this.matrixWorld.elements;
7661
7662		return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
7663
7664	}
7665
7666	raycast( /* raycaster, intersects */ ) {}
7667
7668	traverse( callback ) {
7669
7670		callback( this );
7671
7672		const children = this.children;
7673
7674		for ( let i = 0, l = children.length; i < l; i ++ ) {
7675
7676			children[ i ].traverse( callback );
7677
7678		}
7679
7680	}
7681
7682	traverseVisible( callback ) {
7683
7684		if ( this.visible === false ) return;
7685
7686		callback( this );
7687
7688		const children = this.children;
7689
7690		for ( let i = 0, l = children.length; i < l; i ++ ) {
7691
7692			children[ i ].traverseVisible( callback );
7693
7694		}
7695
7696	}
7697
7698	traverseAncestors( callback ) {
7699
7700		const parent = this.parent;
7701
7702		if ( parent !== null ) {
7703
7704			callback( parent );
7705
7706			parent.traverseAncestors( callback );
7707
7708		}
7709
7710	}
7711
7712	updateMatrix() {
7713
7714		this.matrix.compose( this.position, this.quaternion, this.scale );
7715
7716		this.matrixWorldNeedsUpdate = true;
7717
7718	}
7719
7720	updateMatrixWorld( force ) {
7721
7722		if ( this.matrixAutoUpdate ) this.updateMatrix();
7723
7724		if ( this.matrixWorldNeedsUpdate || force ) {
7725
7726			if ( this.parent === null ) {
7727
7728				this.matrixWorld.copy( this.matrix );
7729
7730			} else {
7731
7732				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7733
7734			}
7735
7736			this.matrixWorldNeedsUpdate = false;
7737
7738			force = true;
7739
7740		}
7741
7742		// update children
7743
7744		const children = this.children;
7745
7746		for ( let i = 0, l = children.length; i < l; i ++ ) {
7747
7748			const child = children[ i ];
7749
7750			if ( child.matrixWorldAutoUpdate === true || force === true ) {
7751
7752				child.updateMatrixWorld( force );
7753
7754			}
7755
7756		}
7757
7758	}
7759
7760	updateWorldMatrix( updateParents, updateChildren ) {
7761
7762		const parent = this.parent;
7763
7764		if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) {
7765
7766			parent.updateWorldMatrix( true, false );
7767
7768		}
7769
7770		if ( this.matrixAutoUpdate ) this.updateMatrix();
7771
7772		if ( this.parent === null ) {
7773
7774			this.matrixWorld.copy( this.matrix );
7775
7776		} else {
7777
7778			this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7779
7780		}
7781
7782		// update children
7783
7784		if ( updateChildren === true ) {
7785
7786			const children = this.children;
7787
7788			for ( let i = 0, l = children.length; i < l; i ++ ) {
7789
7790				const child = children[ i ];
7791
7792				if ( child.matrixWorldAutoUpdate === true ) {
7793
7794					child.updateWorldMatrix( false, true );
7795
7796				}
7797
7798			}
7799
7800		}
7801
7802	}
7803
7804	toJSON( meta ) {
7805
7806		// meta is a string when called from JSON.stringify
7807		const isRootObject = ( meta === undefined || typeof meta === 'string' );
7808
7809		const output = {};
7810
7811		// meta is a hash used to collect geometries, materials.
7812		// not providing it implies that this is the root object
7813		// being serialized.
7814		if ( isRootObject ) {
7815
7816			// initialize meta obj
7817			meta = {
7818				geometries: {},
7819				materials: {},
7820				textures: {},
7821				images: {},
7822				shapes: {},
7823				skeletons: {},
7824				animations: {},
7825				nodes: {}
7826			};
7827
7828			output.metadata = {
7829				version: 4.6,
7830				type: 'Object',
7831				generator: 'Object3D.toJSON'
7832			};
7833
7834		}
7835
7836		// standard Object3D serialization
7837
7838		const object = {};
7839
7840		object.uuid = this.uuid;
7841		object.type = this.type;
7842
7843		if ( this.name !== '' ) object.name = this.name;
7844		if ( this.castShadow === true ) object.castShadow = true;
7845		if ( this.receiveShadow === true ) object.receiveShadow = true;
7846		if ( this.visible === false ) object.visible = false;
7847		if ( this.frustumCulled === false ) object.frustumCulled = false;
7848		if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
7849		if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
7850
7851		object.layers = this.layers.mask;
7852		object.matrix = this.matrix.toArray();
7853		object.up = this.up.toArray();
7854
7855		if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
7856
7857		// object specific properties
7858
7859		if ( this.isInstancedMesh ) {
7860
7861			object.type = 'InstancedMesh';
7862			object.count = this.count;
7863			object.instanceMatrix = this.instanceMatrix.toJSON();
7864			if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
7865
7866		}
7867
7868		if ( this.isBatchedMesh ) {
7869
7870			object.type = 'BatchedMesh';
7871			object.perObjectFrustumCulled = this.perObjectFrustumCulled;
7872			object.sortObjects = this.sortObjects;
7873
7874			object.drawRanges = this._drawRanges;
7875			object.reservedRanges = this._reservedRanges;
7876
7877			object.visibility = this._visibility;
7878			object.active = this._active;
7879			object.bounds = this._bounds.map( bound => ( {
7880				boxInitialized: bound.boxInitialized,
7881				boxMin: bound.box.min.toArray(),
7882				boxMax: bound.box.max.toArray(),
7883
7884				sphereInitialized: bound.sphereInitialized,
7885				sphereRadius: bound.sphere.radius,
7886				sphereCenter: bound.sphere.center.toArray()
7887			} ) );
7888
7889			object.maxGeometryCount = this._maxGeometryCount;
7890			object.maxVertexCount = this._maxVertexCount;
7891			object.maxIndexCount = this._maxIndexCount;
7892
7893			object.geometryInitialized = this._geometryInitialized;
7894			object.geometryCount = this._geometryCount;
7895
7896			object.matricesTexture = this._matricesTexture.toJSON( meta );
7897
7898			if ( this.boundingSphere !== null ) {
7899
7900				object.boundingSphere = {
7901					center: object.boundingSphere.center.toArray(),
7902					radius: object.boundingSphere.radius
7903				};
7904
7905			}
7906
7907			if ( this.boundingBox !== null ) {
7908
7909				object.boundingBox = {
7910					min: object.boundingBox.min.toArray(),
7911					max: object.boundingBox.max.toArray()
7912				};
7913
7914			}
7915
7916		}
7917
7918		//
7919
7920		function serialize( library, element ) {
7921
7922			if ( library[ element.uuid ] === undefined ) {
7923
7924				library[ element.uuid ] = element.toJSON( meta );
7925
7926			}
7927
7928			return element.uuid;
7929
7930		}
7931
7932		if ( this.isScene ) {
7933
7934			if ( this.background ) {
7935
7936				if ( this.background.isColor ) {
7937
7938					object.background = this.background.toJSON();
7939
7940				} else if ( this.background.isTexture ) {
7941
7942					object.background = this.background.toJSON( meta ).uuid;
7943
7944				}
7945
7946			}
7947
7948			if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
7949
7950				object.environment = this.environment.toJSON( meta ).uuid;
7951
7952			}
7953
7954		} else if ( this.isMesh || this.isLine || this.isPoints ) {
7955
7956			object.geometry = serialize( meta.geometries, this.geometry );
7957
7958			const parameters = this.geometry.parameters;
7959
7960			if ( parameters !== undefined && parameters.shapes !== undefined ) {
7961
7962				const shapes = parameters.shapes;
7963
7964				if ( Array.isArray( shapes ) ) {
7965
7966					for ( let i = 0, l = shapes.length; i < l; i ++ ) {
7967
7968						const shape = shapes[ i ];
7969
7970						serialize( meta.shapes, shape );
7971
7972					}
7973
7974				} else {
7975
7976					serialize( meta.shapes, shapes );
7977
7978				}
7979
7980			}
7981
7982		}
7983
7984		if ( this.isSkinnedMesh ) {
7985
7986			object.bindMode = this.bindMode;
7987			object.bindMatrix = this.bindMatrix.toArray();
7988
7989			if ( this.skeleton !== undefined ) {
7990
7991				serialize( meta.skeletons, this.skeleton );
7992
7993				object.skeleton = this.skeleton.uuid;
7994
7995			}
7996
7997		}
7998
7999		if ( this.material !== undefined ) {
8000
8001			if ( Array.isArray( this.material ) ) {
8002
8003				const uuids = [];
8004
8005				for ( let i = 0, l = this.material.length; i < l; i ++ ) {
8006
8007					uuids.push( serialize( meta.materials, this.material[ i ] ) );
8008
8009				}
8010
8011				object.material = uuids;
8012
8013			} else {
8014
8015				object.material = serialize( meta.materials, this.material );
8016
8017			}
8018
8019		}
8020
8021		//
8022
8023		if ( this.children.length > 0 ) {
8024
8025			object.children = [];
8026
8027			for ( let i = 0; i < this.children.length; i ++ ) {
8028
8029				object.children.push( this.children[ i ].toJSON( meta ).object );
8030
8031			}
8032
8033		}
8034
8035		//
8036
8037		if ( this.animations.length > 0 ) {
8038
8039			object.animations = [];
8040
8041			for ( let i = 0; i < this.animations.length; i ++ ) {
8042
8043				const animation = this.animations[ i ];
8044
8045				object.animations.push( serialize( meta.animations, animation ) );
8046
8047			}
8048
8049		}
8050
8051		if ( isRootObject ) {
8052
8053			const geometries = extractFromCache( meta.geometries );
8054			const materials = extractFromCache( meta.materials );
8055			const textures = extractFromCache( meta.textures );
8056			const images = extractFromCache( meta.images );
8057			const shapes = extractFromCache( meta.shapes );
8058			const skeletons = extractFromCache( meta.skeletons );
8059			const animations = extractFromCache( meta.animations );
8060			const nodes = extractFromCache( meta.nodes );
8061
8062			if ( geometries.length > 0 ) output.geometries = geometries;
8063			if ( materials.length > 0 ) output.materials = materials;
8064			if ( textures.length > 0 ) output.textures = textures;
8065			if ( images.length > 0 ) output.images = images;
8066			if ( shapes.length > 0 ) output.shapes = shapes;
8067			if ( skeletons.length > 0 ) output.skeletons = skeletons;
8068			if ( animations.length > 0 ) output.animations = animations;
8069			if ( nodes.length > 0 ) output.nodes = nodes;
8070
8071		}
8072
8073		output.object = object;
8074
8075		return output;
8076
8077		// extract data from the cache hash
8078		// remove metadata on each item
8079		// and return as array
8080		function extractFromCache( cache ) {
8081
8082			const values = [];
8083			for ( const key in cache ) {
8084
8085				const data = cache[ key ];
8086				delete data.metadata;
8087				values.push( data );
8088
8089			}
8090
8091			return values;
8092
8093		}
8094
8095	}
8096
8097	clone( recursive ) {
8098
8099		return new this.constructor().copy( this, recursive );
8100
8101	}
8102
8103	copy( source, recursive = true ) {
8104
8105		this.name = source.name;
8106
8107		this.up.copy( source.up );
8108
8109		this.position.copy( source.position );
8110		this.rotation.order = source.rotation.order;
8111		this.quaternion.copy( source.quaternion );
8112		this.scale.copy( source.scale );
8113
8114		this.matrix.copy( source.matrix );
8115		this.matrixWorld.copy( source.matrixWorld );
8116
8117		this.matrixAutoUpdate = source.matrixAutoUpdate;
8118
8119		this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
8120		this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
8121
8122		this.layers.mask = source.layers.mask;
8123		this.visible = source.visible;
8124
8125		this.castShadow = source.castShadow;
8126		this.receiveShadow = source.receiveShadow;
8127
8128		this.frustumCulled = source.frustumCulled;
8129		this.renderOrder = source.renderOrder;
8130
8131		this.animations = source.animations.slice();
8132
8133		this.userData = JSON.parse( JSON.stringify( source.userData ) );
8134
8135		if ( recursive === true ) {
8136
8137			for ( let i = 0; i < source.children.length; i ++ ) {
8138
8139				const child = source.children[ i ];
8140				this.add( child.clone() );
8141
8142			}
8143
8144		}
8145
8146		return this;
8147
8148	}
8149
8150}
8151
8152Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
8153Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true;
8154Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;
8155
8156const _v0$1 = /*@__PURE__*/ new Vector3();
8157const _v1$3 = /*@__PURE__*/ new Vector3();
8158const _v2$2 = /*@__PURE__*/ new Vector3();
8159const _v3$
81591 = /*@__PURE__*/ new Vector3();
8160
8161const _vab = /*@__PURE__*/ new Vector3();
8162const _vac = /*@__PURE__*/ new Vector3();
8163const _vbc = /*@__PURE__*/ new Vector3();
8164const _vap = /*@__PURE__*/ new Vector3();
8165const _vbp = /*@__PURE__*/ new Vector3();
8166const _vcp = /*@__PURE__*/ new Vector3();
8167
8168let warnedGetUV = false;
8169
8170class Triangle {
8171
8172	constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
8173
8174		this.a = a;
8175		this.b = b;
8176		this.c = c;
8177
8178	}
8179
8180	static getNormal( a, b, c, target ) {
8181
8182		target.subVectors( c, b );
8183		_v0$1.subVectors( a, b );
8184		target.cross( _v0$1 );
8185
8186		const targetLengthSq = target.lengthSq();
8187		if ( targetLengthSq > 0 ) {
8188
8189			return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
8190
8191		}
8192
8193		return target.set( 0, 0, 0 );
8194
8195	}
8196
8197	// static/instance method to calculate barycentric coordinates
8198	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
8199	static getBarycoord( point, a, b, c, target ) {
8200
8201		_v0$1.subVectors( c, a );
8202		_v1$3.subVectors( b, a );
8203		_v2$2.subVectors( point, a );
8204
vendor: 4,129 bytes, lines 8205-8412
8205		const dot00 = _v0$1.dot( _v0$1 );
8206		const dot01 = _v0$1.dot( _v1$3 );
8207		const dot02 = _v0$1.dot( _v2$2 );
8208		const dot11 = _v1$3.dot( _v1$3 );
8209		const dot12 = _v1$3.dot( _v2$2 );
8210
8211		const denom = ( dot00 * dot11 - dot01 * dot01 );
8212
8213		// collinear or singular triangle
8214		if ( denom === 0 ) {
8215
8216			target.set( 0, 0, 0 );
8217			return null;
8218
8219		}
8220
8221		const invDenom = 1 / denom;
8222		const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
8223		const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
8224
8225		// barycentric coordinates must always sum to 1
8226		return target.set( 1 - u - v, v, u );
8227
8228	}
8229
8230	static containsPoint( point, a, b, c ) {
8231
8232		// if the triangle is degenerate then we can't contain a point
8233		if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) {
8234
8235			return false;
8236
8237		}
8238
8239		return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 );
8240
8241	}
8242
8243	static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151
8244
8245		if ( warnedGetUV === false ) {
8246
8247			console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8248
8249			warnedGetUV = true;
8250
8251		}
8252
8253		return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target );
8254
8255	}
8256
8257	static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
8258
8259		if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) {
8260
8261			target.x = 0;
8262			target.y = 0;
8263			if ( 'z' in target ) target.z = 0;
8264			if ( 'w' in target ) target.w = 0;
8265			return null;
8266
8267		}
8268
8269		target.setScalar( 0 );
8270		target.addScaledVector( v1, _v3$1.x );
8271		target.addScaledVector( v2, _v3$1.y );
8272		target.addScaledVector( v3, _v3$1.z );
8273
8274		return target;
8275
8276	}
8277
8278	static isFrontFacing( a, b, c, direction ) {
8279
8280		_v0$1.subVectors( c, b );
8281		_v1$3.subVectors( a, b );
8282
8283		// strictly front facing
8284		return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
8285
8286	}
8287
8288	set( a, b, c ) {
8289
8290		this.a.copy( a );
8291		this.b.copy( b );
8292		this.c.copy( c );
8293
8294		return this;
8295
8296	}
8297
8298	setFromPointsAndIndices( points, i0, i1, i2 ) {
8299
8300		this.a.copy( points[ i0 ] );
8301		this.b.copy( points[ i1 ] );
8302		this.c.copy( points[ i2 ] );
8303
8304		return this;
8305
8306	}
8307
8308	setFromAttributeAndIndices( attribute, i0, i1, i2 ) {
8309
8310		this.a.fromBufferAttribute( attribute, i0 );
8311		this.b.fromBufferAttribute( attribute, i1 );
8312		this.c.fromBufferAttribute( attribute, i2 );
8313
8314		return this;
8315
8316	}
8317
8318	clone() {
8319
8320		return new this.constructor().copy( this );
8321
8322	}
8323
8324	copy( triangle ) {
8325
8326		this.a.copy( triangle.a );
8327		this.b.copy( triangle.b );
8328		this.c.copy( triangle.c );
8329
8330		return this;
8331
8332	}
8333
8334	getArea() {
8335
8336		_v0$1.subVectors( this.c, this.b );
8337		_v1$3.subVectors( this.a, this.b );
8338
8339		return _v0$1.cross( _v1$3 ).length() * 0.5;
8340
8341	}
8342
8343	getMidpoint( target ) {
8344
8345		return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
8346
8347	}
8348
8349	getNormal( target ) {
8350
8351		return Triangle.getNormal( this.a, this.b, this.c, target );
8352
8353	}
8354
8355	getPlane( target ) {
8356
8357		return target.setFromCoplanarPoints( this.a, this.b, this.c );
8358
8359	}
8360
8361	getBarycoord( point, target ) {
8362
8363		return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
8364
8365	}
8366
8367	getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151
8368
8369		if ( warnedGetUV === false ) {
8370
8371			console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8372
8373			warnedGetUV = true;
8374
8375		}
8376
8377		return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
8378
8379	}
8380
8381	getInterpolation( point, v1, v2, v3, target ) {
8382
8383		return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );
8384
8385	}
8386
8387	containsPoint( point ) {
8388
8389		return Triangle.containsPoint( point, this.a, this.b, this.c );
8390
8391	}
8392
8393	isFrontFacing( direction ) {
8394
8395		return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
8396
8397	}
8398
8399	intersectsBox( box ) {
8400
8401		return box.intersectsTriangle( this );
8402
8403	}
8404
8405	closestPointToPoint( p, target ) {
8406
8407		const a = this.a, b = this.b, c = this.c;
8408		let v, w;
8409
8410		// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
8411		// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
8412		// under the accompanying license; see chapter 5.1.5 for detailed explanation.
vendor: 26,125 bytes, lines 8413-9454
8413		// basically, we're distinguishing which of the voronoi regions of the triangle
8414		// the point lies in with the minimum amount of redundant computation.
8415
8416		_vab.subVectors( b, a );
8417		_vac.subVectors( c, a );
8418		_vap.subVectors( p, a );
8419		const d1 = _vab.dot( _vap );
8420		const d2 = _vac.dot( _vap );
8421		if ( d1 <= 0 && d2 <= 0 ) {
8422
8423			// vertex region of A; barycentric coords (1, 0, 0)
8424			return target.copy( a );
8425
8426		}
8427
8428		_vbp.subVectors( p, b );
8429		const d3 = _vab.dot( _vbp );
8430		const d4 = _vac.dot( _vbp );
8431		if ( d3 >= 0 && d4 <= d3 ) {
8432
8433			// vertex region of B; barycentric coords (0, 1, 0)
8434			return target.copy( b );
8435
8436		}
8437
8438		const vc = d1 * d4 - d3 * d2;
8439		if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
8440
8441			v = d1 / ( d1 - d3 );
8442			// edge region of AB; barycentric coords (1-v, v, 0)
8443			return target.copy( a ).addScaledVector( _vab, v );
8444
8445		}
8446
8447		_vcp.subVectors( p, c );
8448		const d5 = _vab.dot( _vcp );
8449		const d6 = _vac.dot( _vcp );
8450		if ( d6 >= 0 && d5 <= d6 ) {
8451
8452			// vertex region of C; barycentric coords (0, 0, 1)
8453			return target.copy( c );
8454
8455		}
8456
8457		const vb = d5 * d2 - d1 * d6;
8458		if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
8459
8460			w = d2 / ( d2 - d6 );
8461			// edge region of AC; barycentric coords (1-w, 0, w)
8462			return target.copy( a ).addScaledVector( _vac, w );
8463
8464		}
8465
8466		const va = d3 * d6 - d5 * d4;
8467		if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
8468
8469			_vbc.subVectors( c, b );
8470			w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
8471			// edge region of BC; barycentric coords (0, 1-w, w)
8472			return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
8473
8474		}
8475
8476		// face region
8477		const denom = 1 / ( va + vb + vc );
8478		// u = va * denom
8479		v = vb * denom;
8480		w = vc * denom;
8481
8482		return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
8483
8484	}
8485
8486	equals( triangle ) {
8487
8488		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
8489
8490	}
8491
8492}
8493
8494const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
8495	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
8496	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
8497	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
8498	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
8499	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
8500	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
8501	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
8502	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
8503	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
8504	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
8505	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
8506	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
8507	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
8508	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
8509	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
8510	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
8511	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
8512	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
8513	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
8514	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
8515	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
8516	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
8517	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
8518
8519const _hslA = { h: 0, s: 0, l: 0 };
8520const _hslB = { h: 0, s: 0, l: 0 };
8521
8522function hue2rgb( p, q, t ) {
8523
8524	if ( t < 0 ) t += 1;
8525	if ( t > 1 ) t -= 1;
8526	if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
8527	if ( t < 1 / 2 ) return q;
8528	if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
8529	return p;
8530
8531}
8532
8533class Color {
8534
8535	constructor( r, g, b ) {
8536
8537		this.isColor = true;
8538
8539		this.r = 1;
8540		this.g = 1;
8541		this.b = 1;
8542
8543		return this.set( r, g, b );
8544
8545	}
8546
8547	set( r, g, b ) {
8548
8549		if ( g === undefined && b === undefined ) {
8550
8551			// r is THREE.Color, hex or string
8552
8553			const value = r;
8554
8555			if ( value && value.isColor ) {
8556
8557				this.copy( value );
8558
8559			} else if ( typeof value === 'number' ) {
8560
8561				this.setHex( value );
8562
8563			} else if ( typeof value === 'string' ) {
8564
8565				this.setStyle( value );
8566
8567			}
8568
8569		} else {
8570
8571			this.setRGB( r, g, b );
8572
8573		}
8574
8575		return this;
8576
8577	}
8578
8579	setScalar( scalar ) {
8580
8581		this.r = scalar;
8582		this.g = scalar;
8583		this.b = scalar;
8584
8585		return this;
8586
8587	}
8588
8589	setHex( hex, colorSpace = SRGBColorSpace ) {
8590
8591		hex = Math.floor( hex );
8592
8593		this.r = ( hex >> 16 & 255 ) / 255;
8594		this.g = ( hex >> 8 & 255 ) / 255;
8595		this.b = ( hex & 255 ) / 255;
8596
8597		ColorManagement.toWorkingColorSpace( this, colorSpace );
8598
8599		return this;
8600
8601	}
8602
8603	setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {
8604
8605		this.r = r;
8606		this.g = g;
8607		this.b = b;
8608
8609		ColorManagement.toWorkingColorSpace( this, colorSpace );
8610
8611		return this;
8612
8613	}
8614
8615	setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {
8616
8617		// h,s,l ranges are in 0.0 - 1.0
8618		h = euclideanModulo( h, 1 );
8619		s = clamp( s, 0, 1 );
8620		l = clamp( l, 0, 1 );
8621
8622		if ( s === 0 ) {
8623
8624			this.r = this.g = this.b = l;
8625
8626		} else {
8627
8628			const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
8629			const q = ( 2 * l ) - p;
8630
8631			this.r = hue2rgb( q, p, h + 1 / 3 );
8632			this.g = hue2rgb( q, p, h );
8633			this.b = hue2rgb( q, p, h - 1 / 3 );
8634
8635		}
8636
8637		ColorManagement.toWorkingColorSpace( this, colorSpace );
8638
8639		return this;
8640
8641	}
8642
8643	setStyle( style, colorSpace = SRGBColorSpace ) {
8644
8645		function handleAlpha( string ) {
8646
8647			if ( string === undefined ) return;
8648
8649			if ( parseFloat( string ) < 1 ) {
8650
8651				console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
8652
8653			}
8654
8655		}
8656
8657
8658		let m;
8659
8660		if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) {
8661
8662			// rgb / hsl
8663
8664			let color;
8665			const name = m[ 1 ];
8666			const components = m[ 2 ];
8667
8668			switch ( name ) {
8669
8670				case 'rgb':
8671				case 'rgba':
8672
8673					if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8674
8675						// rgb(255,0,0) rgba(255,0,0,0.5)
8676
8677						handleAlpha( color[ 4 ] );
8678
8679						return this.setRGB(
8680							Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,
8681							Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,
8682							Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,
8683							colorSpace
8684						);
8685
8686					}
8687
8688					if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8689
8690						// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
8691
8692						handleAlpha( color[ 4 ] );
8693
8694						return this.setRGB(
8695							Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,
8696							Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,
8697							Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,
8698							colorSpace
8699						);
8700
8701					}
8702
8703					break;
8704
8705				case 'hsl':
8706				case 'hsla':
8707
8708					if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8709
8710						// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
8711
8712						handleAlpha( color[ 4 ] );
8713
8714						return this.setHSL(
8715							parseFloat( color[ 1 ] ) / 360,
8716							parseFloat( color[ 2 ] ) / 100,
8717							parseFloat( color[ 3 ] ) / 100,
8718							colorSpace
8719						);
8720
8721					}
8722
8723					break;
8724
8725				default:
8726
8727					console.warn( 'THREE.Color: Unknown color model ' + style );
8728
8729			}
8730
8731		} else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
8732
8733			// hex color
8734
8735			const hex = m[ 1 ];
8736			const size = hex.length;
8737
8738			if ( size === 3 ) {
8739
8740				// #ff0
8741				return this.setRGB(
8742					parseInt( hex.charAt( 0 ), 16 ) / 15,
8743					parseInt( hex.charAt( 1 ), 16 ) / 15,
8744					parseInt( hex.charAt( 2 ), 16 ) / 15,
8745					colorSpace
8746				);
8747
8748			} else if ( size === 6 ) {
8749
8750				// #ff0000
8751				return this.setHex( parseInt( hex, 16 ), colorSpace );
8752
8753			} else {
8754
8755				console.warn( 'THREE.Color: Invalid hex color ' + style );
8756
8757			}
8758
8759		} else if ( style && style.length > 0 ) {
8760
8761			return this.setColorName( style, colorSpace );
8762
8763		}
8764
8765		return this;
8766
8767	}
8768
8769	setColorName( style, colorSpace = SRGBColorSpace ) {
8770
8771		// color keywords
8772		const hex = _colorKeywords[ style.toLowerCase() ];
8773
8774		if ( hex !== undefined ) {
8775
8776			// red
8777			this.setHex( hex, colorSpace );
8778
8779		} else {
8780
8781			// unknown color
8782			console.warn( 'THREE.Color: Unknown color ' + style );
8783
8784		}
8785
8786		return this;
8787
8788	}
8789
8790	clone() {
8791
8792		return new this.constructor( this.r, this.g, this.b );
8793
8794	}
8795
8796	copy( color ) {
8797
8798		this.r = color.r;
8799		this.g = color.g;
8800		this.b = color.b;
8801
8802		return this;
8803
8804	}
8805
8806	copySRGBToLinear( color ) {
8807
8808		this.r = SRGBToLinear( color.r );
8809		this.g = SRGBToLinear( color.g );
8810		this.b = SRGBToLinear( color.b );
8811
8812		return this;
8813
8814	}
8815
8816	copyLinearToSRGB( color ) {
8817
8818		this.r = LinearToSRGB( color.r );
8819		this.g = LinearToSRGB( color.g );
8820		this.b = LinearToSRGB( color.b );
8821
8822		return this;
8823
8824	}
8825
8826	convertSRGBToLinear() {
8827
8828		this.copySRGBToLinear( this );
8829
8830		return this;
8831
8832	}
8833
8834	convertLinearToSRGB() {
8835
8836		this.copyLinearToSRGB( this );
8837
8838		return this;
8839
8840	}
8841
8842	getHex( colorSpace = SRGBColorSpace ) {
8843
8844		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8845
8846		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 ) );
8847
8848	}
8849
8850	getHexString( colorSpace = SRGBColorSpace ) {
8851
8852		return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );
8853
8854	}
8855
8856	getHSL( target, colorSpace = ColorManagement.workingColorSpace ) {
8857
8858		// h,s,l ranges are in 0.0 - 1.0
8859
8860		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8861
8862		const r = _color.r, g = _color.g, b = _color.b;
8863
8864		const max = Math.max( r, g, b );
8865		const min = Math.min( r, g, b );
8866
8867		let hue, saturation;
8868		const lightness = ( min + max ) / 2.0;
8869
8870		if ( min === max ) {
8871
8872			hue = 0;
8873			saturation = 0;
8874
8875		} else {
8876
8877			const delta = max - min;
8878
8879			saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
8880
8881			switch ( max ) {
8882
8883				case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
8884				case g: hue = ( b - r ) / delta + 2; break;
8885				case b: hue = ( r - g ) / delta + 4; break;
8886
8887			}
8888
8889			hue /= 6;
8890
8891		}
8892
8893		target.h = hue;
8894		target.s = saturation;
8895		target.l = lightness;
8896
8897		return target;
8898
8899	}
8900
8901	getRGB( target, colorSpace = ColorManagement.workingColorSpace ) {
8902
8903		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8904
8905		target.r = _color.r;
8906		target.g = _color.g;
8907		target.b = _color.b;
8908
8909		return target;
8910
8911	}
8912
8913	getStyle( colorSpace = SRGBColorSpace ) {
8914
8915		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8916
8917		const r = _color.r, g = _color.g, b = _color.b;
8918
8919		if ( colorSpace !== SRGBColorSpace ) {
8920
8921			// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
8922			return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;
8923
8924		}
8925
8926		return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;
8927
8928	}
8929
8930	offsetHSL( h, s, l ) {
8931
8932		this.getHSL( _hslA );
8933
8934		return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );
8935
8936	}
8937
8938	add( color ) {
8939
8940		this.r += color.r;
8941		this.g += color.g;
8942		this.b += color.b;
8943
8944		return this;
8945
8946	}
8947
8948	addColors( color1, color2 ) {
8949
8950		this.r = color1.r + color2.r;
8951		this.g = color1.g + color2.g;
8952		this.b = color1.b + color2.b;
8953
8954		return this;
8955
8956	}
8957
8958	addScalar( s ) {
8959
8960		this.r += s;
8961		this.g += s;
8962		this.b += s;
8963
8964		return this;
8965
8966	}
8967
8968	sub( color ) {
8969
8970		this.r = Math.max( 0, this.r - color.r );
8971		this.g = Math.max( 0, this.g - color.g );
8972		this.b = Math.max( 0, this.b - color.b );
8973
8974		return this;
8975
8976	}
8977
8978	multiply( color ) {
8979
8980		this.r *= color.r;
8981		this.g *= color.g;
8982		this.b *= color.b;
8983
8984		return this;
8985
8986	}
8987
8988	multiplyScalar( s ) {
8989
8990		this.r *= s;
8991		this.g *= s;
8992		this.b *= s;
8993
8994		return this;
8995
8996	}
8997
8998	lerp( color, alpha ) {
8999
9000		this.r += ( color.r - this.r ) * alpha;
9001		this.g += ( color.g - this.g ) * alpha;
9002		this.b += ( color.b - this.b ) * alpha;
9003
9004		return this;
9005
9006	}
9007
9008	lerpColors( color1, color2, alpha ) {
9009
9010		this.r = color1.r + ( color2.r - color1.r ) * alpha;
9011		this.g = color1.g + ( color2.g - color1.g ) * alpha;
9012		this.b = color1.b + ( color2.b - color1.b ) * alpha;
9013
9014		return this;
9015
9016	}
9017
9018	lerpHSL( color, alpha ) {
9019
9020		this.getHSL( _hslA );
9021		color.getHSL( _hslB );
9022
9023		const h = lerp( _hslA.h, _hslB.h, alpha );
9024		const s = lerp( _hslA.s, _hslB.s, alpha );
9025		const l = lerp( _hslA.l, _hslB.l, alpha );
9026
9027		this.setHSL( h, s, l );
9028
9029		return this;
9030
9031	}
9032
9033	setFromVector3( v ) {
9034
9035		this.r = v.x;
9036		this.g = v.y;
9037		this.b = v.z;
9038
9039		return this;
9040
9041	}
9042
9043	applyMatrix3( m ) {
9044
9045		const r = this.r, g = this.g, b = this.b;
9046		const e = m.elements;
9047
9048		this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;
9049		this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;
9050		this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;
9051
9052		return this;
9053
9054	}
9055
9056	equals( c ) {
9057
9058		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
9059
9060	}
9061
9062	fromArray( array, offset = 0 ) {
9063
9064		this.r = array[ offset ];
9065		this.g = array[ offset + 1 ];
9066		this.b = array[ offset + 2 ];
9067
9068		return this;
9069
9070	}
9071
9072	toArray( array = [], offset = 0 ) {
9073
9074		array[ offset ] = this.r;
9075		array[ offset + 1 ] = this.g;
9076		array[ offset + 2 ] = this.b;
9077
9078		return array;
9079
9080	}
9081
9082	fromBufferAttribute( attribute, index ) {
9083
9084		this.r = attribute.getX( index );
9085		this.g = attribute.getY( index );
9086		this.b = attribute.getZ( index );
9087
9088		return this;
9089
9090	}
9091
9092	toJSON() {
9093
9094		return this.getHex();
9095
9096	}
9097
9098	*[ Symbol.iterator ]() {
9099
9100		yield this.r;
9101		yield this.g;
9102		yield this.b;
9103
9104	}
9105
9106}
9107
9108const _color = /*@__PURE__*/ new Color();
9109
9110Color.NAMES = _colorKeywords;
9111
9112let _materialId = 0;
9113
9114class Material extends EventDispatcher {
9115
9116	constructor() {
9117
9118		super();
9119
9120		this.isMaterial = true;
9121
9122		Object.defineProperty( this, 'id', { value: _materialId ++ } );
9123
9124		this.uuid = generateUUID();
9125
9126		this.name = '';
9127		this.type = 'Material';
9128
9129		this.blending = NormalBlending;
9130		this.side = FrontSide;
9131		this.vertexColors = false;
9132
9133		this.opacity = 1;
9134		this.transparent = false;
9135		this.alphaHash = false;
9136
9137		this.blendSrc = SrcAlphaFactor;
9138		this.blendDst = OneMinusSrcAlphaFactor;
9139		this.blendEquation = AddEquation;
9140		this.blendSrcAlpha = null;
9141		this.blendDstAlpha = null;
9142		this.blendEquationAlpha = null;
9143		this.blendColor = new Color( 0, 0, 0 );
9144		this.blendAlpha = 0;
9145
9146		this.depthFunc = LessEqualDepth;
9147		this.depthTest = true;
9148		this.depthWrite = true;
9149
9150		this.stencilWriteMask = 0xff;
9151		this.stencilFunc = AlwaysStencilFunc;
9152		this.stencilRef = 0;
9153		this.stencilFuncMask = 0xff;
9154		this.stencilFail = KeepStencilOp;
9155		this.stencilZFail = KeepStencilOp;
9156		this.stencilZPass = KeepStencilOp;
9157		this.stencilWrite = false;
9158
9159		this.clippingPlanes = null;
9160		this.clipIntersection = false;
9161		this.clipShadows = false;
9162
9163		this.shadowSide = null;
9164
9165		this.colorWrite = true;
9166
9167		this.precision = null; // override the renderer's default precision for this material
9168
9169		this.polygonOffset = false;
9170		this.polygonOffsetFactor = 0;
9171		this.polygonOffsetUnits = 0;
9172
9173		this.dithering = false;
9174
9175		this.alphaToCoverage = false;
9176		this.premultipliedAlpha = false;
9177		this.forceSinglePass = false;
9178
9179		this.visible = true;
9180
9181		this.toneMapped = true;
9182
9183		this.userData = {};
9184
9185		this.version = 0;
9186
9187		this._alphaTest = 0;
9188
9189	}
9190
9191	get alphaTest() {
9192
9193		return this._alphaTest;
9194
9195	}
9196
9197	set alphaTest( value ) {
9198
9199		if ( this._alphaTest > 0 !== value > 0 ) {
9200
9201			this.version ++;
9202
9203		}
9204
9205		this._alphaTest = value;
9206
9207	}
9208
9209	onBuild( /* shaderobject, renderer */ ) {}
9210
9211	onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
9212
9213	onBeforeCompile( /* shaderobject, renderer */ ) {}
9214
9215	customProgramCacheKey() {
9216
9217		return this.onBeforeCompile.toString();
9218
9219	}
9220
9221	setValues( values ) {
9222
9223		if ( values === undefined ) return;
9224
9225		for ( const key in values ) {
9226
9227			const newValue = values[ key ];
9228
9229			if ( newValue === undefined ) {
9230
9231				console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );
9232				continue;
9233
9234			}
9235
9236			const currentValue = this[ key ];
9237
9238			if ( currentValue === undefined ) {
9239
9240				console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );
9241				continue;
9242
9243			}
9244
9245			if ( currentValue && currentValue.isColor ) {
9246
9247				currentValue.set( newValue );
9248
9249			} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
9250
9251				currentValue.copy( newValue );
9252
9253			} else {
9254
9255				this[ key ] = newValue;
9256
9257			}
9258
9259		}
9260
9261	}
9262
9263	toJSON( meta ) {
9264
9265		const isRootObject = ( meta === undefined || typeof meta === 'string' );
9266
9267		if ( isRootObject ) {
9268
9269			meta = {
9270				textures: {},
9271				images: {}
9272			};
9273
9274		}
9275
9276		const data = {
9277			metadata: {
9278				version: 4.6,
9279				type: 'Material',
9280				generator: 'Material.toJSON'
9281			}
9282		};
9283
9284		// standard Material serialization
9285		data.uuid = this.uuid;
9286		data.type = this.type;
9287
9288		if ( this.name !== '' ) data.name = this.name;
9289
9290		if ( this.color && this.color.isColor ) data.color = this.color.getHex();
9291
9292		if ( this.roughness !== undefined ) data.roughness = this.roughness;
9293		if ( this.metalness !== undefined ) data.metalness = this.metalness;
9294
9295		if ( this.sheen !== undefined ) data.sheen = this.sheen;
9296		if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
9297		if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
9298		if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
9299		if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
9300
9301		if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
9302		if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
9303		if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
9304		if ( this.shininess !== undefined ) data.shininess = this.shininess;
9305		if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
9306		if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
9307
9308		if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
9309
9310			data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
9311
9312		}
9313
9314		if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
9315
9316			data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
9317
9318		}
9319
9320		if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
9321
9322			data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
9323			data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
9324
9325		}
9326
9327		if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
9328		if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
9329		if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
9330
9331		if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
9332
9333			data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
9334
9335		}
9336
9337		if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
9338
9339			data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
9340
9341		}
9342
9343		if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
9344		if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
9345
9346		if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
9347
9348			data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
9349
9350		}
9351
9352		if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
9353		if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
9354		if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
9355
9356		if ( this.lightMap && this.lightMap.isTexture ) {
9357
9358			data.lightMap = this.lightMap.toJSON( meta ).uuid;
9359			data.lightMapIntensity = this.lightMapIntensity;
9360
9361		}
9362
9363		if ( this.aoMap && this.aoMap.isTexture ) {
9364
9365			data.aoMap = this.aoMap.toJSON( meta ).uuid;
9366			data.aoMapIntensity = this.aoMapIntensity;
9367
9368		}
9369
9370		if ( this.bumpMap && this.bumpMap.isTexture ) {
9371
9372			data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
9373			data.bumpScale = this.bumpScale;
9374
9375		}
9376
9377		if ( this.normalMap && this.normalMap.isTexture ) {
9378
9379			data.normalMap = this.normalMap.toJSON( meta ).uuid;
9380			data.normalMapType = this.normalMapType;
9381			data.normalScale = this.normalScale.toArray();
9382
9383		}
9384
9385		if ( this.displacementMap && this.displacementMap.isTexture ) {
9386
9387			data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
9388			data.displacementScale = this.displacementScale;
9389			data.displacementBias = this.displacementBias;
9390
9391		}
9392
9393		if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
9394		if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
9395
9396		if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
9397		if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
9398		if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
9399		if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
9400
9401		if ( this.envMap && this.envMap.isTexture ) {
9402
9403			data.envMap = this.envMap.toJSON( meta ).uuid;
9404
9405			if ( this.combine !== undefined ) data.combine = this.combine;
9406
9407		}
9408
9409		if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
9410		if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
9411		if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
9412
9413		if ( this.gradientMap && this.gradientMap.isTexture ) {
9414
9415			data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
9416
9417		}
9418
9419		if ( this.transmission !== undefined ) data.transmission = this.transmission;
9420		if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
9421		if ( this.thickness !== undefined ) data.thickness = this.thickness;
9422		if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
9423		if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
9424		if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
9425
9426		if ( this.size !== undefined ) data.size = this.size;
9427		if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
9428		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
9429
9430		if ( this.blending !== NormalBlending ) data.blending = this.blending;
9431		if ( this.side !== FrontSide ) data.side = this.side;
9432		if ( this.vertexColors === true ) data.vertexColors = true;
9433
9434		if ( this.opacity < 1 ) data.opacity = this.opacity;
9435		if ( this.transparent === true ) data.transparent = true;
9436
9437		if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
9438		if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
9439		if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
9440		if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
9441		if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
9442		if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
9443		if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
9444		if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
9445
9446		if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
9447		if ( this.depthTest === false ) data.depthTest = this.depthTest;
9448		if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
9449		if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
9450
9451		if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
9452		if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
9453		if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
9454		if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
vendor: 5,379 bytes, lines 9455-9657
9455		if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
9456		if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
9457		if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
9458		if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
9459
9460		// rotation (SpriteMaterial)
9461		if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
9462
9463		if ( this.polygonOffset === true ) data.polygonOffset = true;
9464		if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
9465		if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
9466
9467		if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
9468		if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
9469		if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
9470		if ( this.scale !== undefined ) data.scale = this.scale;
9471
9472		if ( this.dithering === true ) data.dithering = true;
9473
9474		if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
9475		if ( this.alphaHash === true ) data.alphaHash = true;
9476		if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
9477		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
9478		if ( this.forceSinglePass === true ) data.forceSinglePass = true;
9479
9480		if ( this.wireframe === true ) data.wireframe = true;
9481		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
9482		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
9483		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
9484
9485		if ( this.flatShading === true ) data.flatShading = true;
9486
9487		if ( this.visible === false ) data.visible = false;
9488
9489		if ( this.toneMapped === false ) data.toneMapped = false;
9490
9491		if ( this.fog === false ) data.fog = false;
9492
9493		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
9494
9495		// TODO: Copied from Object3D.toJSON
9496
9497		function extractFromCache( cache ) {
9498
9499			const values = [];
9500
9501			for ( const key in cache ) {
9502
9503				const data = cache[ key ];
9504				delete data.metadata;
9505				values.push( data );
9506
9507			}
9508
9509			return values;
9510
9511		}
9512
9513		if ( isRootObject ) {
9514
9515			const textures = extractFromCache( meta.textures );
9516			const images = extractFromCache( meta.images );
9517
9518			if ( textures.length > 0 ) data.textures = textures;
9519			if ( images.length > 0 ) data.images = images;
9520
9521		}
9522
9523		return data;
9524
9525	}
9526
9527	clone() {
9528
9529		return new this.constructor().copy( this );
9530
9531	}
9532
9533	copy( source ) {
9534
9535		this.name = source.name;
9536
9537		this.blending = source.blending;
9538		this.side = source.side;
9539		this.vertexColors = source.vertexColors;
9540
9541		this.opacity = source.opacity;
9542		this.transparent = source.transparent;
9543
9544		this.blendSrc = source.blendSrc;
9545		this.blendDst = source.blendDst;
9546		this.blendEquation = source.blendEquation;
9547		this.blendSrcAlpha = source.blendSrcAlpha;
9548		this.blendDstAlpha = source.blendDstAlpha;
9549		this.blendEquationAlpha = source.blendEquationAlpha;
9550		this.blendColor.copy( source.blendColor );
9551		this.blendAlpha = source.blendAlpha;
9552
9553		this.depthFunc = source.depthFunc;
9554		this.depthTest = source.depthTest;
9555		this.depthWrite = source.depthWrite;
9556
9557		this.stencilWriteMask = source.stencilWriteMask;
9558		this.stencilFunc = source.stencilFunc;
9559		this.stencilRef = source.stencilRef;
9560		this.stencilFuncMask = source.stencilFuncMask;
9561		this.stencilFail = source.stencilFail;
9562		this.stencilZFail = source.stencilZFail;
9563		this.stencilZPass = source.stencilZPass;
9564		this.stencilWrite = source.stencilWrite;
9565
9566		const srcPlanes = source.clippingPlanes;
9567		let dstPlanes = null;
9568
9569		if ( srcPlanes !== null ) {
9570
9571			const n = srcPlanes.length;
9572			dstPlanes = new Array( n );
9573
9574			for ( let i = 0; i !== n; ++ i ) {
9575
9576				dstPlanes[ i ] = srcPlanes[ i ].clone();
9577
9578			}
9579
9580		}
9581
9582		this.clippingPlanes = dstPlanes;
9583		this.clipIntersection = source.clipIntersection;
9584		this.clipShadows = source.clipShadows;
9585
9586		this.shadowSide = source.shadowSide;
9587
9588		this.colorWrite = source.colorWrite;
9589
9590		this.precision = source.precision;
9591
9592		this.polygonOffset = source.polygonOffset;
9593		this.polygonOffsetFactor = source.polygonOffsetFactor;
9594		this.polygonOffsetUnits = source.polygonOffsetUnits;
9595
9596		this.dithering = source.dithering;
9597
9598		this.alphaTest = source.alphaTest;
9599		this.alphaHash = source.alphaHash;
9600		this.alphaToCoverage = source.alphaToCoverage;
9601		this.premultipliedAlpha = source.premultipliedAlpha;
9602		this.forceSinglePass = source.forceSinglePass;
9603
9604		this.visible = source.visible;
9605
9606		this.toneMapped = source.toneMapped;
9607
9608		this.userData = JSON.parse( JSON.stringify( source.userData ) );
9609
9610		return this;
9611
9612	}
9613
9614	dispose() {
9615
9616		this.dispatchEvent( { type: 'dispose' } );
9617
9618	}
9619
9620	set needsUpdate( value ) {
9621
9622		if ( value === true ) this.version ++;
9623
9624	}
9625
9626}
9627
9628class MeshBasicMaterial extends Material {
9629
9630	constructor( parameters ) {
9631
9632		super();
9633
9634		this.isMeshBasicMaterial = true;
9635
9636		this.type = 'MeshBasicMaterial';
9637
9638		this.color = new Color( 0xffffff ); // emissive
9639
9640		this.map = null;
9641
9642		this.lightMap = null;
9643		this.lightMapIntensity = 1.0;
9644
9645		this.aoMap = null;
9646		this.aoMapIntensity = 1.0;
9647
9648		this.specularMap = null;
9649
9650		this.alphaMap = null;
9651
9652		this.envMap = null;
9653		this.combine = MultiplyOperation;
9654		this.reflectivity = 1;
9655		this.refractionRatio = 0.98;
9656
9657		this.wireframe = false;
vendor: 5,583 bytes, lines 9658-9942
9658		this.wireframeLinewidth = 1;
9659		this.wireframeLinecap = 'round';
9660		this.wireframeLinejoin = 'round';
9661
9662		this.fog = true;
9663
9664		this.setValues( parameters );
9665
9666	}
9667
9668	copy( source ) {
9669
9670		super.copy( source );
9671
9672		this.color.copy( source.color );
9673
9674		this.map = source.map;
9675
9676		this.lightMap = source.lightMap;
9677		this.lightMapIntensity = source.lightMapIntensity;
9678
9679		this.aoMap = source.aoMap;
9680		this.aoMapIntensity = source.aoMapIntensity;
9681
9682		this.specularMap = source.specularMap;
9683
9684		this.alphaMap = source.alphaMap;
9685
9686		this.envMap = source.envMap;
9687		this.combine = source.combine;
9688		this.reflectivity = source.reflectivity;
9689		this.refractionRatio = source.refractionRatio;
9690
9691		this.wireframe = source.wireframe;
9692		this.wireframeLinewidth = source.wireframeLinewidth;
9693		this.wireframeLinecap = source.wireframeLinecap;
9694		this.wireframeLinejoin = source.wireframeLinejoin;
9695
9696		this.fog = source.fog;
9697
9698		return this;
9699
9700	}
9701
9702}
9703
9704// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
9705
9706const _tables = /*@__PURE__*/ _generateTables();
9707
9708function _generateTables() {
9709
9710	// float32 to float16 helpers
9711
9712	const buffer = new ArrayBuffer( 4 );
9713	const floatView = new Float32Array( buffer );
9714	const uint32View = new Uint32Array( buffer );
9715
9716	const baseTable = new Uint32Array( 512 );
9717	const shiftTable = new Uint32Array( 512 );
9718
9719	for ( let i = 0; i < 256; ++ i ) {
9720
9721		const e = i - 127;
9722
9723		// very small number (0, -0)
9724
9725		if ( e < - 27 ) {
9726
9727			baseTable[ i ] = 0x0000;
9728			baseTable[ i | 0x100 ] = 0x8000;
9729			shiftTable[ i ] = 24;
9730			shiftTable[ i | 0x100 ] = 24;
9731
9732			// small number (denorm)
9733
9734		} else if ( e < - 14 ) {
9735
9736			baseTable[ i ] = 0x0400 >> ( - e - 14 );
9737			baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;
9738			shiftTable[ i ] = - e - 1;
9739			shiftTable[ i | 0x100 ] = - e - 1;
9740
9741			// normal number
9742
9743		} else if ( e <= 15 ) {
9744
9745			baseTable[ i ] = ( e + 15 ) << 10;
9746			baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;
9747			shiftTable[ i ] = 13;
9748			shiftTable[ i | 0x100 ] = 13;
9749
9750			// large number (Infinity, -Infinity)
9751
9752		} else if ( e < 128 ) {
9753
9754			baseTable[ i ] = 0x7c00;
9755			baseTable[ i | 0x100 ] = 0xfc00;
9756			shiftTable[ i ] = 24;
9757			shiftTable[ i | 0x100 ] = 24;
9758
9759			// stay (NaN, Infinity, -Infinity)
9760
9761		} else {
9762
9763			baseTable[ i ] = 0x7c00;
9764			baseTable[ i | 0x100 ] = 0xfc00;
9765			shiftTable[ i ] = 13;
9766			shiftTable[ i | 0x100 ] = 13;
9767
9768		}
9769
9770	}
9771
9772	// float16 to float32 helpers
9773
9774	const mantissaTable = new Uint32Array( 2048 );
9775	const exponentTable = new Uint32Array( 64 );
9776	const offsetTable = new Uint32Array( 64 );
9777
9778	for ( let i = 1; i < 1024; ++ i ) {
9779
9780		let m = i << 13; // zero pad mantissa bits
9781		let e = 0; // zero exponent
9782
9783		// normalized
9784		while ( ( m & 0x00800000 ) === 0 ) {
9785
9786			m <<= 1;
9787			e -= 0x00800000; // decrement exponent
9788
9789		}
9790
9791		m &= ~ 0x00800000; // clear leading 1 bit
9792		e += 0x38800000; // adjust bias
9793
9794		mantissaTable[ i ] = m | e;
9795
9796	}
9797
9798	for ( let i = 1024; i < 2048; ++ i ) {
9799
9800		mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );
9801
9802	}
9803
9804	for ( let i = 1; i < 31; ++ i ) {
9805
9806		exponentTable[ i ] = i << 23;
9807
9808	}
9809
9810	exponentTable[ 31 ] = 0x47800000;
9811	exponentTable[ 32 ] = 0x80000000;
9812
9813	for ( let i = 33; i < 63; ++ i ) {
9814
9815		exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );
9816
9817	}
9818
9819	exponentTable[ 63 ] = 0xc7800000;
9820
9821	for ( let i = 1; i < 64; ++ i ) {
9822
9823		if ( i !== 32 ) {
9824
9825			offsetTable[ i ] = 1024;
9826
9827		}
9828
9829	}
9830
9831	return {
9832		floatView: floatView,
9833		uint32View: uint32View,
9834		baseTable: baseTable,
9835		shiftTable: shiftTable,
9836		mantissaTable: mantissaTable,
9837		exponentTable: exponentTable,
9838		offsetTable: offsetTable
9839	};
9840
9841}
9842
9843// float32 to float16
9844
9845function toHalfFloat( val ) {
9846
9847	if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );
9848
9849	val = clamp( val, - 65504, 65504 );
9850
9851	_tables.floatView[ 0 ] = val;
9852	const f = _tables.uint32View[ 0 ];
9853	const e = ( f >> 23 ) & 0x1ff;
9854	return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );
9855
9856}
9857
9858// float16 to float32
9859
9860function fromHalfFloat( val ) {
9861
9862	const m = val >> 10;
9863	_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];
9864	return _tables.floatView[ 0 ];
9865
9866}
9867
9868const DataUtils = {
9869	toHalfFloat: toHalfFloat,
9870	fromHalfFloat: fromHalfFloat,
9871};
9872
9873const _vector$9 = /*@__PURE__*/ new Vector3();
9874const _vector2$1 = /*@__PURE__*/ new Vector2();
9875
9876class BufferAttribute {
9877
9878	constructor( array, itemSize, normalized = false ) {
9879
9880		if ( Array.isArray( array ) ) {
9881
9882			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
9883
9884		}
9885
9886		this.isBufferAttribute = true;
9887
9888		this.name = '';
9889
9890		this.array = array;
9891		this.itemSize = itemSize;
9892		this.count = array !== undefined ? array.length / itemSize : 0;
9893		this.normalized = normalized;
9894
9895		this.usage = StaticDrawUsage;
9896		this._updateRange = { offset: 0, count: - 1 };
9897		this.updateRanges = [];
9898		this.gpuType = FloatType;
9899
9900		this.version = 0;
9901
9902	}
9903
9904	onUploadCallback() {}
9905
9906	set needsUpdate( value ) {
9907
9908		if ( value === true ) this.version ++;
9909
9910	}
9911
9912	get updateRange() {
9913
9914		console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
9915		return this._updateRange;
9916
9917	}
9918
9919	setUsage( value ) {
9920
9921		this.usage = value;
9922
9923		return this;
9924
9925	}
9926
9927	addUpdateRange( start, count ) {
9928
9929		this.updateRanges.push( { start, count } );
9930
9931	}
9932
9933	clearUpdateRanges() {
9934
9935		this.updateRanges.length = 0;
9936
9937	}
9938
9939	copy( source ) {
9940
9941		this.name = source.name;
9942		this.array = new source.array.constructor( source.array );
vendor: 9,245 bytes, lines 9943-10509
9943		this.itemSize = source.itemSize;
9944		this.count = source.count;
9945		this.normalized = source.normalized;
9946
9947		this.usage = source.usage;
9948		this.gpuType = source.gpuType;
9949
9950		return this;
9951
9952	}
9953
9954	copyAt( index1, attribute, index2 ) {
9955
9956		index1 *= this.itemSize;
9957		index2 *= attribute.itemSize;
9958
9959		for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
9960
9961			this.array[ index1 + i ] = attribute.array[ index2 + i ];
9962
9963		}
9964
9965		return this;
9966
9967	}
9968
9969	copyArray( array ) {
9970
9971		this.array.set( array );
9972
9973		return this;
9974
9975	}
9976
9977	applyMatrix3( m ) {
9978
9979		if ( this.itemSize === 2 ) {
9980
9981			for ( let i = 0, l = this.count; i < l; i ++ ) {
9982
9983				_vector2$1.fromBufferAttribute( this, i );
9984				_vector2$1.applyMatrix3( m );
9985
9986				this.setXY( i, _vector2$1.x, _vector2$1.y );
9987
9988			}
9989
9990		} else if ( this.itemSize === 3 ) {
9991
9992			for ( let i = 0, l = this.count; i < l; i ++ ) {
9993
9994				_vector$9.fromBufferAttribute( this, i );
9995				_vector$9.applyMatrix3( m );
9996
9997				this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
9998
9999			}
10000
10001		}
10002
10003		return this;
10004
10005	}
10006
10007	applyMatrix4( m ) {
10008
10009		for ( let i = 0, l = this.count; i < l; i ++ ) {
10010
10011			_vector$9.fromBufferAttribute( this, i );
10012
10013			_vector$9.applyMatrix4( m );
10014
10015			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10016
10017		}
10018
10019		return this;
10020
10021	}
10022
10023	applyNormalMatrix( m ) {
10024
10025		for ( let i = 0, l = this.count; i < l; i ++ ) {
10026
10027			_vector$9.fromBufferAttribute( this, i );
10028
10029			_vector$9.applyNormalMatrix( m );
10030
10031			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10032
10033		}
10034
10035		return this;
10036
10037	}
10038
10039	transformDirection( m ) {
10040
10041		for ( let i = 0, l = this.count; i < l; i ++ ) {
10042
10043			_vector$9.fromBufferAttribute( this, i );
10044
10045			_vector$9.transformDirection( m );
10046
10047			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10048
10049		}
10050
10051		return this;
10052
10053	}
10054
10055	set( value, offset = 0 ) {
10056
10057		// Matching BufferAttribute constructor, do not normalize the array.
10058		this.array.set( value, offset );
10059
10060		return this;
10061
10062	}
10063
10064	getComponent( index, component ) {
10065
10066		let value = this.array[ index * this.itemSize + component ];
10067
10068		if ( this.normalized ) value = denormalize( value, this.array );
10069
10070		return value;
10071
10072	}
10073
10074	setComponent( index, component, value ) {
10075
10076		if ( this.normalized ) value = normalize( value, this.array );
10077
10078		this.array[ index * this.itemSize + component ] = value;
10079
10080		return this;
10081
10082	}
10083
10084	getX( index ) {
10085
10086		let x = this.array[ index * this.itemSize ];
10087
10088		if ( this.normalized ) x = denormalize( x, this.array );
10089
10090		return x;
10091
10092	}
10093
10094	setX( index, x ) {
10095
10096		if ( this.normalized ) x = normalize( x, this.array );
10097
10098		this.array[ index * this.itemSize ] = x;
10099
10100		return this;
10101
10102	}
10103
10104	getY( index ) {
10105
10106		let y = this.array[ index * this.itemSize + 1 ];
10107
10108		if ( this.normalized ) y = denormalize( y, this.array );
10109
10110		return y;
10111
10112	}
10113
10114	setY( index, y ) {
10115
10116		if ( this.normalized ) y = normalize( y, this.array );
10117
10118		this.array[ index * this.itemSize + 1 ] = y;
10119
10120		return this;
10121
10122	}
10123
10124	getZ( index ) {
10125
10126		let z = this.array[ index * this.itemSize + 2 ];
10127
10128		if ( this.normalized ) z = denormalize( z, this.array );
10129
10130		return z;
10131
10132	}
10133
10134	setZ( index, z ) {
10135
10136		if ( this.normalized ) z = normalize( z, this.array );
10137
10138		this.array[ index * this.itemSize + 2 ] = z;
10139
10140		return this;
10141
10142	}
10143
10144	getW( index ) {
10145
10146		let w = this.array[ index * this.itemSize + 3 ];
10147
10148		if ( this.normalized ) w = denormalize( w, this.array );
10149
10150		return w;
10151
10152	}
10153
10154	setW( index, w ) {
10155
10156		if ( this.normalized ) w = normalize( w, this.array );
10157
10158		this.array[ index * this.itemSize + 3 ] = w;
10159
10160		return this;
10161
10162	}
10163
10164	setXY( index, x, y ) {
10165
10166		index *= this.itemSize;
10167
10168		if ( this.normalized ) {
10169
10170			x = normalize( x, this.array );
10171			y = normalize( y, this.array );
10172
10173		}
10174
10175		this.array[ index + 0 ] = x;
10176		this.array[ index + 1 ] = y;
10177
10178		return this;
10179
10180	}
10181
10182	setXYZ( index, x, y, z ) {
10183
10184		index *= this.itemSize;
10185
10186		if ( this.normalized ) {
10187
10188			x = normalize( x, this.array );
10189			y = normalize( y, this.array );
10190			z = normalize( z, this.array );
10191
10192		}
10193
10194		this.array[ index + 0 ] = x;
10195		this.array[ index + 1 ] = y;
10196		this.array[ index + 2 ] = z;
10197
10198		return this;
10199
10200	}
10201
10202	setXYZW( index, x, y, z, w ) {
10203
10204		index *= this.itemSize;
10205
10206		if ( this.normalized ) {
10207
10208			x = normalize( x, this.array );
10209			y = normalize( y, this.array );
10210			z = normalize( z, this.array );
10211			w = normalize( w, this.array );
10212
10213		}
10214
10215		this.array[ index + 0 ] = x;
10216		this.array[ index + 1 ] = y;
10217		this.array[ index + 2 ] = z;
10218		this.array[ index + 3 ] = w;
10219
10220		return this;
10221
10222	}
10223
10224	onUpload( callback ) {
10225
10226		this.onUploadCallback = callback;
10227
10228		return this;
10229
10230	}
10231
10232	clone() {
10233
10234		return new this.constructor( this.array, this.itemSize ).copy( this );
10235
10236	}
10237
10238	toJSON() {
10239
10240		const data = {
10241			itemSize: this.itemSize,
10242			type: this.array.constructor.name,
10243			array: Array.from( this.array ),
10244			normalized: this.normalized
10245		};
10246
10247		if ( this.name !== '' ) data.name = this.name;
10248		if ( this.usage !== StaticDrawUsage ) data.usage = this.usage;
10249
10250		return data;
10251
10252	}
10253
10254}
10255
10256//
10257
10258class Int8BufferAttribute extends BufferAttribute {
10259
10260	constructor( array, itemSize, normalized ) {
10261
10262		super( new Int8Array( array ), itemSize, normalized );
10263
10264	}
10265
10266}
10267
10268class Uint8BufferAttribute extends BufferAttribute {
10269
10270	constructor( array, itemSize, normalized ) {
10271
10272		super( new Uint8Array( array ), itemSize, normalized );
10273
10274	}
10275
10276}
10277
10278class Uint8ClampedBufferAttribute extends BufferAttribute {
10279
10280	constructor( array, itemSize, normalized ) {
10281
10282		super( new Uint8ClampedArray( array ), itemSize, normalized );
10283
10284	}
10285
10286}
10287
10288class Int16BufferAttribute extends BufferAttribute {
10289
10290	constructor( array, itemSize, normalized ) {
10291
10292		super( new Int16Array( array ), itemSize, normalized );
10293
10294	}
10295
10296}
10297
10298class Uint16BufferAttribute extends BufferAttribute {
10299
10300	constructor( array, itemSize, normalized ) {
10301
10302		super( new Uint16Array( array ), itemSize, normalized );
10303
10304	}
10305
10306}
10307
10308class Int32BufferAttribute extends BufferAttribute {
10309
10310	constructor( array, itemSize, normalized ) {
10311
10312		super( new Int32Array( array ), itemSize, normalized );
10313
10314	}
10315
10316}
10317
10318class Uint32BufferAttribute extends BufferAttribute {
10319
10320	constructor( array, itemSize, normalized ) {
10321
10322		super( new Uint32Array( array ), itemSize, normalized );
10323
10324	}
10325
10326}
10327
10328class Float16BufferAttribute extends BufferAttribute {
10329
10330	constructor( array, itemSize, normalized ) {
10331
10332		super( new Uint16Array( array ), itemSize, normalized );
10333
10334		this.isFloat16BufferAttribute = true;
10335
10336	}
10337
10338	getX( index ) {
10339
10340		let x = fromHalfFloat( this.array[ index * this.itemSize ] );
10341
10342		if ( this.normalized ) x = denormalize( x, this.array );
10343
10344		return x;
10345
10346	}
10347
10348	setX( index, x ) {
10349
10350		if ( this.normalized ) x = normalize( x, this.array );
10351
10352		this.array[ index * this.itemSize ] = toHalfFloat( x );
10353
10354		return this;
10355
10356	}
10357
10358	getY( index ) {
10359
10360		let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );
10361
10362		if ( this.normalized ) y = denormalize( y, this.array );
10363
10364		return y;
10365
10366	}
10367
10368	setY( index, y ) {
10369
10370		if ( this.normalized ) y = normalize( y, this.array );
10371
10372		this.array[ index * this.itemSize + 1 ] = toHalfFloat( y );
10373
10374		return this;
10375
10376	}
10377
10378	getZ( index ) {
10379
10380		let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );
10381
10382		if ( this.normalized ) z = denormalize( z, this.array );
10383
10384		return z;
10385
10386	}
10387
10388	setZ( index, z ) {
10389
10390		if ( this.normalized ) z = normalize( z, this.array );
10391
10392		this.array[ index * this.itemSize + 2 ] = toHalfFloat( z );
10393
10394		return this;
10395
10396	}
10397
10398	getW( index ) {
10399
10400		let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );
10401
10402		if ( this.normalized ) w = denormalize( w, this.array );
10403
10404		return w;
10405
10406	}
10407
10408	setW( index, w ) {
10409
10410		if ( this.normalized ) w = normalize( w, this.array );
10411
10412		this.array[ index * this.itemSize + 3 ] = toHalfFloat( w );
10413
10414		return this;
10415
10416	}
10417
10418	setXY( index, x, y ) {
10419
10420		index *= this.itemSize;
10421
10422		if ( this.normalized ) {
10423
10424			x = normalize( x, this.array );
10425			y = normalize( y, this.array );
10426
10427		}
10428
10429		this.array[ index + 0 ] = toHalfFloat( x );
10430		this.array[ index + 1 ] = toHalfFloat( y );
10431
10432		return this;
10433
10434	}
10435
10436	setXYZ( index, x, y, z ) {
10437
10438		index *= this.itemSize;
10439
10440		if ( this.normalized ) {
10441
10442			x = normalize( x, this.array );
10443			y = normalize( y, this.array );
10444			z = normalize( z, this.array );
10445
10446		}
10447
10448		this.array[ index + 0 ] = toHalfFloat( x );
10449		this.array[ index + 1 ] = toHalfFloat( y );
10450		this.array[ index + 2 ] = toHalfFloat( z );
10451
10452		return this;
10453
10454	}
10455
10456	setXYZW( index, x, y, z, w ) {
10457
10458		index *= this.itemSize;
10459
10460		if ( this.normalized ) {
10461
10462			x = normalize( x, this.array );
10463			y = normalize( y, this.array );
10464			z = normalize( z, this.array );
10465			w = normalize( w, this.array );
10466
10467		}
10468
10469		this.array[ index + 0 ] = toHalfFloat( x );
10470		this.array[ index + 1 ] = toHalfFloat( y );
10471		this.array[ index + 2 ] = toHalfFloat( z );
10472		this.array[ index + 3 ] = toHalfFloat( w );
10473
10474		return this;
10475
10476	}
10477
10478}
10479
10480
10481class Float32BufferAttribute extends BufferAttribute {
10482
10483	constructor( array, itemSize, normalized ) {
10484
10485		super( new Float32Array( array ), itemSize, normalized );
10486
10487	}
10488
10489}
10490
10491class Float64BufferAttribute extends BufferAttribute {
10492
10493	constructor( array, itemSize, normalized ) {
10494
10495		super( new Float64Array( array ), itemSize, normalized );
10496
10497	}
10498
10499}
10500
10501let _id$2 = 0;
10502
10503const _m1 = /*@__PURE__*/ new Matrix4();
10504const _obj = /*@__PURE__*/ new Object3D();
10505const _offset = /*@__PURE__*/ new Vector3();
10506const _box$2 = /*@__PURE__*/ new Box3();
10507const _boxMorphTargets = /*@__PURE__*/ new Box3();
10508const _vector$8 = /*@__PURE__*/ new Vector3();
10509
vendor: 5,687 bytes, lines 10510-10861
10510class BufferGeometry extends EventDispatcher {
10511
10512	constructor() {
10513
10514		super();
10515
10516		this.isBufferGeometry = true;
10517
10518		Object.defineProperty( this, 'id', { value: _id$2 ++ } );
10519
10520		this.uuid = generateUUID();
10521
10522		this.name = '';
10523		this.type = 'BufferGeometry';
10524
10525		this.index = null;
10526		this.attributes = {};
10527
10528		this.morphAttributes = {};
10529		this.morphTargetsRelative = false;
10530
10531		this.groups = [];
10532
10533		this.boundingBox = null;
10534		this.boundingSphere = null;
10535
10536		this.drawRange = { start: 0, count: Infinity };
10537
10538		this.userData = {};
10539
10540	}
10541
10542	getIndex() {
10543
10544		return this.index;
10545
10546	}
10547
10548	setIndex( index ) {
10549
10550		if ( Array.isArray( index ) ) {
10551
10552			this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
10553
10554		} else {
10555
10556			this.index = index;
10557
10558		}
10559
10560		return this;
10561
10562	}
10563
10564	getAttribute( name ) {
10565
10566		return this.attributes[ name ];
10567
10568	}
10569
10570	setAttribute( name, attribute ) {
10571
10572		this.attributes[ name ] = attribute;
10573
10574		return this;
10575
10576	}
10577
10578	deleteAttribute( name ) {
10579
10580		delete this.attributes[ name ];
10581
10582		return this;
10583
10584	}
10585
10586	hasAttribute( name ) {
10587
10588		return this.attributes[ name ] !== undefined;
10589
10590	}
10591
10592	addGroup( start, count, materialIndex = 0 ) {
10593
10594		this.groups.push( {
10595
10596			start: start,
10597			count: count,
10598			materialIndex: materialIndex
10599
10600		} );
10601
10602	}
10603
10604	clearGroups() {
10605
10606		this.groups = [];
10607
10608	}
10609
10610	setDrawRange( start, count ) {
10611
10612		this.drawRange.start = start;
10613		this.drawRange.count = count;
10614
10615	}
10616
10617	applyMatrix4( matrix ) {
10618
10619		const position = this.attributes.position;
10620
10621		if ( position !== undefined ) {
10622
10623			position.applyMatrix4( matrix );
10624
10625			position.needsUpdate = true;
10626
10627		}
10628
10629		const normal = this.attributes.normal;
10630
10631		if ( normal !== undefined ) {
10632
10633			const normalMatrix = new Matrix3().getNormalMatrix( matrix );
10634
10635			normal.applyNormalMatrix( normalMatrix );
10636
10637			normal.needsUpdate = true;
10638
10639		}
10640
10641		const tangent = this.attributes.tangent;
10642
10643		if ( tangent !== undefined ) {
10644
10645			tangent.transformDirection( matrix );
10646
10647			tangent.needsUpdate = true;
10648
10649		}
10650
10651		if ( this.boundingBox !== null ) {
10652
10653			this.computeBoundingBox();
10654
10655		}
10656
10657		if ( this.boundingSphere !== null ) {
10658
10659			this.computeBoundingSphere();
10660
10661		}
10662
10663		return this;
10664
10665	}
10666
10667	applyQuaternion( q ) {
10668
10669		_m1.makeRotationFromQuaternion( q );
10670
10671		this.applyMatrix4( _m1 );
10672
10673		return this;
10674
10675	}
10676
10677	rotateX( angle ) {
10678
10679		// rotate geometry around world x-axis
10680
10681		_m1.makeRotationX( angle );
10682
10683		this.applyMatrix4( _m1 );
10684
10685		return this;
10686
10687	}
10688
10689	rotateY( angle ) {
10690
10691		// rotate geometry around world y-axis
10692
10693		_m1.makeRotationY( angle );
10694
10695		this.applyMatrix4( _m1 );
10696
10697		return this;
10698
10699	}
10700
10701	rotateZ( angle ) {
10702
10703		// rotate geometry around world z-axis
10704
10705		_m1.makeRotationZ( angle );
10706
10707		this.applyMatrix4( _m1 );
10708
10709		return this;
10710
10711	}
10712
10713	translate( x, y, z ) {
10714
10715		// translate geometry
10716
10717		_m1.makeTranslation( x, y, z );
10718
10719		this.applyMatrix4( _m1 );
10720
10721		return this;
10722
10723	}
10724
10725	scale( x, y, z ) {
10726
10727		// scale geometry
10728
10729		_m1.makeScale( x, y, z );
10730
10731		this.applyMatrix4( _m1 );
10732
10733		return this;
10734
10735	}
10736
10737	lookAt( vector ) {
10738
10739		_obj.lookAt( vector );
10740
10741		_obj.updateMatrix();
10742
10743		this.applyMatrix4( _obj.matrix );
10744
10745		return this;
10746
10747	}
10748
10749	center() {
10750
10751		this.computeBoundingBox();
10752
10753		this.boundingBox.getCenter( _offset ).negate();
10754
10755		this.translate( _offset.x, _offset.y, _offset.z );
10756
10757		return this;
10758
10759	}
10760
10761	setFromPoints( points ) {
10762
10763		const position = [];
10764
10765		for ( let i = 0, l = points.length; i < l; i ++ ) {
10766
10767			const point = points[ i ];
10768			position.push( point.x, point.y, point.z || 0 );
10769
10770		}
10771
10772		this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
10773
10774		return this;
10775
10776	}
10777
10778	computeBoundingBox() {
10779
10780		if ( this.boundingBox === null ) {
10781
10782			this.boundingBox = new Box3();
10783
10784		}
10785
10786		const position = this.attributes.position;
10787		const morphAttributesPosition = this.morphAttributes.position;
10788
10789		if ( position && position.isGLBufferAttribute ) {
10790
10791			console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
10792
10793			this.boundingBox.set(
10794				new Vector3( - Infinity, - Infinity, - Infinity ),
10795				new Vector3( + Infinity, + Infinity, + Infinity )
10796			);
10797
10798			return;
10799
10800		}
10801
10802		if ( position !== undefined ) {
10803
10804			this.boundingBox.setFromBufferAttribute( position );
10805
10806			// process morph attributes if present
10807
10808			if ( morphAttributesPosition ) {
10809
10810				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10811
10812					const morphAttribute = morphAttributesPosition[ i ];
10813					_box$2.setFromBufferAttribute( morphAttribute );
10814
10815					if ( this.morphTargetsRelative ) {
10816
10817						_vector$8.addVectors( this.boundingBox.min, _box$2.min );
10818						this.boundingBox.expandByPoint( _vector$8 );
10819
10820						_vector$8.addVectors( this.boundingBox.max, _box$2.max );
10821						this.boundingBox.expandByPoint( _vector$8 );
10822
10823					} else {
10824
10825						this.boundingBox.expandByPoint( _box$2.min );
10826						this.boundingBox.expandByPoint( _box$2.max );
10827
10828					}
10829
10830				}
10831
10832			}
10833
10834		} else {
10835
10836			this.boundingBox.makeEmpty();
10837
10838		}
10839
10840		if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
10841
10842			console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
10843
10844		}
10845
10846	}
10847
10848	computeBoundingSphere() {
10849
10850		if ( this.boundingSphere === null ) {
10851
10852			this.boundingSphere = new Sphere();
10853
10854		}
10855
10856		const position = this.attributes.position;
10857		const morphAttributesPosition = this.morphAttributes.position;
10858
10859		if ( position && position.isGLBufferAttribute ) {
10860
10861			console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "fal
vendor: 5,692 bytes, lines 10861-11117
10861se".', this );
10862
10863			this.boundingSphere.set( new Vector3(), Infinity );
10864
10865			return;
10866
10867		}
10868
10869		if ( position ) {
10870
10871			// first, find the center of the bounding sphere
10872
10873			const center = this.boundingSphere.center;
10874
10875			_box$2.setFromBufferAttribute( position );
10876
10877			// process morph attributes if present
10878
10879			if ( morphAttributesPosition ) {
10880
10881				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10882
10883					const morphAttribute = morphAttributesPosition[ i ];
10884					_boxMorphTargets.setFromBufferAttribute( morphAttribute );
10885
10886					if ( this.morphTargetsRelative ) {
10887
10888						_vector$8.addVectors( _box$2.min, _boxMorphTargets.min );
10889						_box$2.expandByPoint( _vector$8 );
10890
10891						_vector$8.addVectors( _box$2.max, _boxMorphTargets.max );
10892						_box$2.expandByPoint( _vector$8 );
10893
10894					} else {
10895
10896						_box$2.expandByPoint( _boxMorphTargets.min );
10897						_box$2.expandByPoint( _boxMorphTargets.max );
10898
10899					}
10900
10901				}
10902
10903			}
10904
10905			_box$2.getCenter( center );
10906
10907			// second, try to find a boundingSphere with a radius smaller than the
10908			// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
10909
10910			let maxRadiusSq = 0;
10911
10912			for ( let i = 0, il = position.count; i < il; i ++ ) {
10913
10914				_vector$8.fromBufferAttribute( position, i );
10915
10916				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10917
10918			}
10919
10920			// process morph attributes if present
10921
10922			if ( morphAttributesPosition ) {
10923
10924				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10925
10926					const morphAttribute = morphAttributesPosition[ i ];
10927					const morphTargetsRelative = this.morphTargetsRelative;
10928
10929					for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
10930
10931						_vector$8.fromBufferAttribute( morphAttribute, j );
10932
10933						if ( morphTargetsRelative ) {
10934
10935							_offset.fromBufferAttribute( position, j );
10936							_vector$8.add( _offset );
10937
10938						}
10939
10940						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10941
10942					}
10943
10944				}
10945
10946			}
10947
10948			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
10949
10950			if ( isNaN( this.boundingSphere.radius ) ) {
10951
10952				console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
10953
10954			}
10955
10956		}
10957
10958	}
10959
10960	computeTangents() {
10961
10962		const index = this.index;
10963		const attributes = this.attributes;
10964
10965		// based on http://www.terathon.com/code/tangent.html
10966		// (per vertex tangents)
10967
10968		if ( index === null ||
10969			 attributes.position === undefined ||
10970			 attributes.normal === undefined ||
10971			 attributes.uv === undefined ) {
10972
10973			console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
10974			return;
10975
10976		}
10977
10978		const indices = index.array;
10979		const positions = attributes.position.array;
10980		const normals = attributes.normal.array;
10981		const uvs = attributes.uv.array;
10982
10983		const nVertices = positions.length / 3;
10984
10985		if ( this.hasAttribute( 'tangent' ) === false ) {
10986
10987			this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
10988
10989		}
10990
10991		const tangents = this.getAttribute( 'tangent' ).array;
10992
10993		const tan1 = [], tan2 = [];
10994
10995		for ( let i = 0; i < nVertices; i ++ ) {
10996
10997			tan1[ i ] = new Vector3();
10998			tan2[ i ] = new Vector3();
10999
11000		}
11001
11002		const vA = new Vector3(),
11003			vB = new Vector3(),
11004			vC = new Vector3(),
11005
11006			uvA = new Vector2(),
11007			uvB = new Vector2(),
11008			uvC = new Vector2(),
11009
11010			sdir = new Vector3(),
11011			tdir = new Vector3();
11012
11013		function handleTriangle( a, b, c ) {
11014
11015			vA.fromArray( positions, a * 3 );
11016			vB.fromArray( positions, b * 3 );
11017			vC.fromArray( positions, c * 3 );
11018
11019			uvA.fromArray( uvs, a * 2 );
11020			uvB.fromArray( uvs, b * 2 );
11021			uvC.fromArray( uvs, c * 2 );
11022
11023			vB.sub( vA );
11024			vC.sub( vA );
11025
11026			uvB.sub( uvA );
11027			uvC.sub( uvA );
11028
11029			const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
11030
11031			// silently ignore degenerate uv triangles having coincident or colinear vertices
11032
11033			if ( ! isFinite( r ) ) return;
11034
11035			sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
11036			tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
11037
11038			tan1[ a ].add( sdir );
11039			tan1[ b ].add( sdir );
11040			tan1[ c ].add( sdir );
11041
11042			tan2[ a ].add( tdir );
11043			tan2[ b ].add( tdir );
11044			tan2[ c ].add( tdir );
11045
11046		}
11047
11048		let groups = this.groups;
11049
11050		if ( groups.length === 0 ) {
11051
11052			groups = [ {
11053				start: 0,
11054				count: indices.length
11055			} ];
11056
11057		}
11058
11059		for ( let i = 0, il = groups.length; i < il; ++ i ) {
11060
11061			const group = groups[ i ];
11062
11063			const start = group.start;
11064			const count = group.count;
11065
11066			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11067
11068				handleTriangle(
11069					indices[ j + 0 ],
11070					indices[ j + 1 ],
11071					indices[ j + 2 ]
11072				);
11073
11074			}
11075
11076		}
11077
11078		const tmp = new Vector3(), tmp2 = new Vector3();
11079		const n = new Vector3(), n2 = new Vector3();
11080
11081		function handleVertex( v ) {
11082
11083			n.fromArray( normals, v * 3 );
11084			n2.copy( n );
11085
11086			const t = tan1[ v ];
11087
11088			// Gram-Schmidt orthogonalize
11089
11090			tmp.copy( t );
11091			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
11092
11093			// Calculate handedness
11094
11095			tmp2.crossVectors( n2, t );
11096			const test = tmp2.dot( tan2[ v ] );
11097			const w = ( test < 0.0 ) ? - 1.0 : 1.0;
11098
11099			tangents[ v * 4 ] = tmp.x;
11100			tangents[ v * 4 + 1 ] = tmp.y;
11101			tangents[ v * 4 + 2 ] = tmp.z;
11102			tangents[ v * 4 + 3 ] = w;
11103
11104		}
11105
11106		for ( let i = 0, il = groups.length; i < il; ++ i ) {
11107
11108			const group = groups[ i ];
11109
11110			const start = group.start;
11111			const count = group.count;
11112
11113			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11114
11115				handleVertex( indices[ j + 0 ] );
11116				handleVertex( indices[ j + 1 ] );
11117				handleVertex( indices[ j + 2 ]
vendor: 18,013 bytes, lines 11117-11945
11117 );
11118
11119			}
11120
11121		}
11122
11123	}
11124
11125	computeVertexNormals() {
11126
11127		const index = this.index;
11128		const positionAttribute = this.getAttribute( 'position' );
11129
11130		if ( positionAttribute !== undefined ) {
11131
11132			let normalAttribute = this.getAttribute( 'normal' );
11133
11134			if ( normalAttribute === undefined ) {
11135
11136				normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
11137				this.setAttribute( 'normal', normalAttribute );
11138
11139			} else {
11140
11141				// reset existing normals to zero
11142
11143				for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
11144
11145					normalAttribute.setXYZ( i, 0, 0, 0 );
11146
11147				}
11148
11149			}
11150
11151			const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
11152			const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
11153			const cb = new Vector3(), ab = new Vector3();
11154
11155			// indexed elements
11156
11157			if ( index ) {
11158
11159				for ( let i = 0, il = index.count; i < il; i += 3 ) {
11160
11161					const vA = index.getX( i + 0 );
11162					const vB = index.getX( i + 1 );
11163					const vC = index.getX( i + 2 );
11164
11165					pA.fromBufferAttribute( positionAttribute, vA );
11166					pB.fromBufferAttribute( positionAttribute, vB );
11167					pC.fromBufferAttribute( positionAttribute, vC );
11168
11169					cb.subVectors( pC, pB );
11170					ab.subVectors( pA, pB );
11171					cb.cross( ab );
11172
11173					nA.fromBufferAttribute( normalAttribute, vA );
11174					nB.fromBufferAttribute( normalAttribute, vB );
11175					nC.fromBufferAttribute( normalAttribute, vC );
11176
11177					nA.add( cb );
11178					nB.add( cb );
11179					nC.add( cb );
11180
11181					normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
11182					normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
11183					normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
11184
11185				}
11186
11187			} else {
11188
11189				// non-indexed elements (unconnected triangle soup)
11190
11191				for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
11192
11193					pA.fromBufferAttribute( positionAttribute, i + 0 );
11194					pB.fromBufferAttribute( positionAttribute, i + 1 );
11195					pC.fromBufferAttribute( positionAttribute, i + 2 );
11196
11197					cb.subVectors( pC, pB );
11198					ab.subVectors( pA, pB );
11199					cb.cross( ab );
11200
11201					normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
11202					normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
11203					normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
11204
11205				}
11206
11207			}
11208
11209			this.normalizeNormals();
11210
11211			normalAttribute.needsUpdate = true;
11212
11213		}
11214
11215	}
11216
11217	normalizeNormals() {
11218
11219		const normals = this.attributes.normal;
11220
11221		for ( let i = 0, il = normals.count; i < il; i ++ ) {
11222
11223			_vector$8.fromBufferAttribute( normals, i );
11224
11225			_vector$8.normalize();
11226
11227			normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );
11228
11229		}
11230
11231	}
11232
11233	toNonIndexed() {
11234
11235		function convertBufferAttribute( attribute, indices ) {
11236
11237			const array = attribute.array;
11238			const itemSize = attribute.itemSize;
11239			const normalized = attribute.normalized;
11240
11241			const array2 = new array.constructor( indices.length * itemSize );
11242
11243			let index = 0, index2 = 0;
11244
11245			for ( let i = 0, l = indices.length; i < l; i ++ ) {
11246
11247				if ( attribute.isInterleavedBufferAttribute ) {
11248
11249					index = indices[ i ] * attribute.data.stride + attribute.offset;
11250
11251				} else {
11252
11253					index = indices[ i ] * itemSize;
11254
11255				}
11256
11257				for ( let j = 0; j < itemSize; j ++ ) {
11258
11259					array2[ index2 ++ ] = array[ index ++ ];
11260
11261				}
11262
11263			}
11264
11265			return new BufferAttribute( array2, itemSize, normalized );
11266
11267		}
11268
11269		//
11270
11271		if ( this.index === null ) {
11272
11273			console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
11274			return this;
11275
11276		}
11277
11278		const geometry2 = new BufferGeometry();
11279
11280		const indices = this.index.array;
11281		const attributes = this.attributes;
11282
11283		// attributes
11284
11285		for ( const name in attributes ) {
11286
11287			const attribute = attributes[ name ];
11288
11289			const newAttribute = convertBufferAttribute( attribute, indices );
11290
11291			geometry2.setAttribute( name, newAttribute );
11292
11293		}
11294
11295		// morph attributes
11296
11297		const morphAttributes = this.morphAttributes;
11298
11299		for ( const name in morphAttributes ) {
11300
11301			const morphArray = [];
11302			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11303
11304			for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
11305
11306				const attribute = morphAttribute[ i ];
11307
11308				const newAttribute = convertBufferAttribute( attribute, indices );
11309
11310				morphArray.push( newAttribute );
11311
11312			}
11313
11314			geometry2.morphAttributes[ name ] = morphArray;
11315
11316		}
11317
11318		geometry2.morphTargetsRelative = this.morphTargetsRelative;
11319
11320		// groups
11321
11322		const groups = this.groups;
11323
11324		for ( let i = 0, l = groups.length; i < l; i ++ ) {
11325
11326			const group = groups[ i ];
11327			geometry2.addGroup( group.start, group.count, group.materialIndex );
11328
11329		}
11330
11331		return geometry2;
11332
11333	}
11334
11335	toJSON() {
11336
11337		const data = {
11338			metadata: {
11339				version: 4.6,
11340				type: 'BufferGeometry',
11341				generator: 'BufferGeometry.toJSON'
11342			}
11343		};
11344
11345		// standard BufferGeometry serialization
11346
11347		data.uuid = this.uuid;
11348		data.type = this.type;
11349		if ( this.name !== '' ) data.name = this.name;
11350		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
11351
11352		if ( this.parameters !== undefined ) {
11353
11354			const parameters = this.parameters;
11355
11356			for ( const key in parameters ) {
11357
11358				if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
11359
11360			}
11361
11362			return data;
11363
11364		}
11365
11366		// for simplicity the code assumes attributes are not shared across geometries, see #15811
11367
11368		data.data = { attributes: {} };
11369
11370		const index = this.index;
11371
11372		if ( index !== null ) {
11373
11374			data.data.index = {
11375				type: index.array.constructor.name,
11376				array: Array.prototype.slice.call( index.array )
11377			};
11378
11379		}
11380
11381		const attributes = this.attributes;
11382
11383		for ( const key in attributes ) {
11384
11385			const attribute = attributes[ key ];
11386
11387			data.data.attributes[ key ] = attribute.toJSON( data.data );
11388
11389		}
11390
11391		const morphAttributes = {};
11392		let hasMorphAttributes = false;
11393
11394		for ( const key in this.morphAttributes ) {
11395
11396			const attributeArray = this.morphAttributes[ key ];
11397
11398			const array = [];
11399
11400			for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
11401
11402				const attribute = attributeArray[ i ];
11403
11404				array.push( attribute.toJSON( data.data ) );
11405
11406			}
11407
11408			if ( array.length > 0 ) {
11409
11410				morphAttributes[ key ] = array;
11411
11412				hasMorphAttributes = true;
11413
11414			}
11415
11416		}
11417
11418		if ( hasMorphAttributes ) {
11419
11420			data.data.morphAttributes = morphAttributes;
11421			data.data.morphTargetsRelative = this.morphTargetsRelative;
11422
11423		}
11424
11425		const groups = this.groups;
11426
11427		if ( groups.length > 0 ) {
11428
11429			data.data.groups = JSON.parse( JSON.stringify( groups ) );
11430
11431		}
11432
11433		const boundingSphere = this.boundingSphere;
11434
11435		if ( boundingSphere !== null ) {
11436
11437			data.data.boundingSphere = {
11438				center: boundingSphere.center.toArray(),
11439				radius: boundingSphere.radius
11440			};
11441
11442		}
11443
11444		return data;
11445
11446	}
11447
11448	clone() {
11449
11450		return new this.constructor().copy( this );
11451
11452	}
11453
11454	copy( source ) {
11455
11456		// reset
11457
11458		this.index = null;
11459		this.attributes = {};
11460		this.morphAttributes = {};
11461		this.groups = [];
11462		this.boundingBox = null;
11463		this.boundingSphere = null;
11464
11465		// used for storing cloned, shared data
11466
11467		const data = {};
11468
11469		// name
11470
11471		this.name = source.name;
11472
11473		// index
11474
11475		const index = source.index;
11476
11477		if ( index !== null ) {
11478
11479			this.setIndex( index.clone( data ) );
11480
11481		}
11482
11483		// attributes
11484
11485		const attributes = source.attributes;
11486
11487		for ( const name in attributes ) {
11488
11489			const attribute = attributes[ name ];
11490			this.setAttribute( name, attribute.clone( data ) );
11491
11492		}
11493
11494		// morph attributes
11495
11496		const morphAttributes = source.morphAttributes;
11497
11498		for ( const name in morphAttributes ) {
11499
11500			const array = [];
11501			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11502
11503			for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
11504
11505				array.push( morphAttribute[ i ].clone( data ) );
11506
11507			}
11508
11509			this.morphAttributes[ name ] = array;
11510
11511		}
11512
11513		this.morphTargetsRelative = source.morphTargetsRelative;
11514
11515		// groups
11516
11517		const groups = source.groups;
11518
11519		for ( let i = 0, l = groups.length; i < l; i ++ ) {
11520
11521			const group = groups[ i ];
11522			this.addGroup( group.start, group.count, group.materialIndex );
11523
11524		}
11525
11526		// bounding box
11527
11528		const boundingBox = source.boundingBox;
11529
11530		if ( boundingBox !== null ) {
11531
11532			this.boundingBox = boundingBox.clone();
11533
11534		}
11535
11536		// bounding sphere
11537
11538		const boundingSphere = source.boundingSphere;
11539
11540		if ( boundingSphere !== null ) {
11541
11542			this.boundingSphere = boundingSphere.clone();
11543
11544		}
11545
11546		// draw range
11547
11548		this.drawRange.start = source.drawRange.start;
11549		this.drawRange.count = source.drawRange.count;
11550
11551		// user data
11552
11553		this.userData = source.userData;
11554
11555		return this;
11556
11557	}
11558
11559	dispose() {
11560
11561		this.dispatchEvent( { type: 'dispose' } );
11562
11563	}
11564
11565}
11566
11567const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();
11568const _ray$3 = /*@__PURE__*/ new Ray();
11569const _sphere$6 = /*@__PURE__*/ new Sphere();
11570const _sphereHitAt = /*@__PURE__*/ new Vector3();
11571
11572const _vA$1 = /*@__PURE__*/ new Vector3();
11573const _vB$1 = /*@__PURE__*/ new Vector3();
11574const _vC$1 = /*@__PURE__*/ new Vector3();
11575
11576const _tempA = /*@__PURE__*/ new Vector3();
11577const _morphA = /*@__PURE__*/ new Vector3();
11578
11579const _uvA$1 = /*@__PURE__*/ new Vector2();
11580const _uvB$1 = /*@__PURE__*/ new Vector2();
11581const _uvC$1 = /*@__PURE__*/ new Vector2();
11582
11583const _normalA = /*@__PURE__*/ new Vector3();
11584const _normalB = /*@__PURE__*/ new Vector3();
11585const _normalC = /*@__PURE__*/ new Vector3();
11586
11587const _intersectionPoint = /*@__PURE__*/ new Vector3();
11588const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
11589
11590class Mesh extends Object3D {
11591
11592	constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
11593
11594		super();
11595
11596		this.isMesh = true;
11597
11598		this.type = 'Mesh';
11599
11600		this.geometry = geometry;
11601		this.material = material;
11602
11603		this.updateMorphTargets();
11604
11605	}
11606
11607	copy( source, recursive ) {
11608
11609		super.copy( source, recursive );
11610
11611		if ( source.morphTargetInfluences !== undefined ) {
11612
11613			this.morphTargetInfluences = source.morphTargetInfluences.slice();
11614
11615		}
11616
11617		if ( source.morphTargetDictionary !== undefined ) {
11618
11619			this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
11620
11621		}
11622
11623		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
11624		this.geometry = source.geometry;
11625
11626		return this;
11627
11628	}
11629
11630	updateMorphTargets() {
11631
11632		const geometry = this.geometry;
11633
11634		const morphAttributes = geometry.morphAttributes;
11635		const keys = Object.keys( morphAttributes );
11636
11637		if ( keys.length > 0 ) {
11638
11639			const morphAttribute = morphAttributes[ keys[ 0 ] ];
11640
11641			if ( morphAttribute !== undefined ) {
11642
11643				this.morphTargetInfluences = [];
11644				this.morphTargetDictionary = {};
11645
11646				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
11647
11648					const name = morphAttribute[ m ].name || String( m );
11649
11650					this.morphTargetInfluences.push( 0 );
11651					this.morphTargetDictionary[ name ] = m;
11652
11653				}
11654
11655			}
11656
11657		}
11658
11659	}
11660
11661	getVertexPosition( index, target ) {
11662
11663		const geometry = this.geometry;
11664		const position = geometry.attributes.position;
11665		const morphPosition = geometry.morphAttributes.position;
11666		const morphTargetsRelative = geometry.morphTargetsRelative;
11667
11668		target.fromBufferAttribute( position, index );
11669
11670		const morphInfluences = this.morphTargetInfluences;
11671
11672		if ( morphPosition && morphInfluences ) {
11673
11674			_morphA.set( 0, 0, 0 );
11675
11676			for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
11677
11678				const influence = morphInfluences[ i ];
11679				const morphAttribute = morphPosition[ i ];
11680
11681				if ( influence === 0 ) continue;
11682
11683				_tempA.fromBufferAttribute( morphAttribute, index );
11684
11685				if ( morphTargetsRelative ) {
11686
11687					_morphA.addScaledVector( _tempA, influence );
11688
11689				} else {
11690
11691					_morphA.addScaledVector( _tempA.sub( target ), influence );
11692
11693				}
11694
11695			}
11696
11697			target.add( _morphA );
11698
11699		}
11700
11701		return target;
11702
11703	}
11704
11705	raycast( raycaster, intersects ) {
11706
11707		const geometry = this.geometry;
11708		const material = this.material;
11709		const matrixWorld = this.matrixWorld;
11710
11711		if ( material === undefined ) return;
11712
11713		// test with bounding sphere in world space
11714
11715		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
11716
11717		_sphere$6.copy( geometry.boundingSphere );
11718		_sphere$6.applyMatrix4( matrixWorld );
11719
11720		// check distance from ray origin to bounding sphere
11721
11722		_ray$3.copy( raycaster.ray ).recast( raycaster.near );
11723
11724		if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {
11725
11726			if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;
11727
11728			if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;
11729
11730		}
11731
11732		// convert ray to local space of mesh
11733
11734		_inverseMatrix$3.copy( matrixWorld ).invert();
11735		_ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );
11736
11737		// test with bounding box in local space
11738
11739		if ( geometry.boundingBox !== null ) {
11740
11741			if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;
11742
11743		}
11744
11745		// test for intersections with geometry
11746
11747		this._computeIntersections( raycaster, intersects, _ray$3 );
11748
11749	}
11750
11751	_computeIntersections( raycaster, intersects, rayLocalSpace ) {
11752
11753		let intersection;
11754
11755		const geometry = this.geometry;
11756		const material = this.material;
11757
11758		const index = geometry.index;
11759		const position = geometry.attributes.position;
11760		const uv = geometry.attributes.uv;
11761		const uv1 = geometry.attributes.uv1;
11762		const normal = geometry.attributes.normal;
11763		const groups = geometry.groups;
11764		const drawRange = geometry.drawRange;
11765
11766		if ( index !== null ) {
11767
11768			// indexed buffer geometry
11769
11770			if ( Array.isArray( material ) ) {
11771
11772				for ( let i = 0, il = groups.length; i < il; i ++ ) {
11773
11774					const group = groups[ i ];
11775					const groupMaterial = material[ group.materialIndex ];
11776
11777					const start = Math.max( group.start, drawRange.start );
11778					const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11779
11780					for ( let j = start, jl = end; j < jl; j += 3 ) {
11781
11782						const a = index.getX( j );
11783						const b = index.getX( j + 1 );
11784						const c = index.getX( j + 2 );
11785
11786						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11787
11788						if ( intersection ) {
11789
11790							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
11791							intersection.face.materialIndex = group.materialIndex;
11792							intersects.push( intersection );
11793
11794						}
11795
11796					}
11797
11798				}
11799
11800			} else {
11801
11802				const start = Math.max( 0, drawRange.start );
11803				const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
11804
11805				for ( let i = start, il = end; i < il; i += 3 ) {
11806
11807					const a = index.getX( i );
11808					const b = index.getX( i + 1 );
11809					const c = index.getX( i + 2 );
11810
11811					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11812
11813					if ( intersection ) {
11814
11815						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
11816						intersects.push( intersection );
11817
11818					}
11819
11820				}
11821
11822			}
11823
11824		} else if ( position !== undefined ) {
11825
11826			// non-indexed buffer geometry
11827
11828			if ( Array.isArray( material ) ) {
11829
11830				for ( let i = 0, il = groups.length; i < il; i ++ ) {
11831
11832					const group = groups[ i ];
11833					const groupMaterial = material[ group.materialIndex ];
11834
11835					const start = Math.max( group.start, drawRange.start );
11836					const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11837
11838					for ( let j = start, jl = end; j < jl; j += 3 ) {
11839
11840						const a = j;
11841						const b = j + 1;
11842						const c = j + 2;
11843
11844						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11845
11846						if ( intersection ) {
11847
11848							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
11849							intersection.face.materialIndex = group.materialIndex;
11850							intersects.push( intersection );
11851
11852						}
11853
11854					}
11855
11856				}
11857
11858			} else {
11859
11860				const start = Math.max( 0, drawRange.start );
11861				const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
11862
11863				for ( let i = start, il = end; i < il; i += 3 ) {
11864
11865					const a = i;
11866					const b = i + 1;
11867					const c = i + 2;
11868
11869					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
11870
11871					if ( intersection ) {
11872
11873						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
11874						intersects.push( intersection );
11875
11876					}
11877
11878				}
11879
11880			}
11881
11882		}
11883
11884	}
11885
11886}
11887
11888function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
11889
11890	let intersect;
11891
11892	if ( material.side === BackSide ) {
11893
11894		intersect = ray.intersectTriangle( pC, pB, pA, true, point );
11895
11896	} else {
11897
11898		intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );
11899
11900	}
11901
11902	if ( intersect === null ) return null;
11903
11904	_intersectionPointWorld.copy( point );
11905	_intersectionPointWorld.applyMatrix4( object.matrixWorld );
11906
11907	const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
11908
11909	if ( distance < raycaster.near || distance > raycaster.far ) return null;
11910
11911	return {
11912		distance: distance,
11913		point: _intersectionPointWorld.clone(),
11914		object: object
11915	};
11916
11917}
11918
11919function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {
11920
11921	object.getVertexPosition( a, _vA$1 );
11922	object.getVertexPosition( b, _vB$1 );
11923	object.getVertexPosition( c, _vC$1 );
11924
11925	const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );
11926
11927	if ( intersection ) {
11928
11929		if ( uv ) {
11930
11931			_uvA$1.fromBufferAttribute( uv, a );
11932			_uvB$1.fromBufferAttribute( uv, b );
11933			_uvC$1.fromBufferAttribute( uv, c );
11934
11935			intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11936
11937		}
11938
11939		if ( uv1 ) {
11940
11941			_uvA$1.fromBufferAttribute( uv1, a );
11942			_uvB$1.fromBufferAttribute( uv1, b );
11943			_uvC$1.fromBufferAttribute( uv1, c );
11944
11945			intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11946			intersection.uv2 = intersection.uv1; // @deprecated, r152
11947
11948		}
11949
11950		if ( normal ) {
11951
11952			_normalA.fromBufferAttribute( normal, a );
11953			_normalB.fromBufferAttribute( normal, b );
11954			_normalC.fromBufferAttribute( normal, c );
11955
vendor: 11,895 bytes, lines 11956-12544
11956			intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );
11957
11958			if ( intersection.normal.dot( ray.direction ) > 0 ) {
11959
11960				intersection.normal.multiplyScalar( - 1 );
11961
11962			}
11963
11964		}
11965
11966		const face = {
11967			a: a,
11968			b: b,
11969			c: c,
11970			normal: new Vector3(),
11971			materialIndex: 0
11972		};
11973
11974		Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
11975
11976		intersection.face = face;
11977
11978	}
11979
11980	return intersection;
11981
11982}
11983
11984class BoxGeometry extends BufferGeometry {
11985
11986	constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
11987
11988		super();
11989
11990		this.type = 'BoxGeometry';
11991
11992		this.parameters = {
11993			width: width,
11994			height: height,
11995			depth: depth,
11996			widthSegments: widthSegments,
11997			heightSegments: heightSegments,
11998			depthSegments: depthSegments
11999		};
12000
12001		const scope = this;
12002
12003		// segments
12004
12005		widthSegments = Math.floor( widthSegments );
12006		heightSegments = Math.floor( heightSegments );
12007		depthSegments = Math.floor( depthSegments );
12008
12009		// buffers
12010
12011		const indices = [];
12012		const vertices = [];
12013		const normals = [];
12014		const uvs = [];
12015
12016		// helper variables
12017
12018		let numberOfVertices = 0;
12019		let groupStart = 0;
12020
12021		// build each side of the box geometry
12022
12023		buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
12024		buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
12025		buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
12026		buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
12027		buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
12028		buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
12029
12030		// build geometry
12031
12032		this.setIndex( indices );
12033		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
12034		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
12035		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
12036
12037		function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
12038
12039			const segmentWidth = width / gridX;
12040			const segmentHeight = height / gridY;
12041
12042			const widthHalf = width / 2;
12043			const heightHalf = height / 2;
12044			const depthHalf = depth / 2;
12045
12046			const gridX1 = gridX + 1;
12047			const gridY1 = gridY + 1;
12048
12049			let vertexCounter = 0;
12050			let groupCount = 0;
12051
12052			const vector = new Vector3();
12053
12054			// generate vertices, normals and uvs
12055
12056			for ( let iy = 0; iy < gridY1; iy ++ ) {
12057
12058				const y = iy * segmentHeight - heightHalf;
12059
12060				for ( let ix = 0; ix < gridX1; ix ++ ) {
12061
12062					const x = ix * segmentWidth - widthHalf;
12063
12064					// set values to correct vector component
12065
12066					vector[ u ] = x * udir;
12067					vector[ v ] = y * vdir;
12068					vector[ w ] = depthHalf;
12069
12070					// now apply vector to vertex buffer
12071
12072					vertices.push( vector.x, vector.y, vector.z );
12073
12074					// set values to correct vector component
12075
12076					vector[ u ] = 0;
12077					vector[ v ] = 0;
12078					vector[ w ] = depth > 0 ? 1 : - 1;
12079
12080					// now apply vector to normal buffer
12081
12082					normals.push( vector.x, vector.y, vector.z );
12083
12084					// uvs
12085
12086					uvs.push( ix / gridX );
12087					uvs.push( 1 - ( iy / gridY ) );
12088
12089					// counters
12090
12091					vertexCounter += 1;
12092
12093				}
12094
12095			}
12096
12097			// indices
12098
12099			// 1. you need three indices to draw a single face
12100			// 2. a single segment consists of two faces
12101			// 3. so we need to generate six (2*3) indices per segment
12102
12103			for ( let iy = 0; iy < gridY; iy ++ ) {
12104
12105				for ( let ix = 0; ix < gridX; ix ++ ) {
12106
12107					const a = numberOfVertices + ix + gridX1 * iy;
12108					const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
12109					const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
12110					const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
12111
12112					// faces
12113
12114					indices.push( a, b, d );
12115					indices.push( b, c, d );
12116
12117					// increase counter
12118
12119					groupCount += 6;
12120
12121				}
12122
12123			}
12124
12125			// add a group to the geometry. this will ensure multi material support
12126
12127			scope.addGroup( groupStart, groupCount, materialIndex );
12128
12129			// calculate new start value for groups
12130
12131			groupStart += groupCount;
12132
12133			// update total number of vertices
12134
12135			numberOfVertices += vertexCounter;
12136
12137		}
12138
12139	}
12140
12141	copy( source ) {
12142
12143		super.copy( source );
12144
12145		this.parameters = Object.assign( {}, source.parameters );
12146
12147		return this;
12148
12149	}
12150
12151	static fromJSON( data ) {
12152
12153		return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );
12154
12155	}
12156
12157}
12158
12159/**
12160 * Uniform Utilities
12161 */
12162
12163function cloneUniforms( src ) {
12164
12165	const dst = {};
12166
12167	for ( const u in src ) {
12168
12169		dst[ u ] = {};
12170
12171		for ( const p in src[ u ] ) {
12172
12173			const property = src[ u ][ p ];
12174
12175			if ( property && ( property.isColor ||
12176				property.isMatrix3 || property.isMatrix4 ||
12177				property.isVector2 || property.isVector3 || property.isVector4 ||
12178				property.isTexture || property.isQuaternion ) ) {
12179
12180				if ( property.isRenderTargetTexture ) {
12181
12182					console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );
12183					dst[ u ][ p ] = null;
12184
12185				} else {
12186
12187					dst[ u ][ p ] = property.clone();
12188
12189				}
12190
12191			} else if ( Array.isArray( property ) ) {
12192
12193				dst[ u ][ p ] = property.slice();
12194
12195			} else {
12196
12197				dst[ u ][ p ] = property;
12198
12199			}
12200
12201		}
12202
12203	}
12204
12205	return dst;
12206
12207}
12208
12209function mergeUniforms( uniforms ) {
12210
12211	const merged = {};
12212
12213	for ( let u = 0; u < uniforms.length; u ++ ) {
12214
12215		const tmp = cloneUniforms( uniforms[ u ] );
12216
12217		for ( const p in tmp ) {
12218
12219			merged[ p ] = tmp[ p ];
12220
12221		}
12222
12223	}
12224
12225	return merged;
12226
12227}
12228
12229function cloneUniformsGroups( src ) {
12230
12231	const dst = [];
12232
12233	for ( let u = 0; u < src.length; u ++ ) {
12234
12235		dst.push( src[ u ].clone() );
12236
12237	}
12238
12239	return dst;
12240
12241}
12242
12243function getUnlitUniformColorSpace( renderer ) {
12244
12245	if ( renderer.getRenderTarget() === null ) {
12246
12247		// https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398
12248		return renderer.outputColorSpace;
12249
12250	}
12251
12252	return ColorManagement.workingColorSpace;
12253
12254}
12255
12256// Legacy
12257
12258const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
12259
12260var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
12261
12262var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
12263
12264class ShaderMaterial extends Material {
12265
12266	constructor( parameters ) {
12267
12268		super();
12269
12270		this.isShaderMaterial = true;
12271
12272		this.type = 'ShaderMaterial';
12273
12274		this.defines = {};
12275		this.uniforms = {};
12276		this.uniformsGroups = [];
12277
12278		this.vertexShader = default_vertex;
12279		this.fragmentShader = default_fragment;
12280
12281		this.linewidth = 1;
12282
12283		this.wireframe = false;
12284		this.wireframeLinewidth = 1;
12285
12286		this.fog = false; // set to use scene fog
12287		this.lights = false; // set to use scene lights
12288		this.clipping = false; // set to use user-defined clipping planes
12289
12290		this.forceSinglePass = true;
12291
12292		this.extensions = {
12293			derivatives: false, // set to use derivatives
12294			fragDepth: false, // set to use fragment depth values
12295			drawBuffers: false, // set to use draw buffers
12296			shaderTextureLOD: false, // set to use shader texture LOD
12297			clipCullDistance: false // set to use vertex shader clipping
12298		};
12299
12300		// When rendered geometry doesn't include these attributes but the material does,
12301		// use these default values in WebGL. This avoids errors when buffer data is missing.
12302		this.defaultAttributeValues = {
12303			'color': [ 1, 1, 1 ],
12304			'uv': [ 0, 0 ],
12305			'uv1': [ 0, 0 ]
12306		};
12307
12308		this.index0AttributeName = undefined;
12309		this.uniformsNeedUpdate = false;
12310
12311		this.glslVersion = null;
12312
12313		if ( parameters !== undefined ) {
12314
12315			this.setValues( parameters );
12316
12317		}
12318
12319	}
12320
12321	copy( source ) {
12322
12323		super.copy( source );
12324
12325		this.fragmentShader = source.fragmentShader;
12326		this.vertexShader = source.vertexShader;
12327
12328		this.uniforms = cloneUniforms( source.uniforms );
12329		this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );
12330
12331		this.defines = Object.assign( {}, source.defines );
12332
12333		this.wireframe = source.wireframe;
12334		this.wireframeLinewidth = source.wireframeLinewidth;
12335
12336		this.fog = source.fog;
12337		this.lights = source.lights;
12338		this.clipping = source.clipping;
12339
12340		this.extensions = Object.assign( {}, source.extensions );
12341
12342		this.glslVersion = source.glslVersion;
12343
12344		return this;
12345
12346	}
12347
12348	toJSON( meta ) {
12349
12350		const data = super.toJSON( meta );
12351
12352		data.glslVersion = this.glslVersion;
12353		data.uniforms = {};
12354
12355		for ( const name in this.uniforms ) {
12356
12357			const uniform = this.uniforms[ name ];
12358			const value = uniform.value;
12359
12360			if ( value && value.isTexture ) {
12361
12362				data.uniforms[ name ] = {
12363					type: 't',
12364					value: value.toJSON( meta ).uuid
12365				};
12366
12367			} else if ( value && value.isColor ) {
12368
12369				data.uniforms[ name ] = {
12370					type: 'c',
12371					value: value.getHex()
12372				};
12373
12374			} else if ( value && value.isVector2 ) {
12375
12376				data.uniforms[ name ] = {
12377					type: 'v2',
12378					value: value.toArray()
12379				};
12380
12381			} else if ( value && value.isVector3 ) {
12382
12383				data.uniforms[ name ] = {
12384					type: 'v3',
12385					value: value.toArray()
12386				};
12387
12388			} else if ( value && value.isVector4 ) {
12389
12390				data.uniforms[ name ] = {
12391					type: 'v4',
12392					value: value.toArray()
12393				};
12394
12395			} else if ( value && value.isMatrix3 ) {
12396
12397				data.uniforms[ name ] = {
12398					type: 'm3',
12399					value: value.toArray()
12400				};
12401
12402			} else if ( value && value.isMatrix4 ) {
12403
12404				data.uniforms[ name ] = {
12405					type: 'm4',
12406					value: value.toArray()
12407				};
12408
12409			} else {
12410
12411				data.uniforms[ name ] = {
12412					value: value
12413				};
12414
12415				// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
12416
12417			}
12418
12419		}
12420
12421		if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
12422
12423		data.vertexShader = this.vertexShader;
12424		data.fragmentShader = this.fragmentShader;
12425
12426		data.lights = this.lights;
12427		data.clipping = this.clipping;
12428
12429		const extensions = {};
12430
12431		for ( const key in this.extensions ) {
12432
12433			if ( this.extensions[ key ] === true ) extensions[ key ] = true;
12434
12435		}
12436
12437		if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
12438
12439		return data;
12440
12441	}
12442
12443}
12444
12445class Camera extends Object3D {
12446
12447	constructor() {
12448
12449		super();
12450
12451		this.isCamera = true;
12452
12453		this.type = 'Camera';
12454
12455		this.matrixWorldInverse = new Matrix4();
12456
12457		this.projectionMatrix = new Matrix4();
12458		this.projectionMatrixInverse = new Matrix4();
12459
12460		this.coordinateSystem = WebGLCoordinateSystem;
12461
12462	}
12463
12464	copy( source, recursive ) {
12465
12466		super.copy( source, recursive );
12467
12468		this.matrixWorldInverse.copy( source.matrixWorldInverse );
12469
12470		this.projectionMatrix.copy( source.projectionMatrix );
12471		this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
12472
12473		this.coordinateSystem = source.coordinateSystem;
12474
12475		return this;
12476
12477	}
12478
12479	getWorldDirection( target ) {
12480
12481		return super.getWorldDirection( target ).negate();
12482
12483	}
12484
12485	updateMatrixWorld( force ) {
12486
12487		super.updateMatrixWorld( force );
12488
12489		this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12490
12491	}
12492
12493	updateWorldMatrix( updateParents, updateChildren ) {
12494
12495		super.updateWorldMatrix( updateParents, updateChildren );
12496
12497		this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12498
12499	}
12500
12501	clone() {
12502
12503		return new this.constructor().copy( this );
12504
12505	}
12506
12507}
12508
12509class PerspectiveCamera extends Camera {
12510
12511	constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
12512
12513		super();
12514
12515		this.isPerspectiveCamera = true;
12516
12517		this.type = 'PerspectiveCamera';
12518
12519		this.fov = fov;
12520		this.zoom = 1;
12521
12522		this.near = near;
12523		this.far = far;
12524		this.focus = 10;
12525
12526		this.aspect = aspect;
12527		this.view = null;
12528
12529		this.filmGauge = 35;	// width of the film (default in millimeters)
12530		this.filmOffset = 0;	// horizontal film offset (same unit as gauge)
12531
12532		this.updateProjectionMatrix();
12533
12534	}
12535
12536	copy( source, recursive ) {
12537
12538		super.copy( source, recursive );
12539
12540		this.fov = source.fov;
12541		this.zoom = source.zoom;
12542
12543		this.near = source.near;
12544		this.far = source.far;
vendor: 3,387 bytes, lines 12545-12690
12545		this.focus = source.focus;
12546
12547		this.aspect = source.aspect;
12548		this.view = source.view === null ? null : Object.assign( {}, source.view );
12549
12550		this.filmGauge = source.filmGauge;
12551		this.filmOffset = source.filmOffset;
12552
12553		return this;
12554
12555	}
12556
12557	/**
12558	 * Sets the FOV by focal length in respect to the current .filmGauge.
12559	 *
12560	 * The default film gauge is 35, so that the focal length can be specified for
12561	 * a 35mm (full frame) camera.
12562	 *
12563	 * Values for focal length and film gauge must have the same unit.
12564	 */
12565	setFocalLength( focalLength ) {
12566
12567		/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
12568		const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
12569
12570		this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );
12571		this.updateProjectionMatrix();
12572
12573	}
12574
12575	/**
12576	 * Calculates the focal length from the current .fov and .filmGauge.
12577	 */
12578	getFocalLength() {
12579
12580		const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );
12581
12582		return 0.5 * this.getFilmHeight() / vExtentSlope;
12583
12584	}
12585
12586	getEffectiveFOV() {
12587
12588		return RAD2DEG * 2 * Math.atan(
12589			Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );
12590
12591	}
12592
12593	getFilmWidth() {
12594
12595		// film not completely covered in portrait format (aspect < 1)
12596		return this.filmGauge * Math.min( this.aspect, 1 );
12597
12598	}
12599
12600	getFilmHeight() {
12601
12602		// film not completely covered in landscape format (aspect > 1)
12603		return this.filmGauge / Math.max( this.aspect, 1 );
12604
12605	}
12606
12607	/**
12608	 * Sets an offset in a larger frustum. This is useful for multi-window or
12609	 * multi-monitor/multi-machine setups.
12610	 *
12611	 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
12612	 * the monitors are in grid like this
12613	 *
12614	 *   +---+---+---+
12615	 *   | A | B | C |
12616	 *   +---+---+---+
12617	 *   | D | E | F |
12618	 *   +---+---+---+
12619	 *
12620	 * then for each monitor you would call it like this
12621	 *
12622	 *   const w = 1920;
12623	 *   const h = 1080;
12624	 *   const fullWidth = w * 3;
12625	 *   const fullHeight = h * 2;
12626	 *
12627	 *   --A--
12628	 *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
12629	 *   --B--
12630	 *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
12631	 *   --C--
12632	 *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
12633	 *   --D--
12634	 *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
12635	 *   --E--
12636	 *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
12637	 *   --F--
12638	 *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
12639	 *
12640	 *   Note there is no reason monitors have to be the same size or in a grid.
12641	 */
12642	setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
12643
12644		this.aspect = fullWidth / fullHeight;
12645
12646		if ( this.view === null ) {
12647
12648			this.view = {
12649				enabled: true,
12650				fullWidth: 1,
12651				fullHeight: 1,
12652				offsetX: 0,
12653				offsetY: 0,
12654				width: 1,
12655				height: 1
12656			};
12657
12658		}
12659
12660		this.view.enabled = true;
12661		this.view.fullWidth = fullWidth;
12662		this.view.fullHeight = fullHeight;
12663		this.view.offsetX = x;
12664		this.view.offsetY = y;
12665		this.view.width = width;
12666		this.view.height = height;
12667
12668		this.updateProjectionMatrix();
12669
12670	}
12671
12672	clearViewOffset() {
12673
12674		if ( this.view !== null ) {
12675
12676			this.view.enabled = false;
12677
12678		}
12679
12680		this.updateProjectionMatrix();
12681
12682	}
12683
12684	updateProjectionMatrix() {
12685
12686		const near = this.near;
12687		let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;
12688		let height = 2 * top;
12689		let width = this.aspect * height;
12690		let left = - 0.5 * width;
vendor: 25,579 bytes, lines 12691-13840
12691		const view = this.view;
12692
12693		if ( this.view !== null && this.view.enabled ) {
12694
12695			const fullWidth = view.fullWidth,
12696				fullHeight = view.fullHeight;
12697
12698			left += view.offsetX * width / fullWidth;
12699			top -= view.offsetY * height / fullHeight;
12700			width *= view.width / fullWidth;
12701			height *= view.height / fullHeight;
12702
12703		}
12704
12705		const skew = this.filmOffset;
12706		if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
12707
12708		this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );
12709
12710		this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
12711
12712	}
12713
12714	toJSON( meta ) {
12715
12716		const data = super.toJSON( meta );
12717
12718		data.object.fov = this.fov;
12719		data.object.zoom = this.zoom;
12720
12721		data.object.near = this.near;
12722		data.object.far = this.far;
12723		data.object.focus = this.focus;
12724
12725		data.object.aspect = this.aspect;
12726
12727		if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12728
12729		data.object.filmGauge = this.filmGauge;
12730		data.object.filmOffset = this.filmOffset;
12731
12732		return data;
12733
12734	}
12735
12736}
12737
12738const fov = - 90; // negative fov is not an error
12739const aspect = 1;
12740
12741class CubeCamera extends Object3D {
12742
12743	constructor( near, far, renderTarget ) {
12744
12745		super();
12746
12747		this.type = 'CubeCamera';
12748
12749		this.renderTarget = renderTarget;
12750		this.coordinateSystem = null;
12751		this.activeMipmapLevel = 0;
12752
12753		const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
12754		cameraPX.layers = this.layers;
12755		this.add( cameraPX );
12756
12757		const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
12758		cameraNX.layers = this.layers;
12759		this.add( cameraNX );
12760
12761		const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
12762		cameraPY.layers = this.layers;
12763		this.add( cameraPY );
12764
12765		const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
12766		cameraNY.layers = this.layers;
12767		this.add( cameraNY );
12768
12769		const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
12770		cameraPZ.layers = this.layers;
12771		this.add( cameraPZ );
12772
12773		const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
12774		cameraNZ.layers = this.layers;
12775		this.add( cameraNZ );
12776
12777	}
12778
12779	updateCoordinateSystem() {
12780
12781		const coordinateSystem = this.coordinateSystem;
12782
12783		const cameras = this.children.concat();
12784
12785		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras;
12786
12787		for ( const camera of cameras ) this.remove( camera );
12788
12789		if ( coordinateSystem === WebGLCoordinateSystem ) {
12790
12791			cameraPX.up.set( 0, 1, 0 );
12792			cameraPX.lookAt( 1, 0, 0 );
12793
12794			cameraNX.up.set( 0, 1, 0 );
12795			cameraNX.lookAt( - 1, 0, 0 );
12796
12797			cameraPY.up.set( 0, 0, - 1 );
12798			cameraPY.lookAt( 0, 1, 0 );
12799
12800			cameraNY.up.set( 0, 0, 1 );
12801			cameraNY.lookAt( 0, - 1, 0 );
12802
12803			cameraPZ.up.set( 0, 1, 0 );
12804			cameraPZ.lookAt( 0, 0, 1 );
12805
12806			cameraNZ.up.set( 0, 1, 0 );
12807			cameraNZ.lookAt( 0, 0, - 1 );
12808
12809		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
12810
12811			cameraPX.up.set( 0, - 1, 0 );
12812			cameraPX.lookAt( - 1, 0, 0 );
12813
12814			cameraNX.up.set( 0, - 1, 0 );
12815			cameraNX.lookAt( 1, 0, 0 );
12816
12817			cameraPY.up.set( 0, 0, 1 );
12818			cameraPY.lookAt( 0, 1, 0 );
12819
12820			cameraNY.up.set( 0, 0, - 1 );
12821			cameraNY.lookAt( 0, - 1, 0 );
12822
12823			cameraPZ.up.set( 0, - 1, 0 );
12824			cameraPZ.lookAt( 0, 0, 1 );
12825
12826			cameraNZ.up.set( 0, - 1, 0 );
12827			cameraNZ.lookAt( 0, 0, - 1 );
12828
12829		} else {
12830
12831			throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );
12832
12833		}
12834
12835		for ( const camera of cameras ) {
12836
12837			this.add( camera );
12838
12839			camera.updateMatrixWorld();
12840
12841		}
12842
12843	}
12844
12845	update( renderer, scene ) {
12846
12847		if ( this.parent === null ) this.updateMatrixWorld();
12848
12849		const { renderTarget, activeMipmapLevel } = this;
12850
12851		if ( this.coordinateSystem !== renderer.coordinateSystem ) {
12852
12853			this.coordinateSystem = renderer.coordinateSystem;
12854
12855			this.updateCoordinateSystem();
12856
12857		}
12858
12859		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;
12860
12861		const currentRenderTarget = renderer.getRenderTarget();
12862		const currentActiveCubeFace = renderer.getActiveCubeFace();
12863		const currentActiveMipmapLevel = renderer.getActiveMipmapLevel();
12864
12865		const currentXrEnabled = renderer.xr.enabled;
12866
12867		renderer.xr.enabled = false;
12868
12869		const generateMipmaps = renderTarget.texture.generateMipmaps;
12870
12871		renderTarget.texture.generateMipmaps = false;
12872
12873		renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel );
12874		renderer.render( scene, cameraPX );
12875
12876		renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel );
12877		renderer.render( scene, cameraNX );
12878
12879		renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel );
12880		renderer.render( scene, cameraPY );
12881
12882		renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel );
12883		renderer.render( scene, cameraNY );
12884
12885		renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel );
12886		renderer.render( scene, cameraPZ );
12887
12888		// mipmaps are generated during the last call of render()
12889		// at this point, all sides of the cube render target are defined
12890
12891		renderTarget.texture.generateMipmaps = generateMipmaps;
12892
12893		renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );
12894		renderer.render( scene, cameraNZ );
12895
12896		renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );
12897
12898		renderer.xr.enabled = currentXrEnabled;
12899
12900		renderTarget.texture.needsPMREMUpdate = true;
12901
12902	}
12903
12904}
12905
12906class CubeTexture extends Texture {
12907
12908	constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) {
12909
12910		images = images !== undefined ? images : [];
12911		mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
12912
12913		super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
12914
12915		this.isCubeTexture = true;
12916
12917		this.flipY = false;
12918
12919	}
12920
12921	get images() {
12922
12923		return this.image;
12924
12925	}
12926
12927	set images( value ) {
12928
12929		this.image = value;
12930
12931	}
12932
12933}
12934
12935class WebGLCubeRenderTarget extends WebGLRenderTarget {
12936
12937	constructor( size = 1, options = {} ) {
12938
12939		super( size, size, options );
12940
12941		this.isWebGLCubeRenderTarget = true;
12942
12943		const image = { width: size, height: size, depth: 1 };
12944		const images = [ image, image, image, image, image, image ];
12945
12946		if ( options.encoding !== undefined ) {
12947
12948			// @deprecated, r152
12949			warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' );
12950			options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
12951
12952		}
12953
12954		this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
12955
12956		// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
12957		// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
12958		// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
12959
12960		// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
12961		// and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture
12962		// as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).
12963
12964		this.texture.isRenderTargetTexture = true;
12965
12966		this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
12967		this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
12968
12969	}
12970
12971	fromEquirectangularTexture( renderer, texture ) {
12972
12973		this.texture.type = texture.type;
12974		this.texture.colorSpace = texture.colorSpace;
12975
12976		this.texture.generateMipmaps = texture.generateMipmaps;
12977		this.texture.minFilter = texture.minFilter;
12978		this.texture.magFilter = texture.magFilter;
12979
12980		const shader = {
12981
12982			uniforms: {
12983				tEquirect: { value: null },
12984			},
12985
12986			vertexShader: /* glsl */`
12987
12988				varying vec3 vWorldDirection;
12989
12990				vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
12991
12992					return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
12993
12994				}
12995
12996				void main() {
12997
12998					vWorldDirection = transformDirection( position, modelMatrix );
12999
13000					#include <begin_vertex>
13001					#include <project_vertex>
13002
13003				}
13004			`,
13005
13006			fragmentShader: /* glsl */`
13007
13008				uniform sampler2D tEquirect;
13009
13010				varying vec3 vWorldDirection;
13011
13012				#include <common>
13013
13014				void main() {
13015
13016					vec3 direction = normalize( vWorldDirection );
13017
13018					vec2 sampleUV = equirectUv( direction );
13019
13020					gl_FragColor = texture2D( tEquirect, sampleUV );
13021
13022				}
13023			`
13024		};
13025
13026		const geometry = new BoxGeometry( 5, 5, 5 );
13027
13028		const material = new ShaderMaterial( {
13029
13030			name: 'CubemapFromEquirect',
13031
13032			uniforms: cloneUniforms( shader.uniforms ),
13033			vertexShader: shader.vertexShader,
13034			fragmentShader: shader.fragmentShader,
13035			side: BackSide,
13036			blending: NoBlending
13037
13038		} );
13039
13040		material.uniforms.tEquirect.value = texture;
13041
13042		const mesh = new Mesh( geometry, material );
13043
13044		const currentMinFilter = texture.minFilter;
13045
13046		// Avoid blurred poles
13047		if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
13048
13049		const camera = new CubeCamera( 1, 10, this );
13050		camera.update( renderer, mesh );
13051
13052		texture.minFilter = currentMinFilter;
13053
13054		mesh.geometry.dispose();
13055		mesh.material.dispose();
13056
13057		return this;
13058
13059	}
13060
13061	clear( renderer, color, depth, stencil ) {
13062
13063		const currentRenderTarget = renderer.getRenderTarget();
13064
13065		for ( let i = 0; i < 6; i ++ ) {
13066
13067			renderer.setRenderTarget( this, i );
13068
13069			renderer.clear( color, depth, stencil );
13070
13071		}
13072
13073		renderer.setRenderTarget( currentRenderTarget );
13074
13075	}
13076
13077}
13078
13079const _vector1 = /*@__PURE__*/ new Vector3();
13080const _vector2 = /*@__PURE__*/ new Vector3();
13081const _normalMatrix = /*@__PURE__*/ new Matrix3();
13082
13083class Plane {
13084
13085	constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {
13086
13087		this.isPlane = true;
13088
13089		// normal is assumed to be normalized
13090
13091		this.normal = normal;
13092		this.constant = constant;
13093
13094	}
13095
13096	set( normal, constant ) {
13097
13098		this.normal.copy( normal );
13099		this.constant = constant;
13100
13101		return this;
13102
13103	}
13104
13105	setComponents( x, y, z, w ) {
13106
13107		this.normal.set( x, y, z );
13108		this.constant = w;
13109
13110		return this;
13111
13112	}
13113
13114	setFromNormalAndCoplanarPoint( normal, point ) {
13115
13116		this.normal.copy( normal );
13117		this.constant = - point.dot( this.normal );
13118
13119		return this;
13120
13121	}
13122
13123	setFromCoplanarPoints( a, b, c ) {
13124
13125		const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
13126
13127		// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
13128
13129		this.setFromNormalAndCoplanarPoint( normal, a );
13130
13131		return this;
13132
13133	}
13134
13135	copy( plane ) {
13136
13137		this.normal.copy( plane.normal );
13138		this.constant = plane.constant;
13139
13140		return this;
13141
13142	}
13143
13144	normalize() {
13145
13146		// Note: will lead to a divide by zero if the plane is invalid.
13147
13148		const inverseNormalLength = 1.0 / this.normal.length();
13149		this.normal.multiplyScalar( inverseNormalLength );
13150		this.constant *= inverseNormalLength;
13151
13152		return this;
13153
13154	}
13155
13156	negate() {
13157
13158		this.constant *= - 1;
13159		this.normal.negate();
13160
13161		return this;
13162
13163	}
13164
13165	distanceToPoint( point ) {
13166
13167		return this.normal.dot( point ) + this.constant;
13168
13169	}
13170
13171	distanceToSphere( sphere ) {
13172
13173		return this.distanceToPoint( sphere.center ) - sphere.radius;
13174
13175	}
13176
13177	projectPoint( point, target ) {
13178
13179		return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) );
13180
13181	}
13182
13183	intersectLine( line, target ) {
13184
13185		const direction = line.delta( _vector1 );
13186
13187		const denominator = this.normal.dot( direction );
13188
13189		if ( denominator === 0 ) {
13190
13191			// line is coplanar, return origin
13192			if ( this.distanceToPoint( line.start ) === 0 ) {
13193
13194				return target.copy( line.start );
13195
13196			}
13197
13198			// Unsure if this is the correct method to handle this case.
13199			return null;
13200
13201		}
13202
13203		const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
13204
13205		if ( t < 0 || t > 1 ) {
13206
13207			return null;
13208
13209		}
13210
13211		return target.copy( line.start ).addScaledVector( direction, t );
13212
13213	}
13214
13215	intersectsLine( line ) {
13216
13217		// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
13218
13219		const startSign = this.distanceToPoint( line.start );
13220		const endSign = this.distanceToPoint( line.end );
13221
13222		return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
13223
13224	}
13225
13226	intersectsBox( box ) {
13227
13228		return box.intersectsPlane( this );
13229
13230	}
13231
13232	intersectsSphere( sphere ) {
13233
13234		return sphere.intersectsPlane( this );
13235
13236	}
13237
13238	coplanarPoint( target ) {
13239
13240		return target.copy( this.normal ).multiplyScalar( - this.constant );
13241
13242	}
13243
13244	applyMatrix4( matrix, optionalNormalMatrix ) {
13245
13246		const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
13247
13248		const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
13249
13250		const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
13251
13252		this.constant = - referencePoint.dot( normal );
13253
13254		return this;
13255
13256	}
13257
13258	translate( offset ) {
13259
13260		this.constant -= offset.dot( this.normal );
13261
13262		return this;
13263
13264	}
13265
13266	equals( plane ) {
13267
13268		return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
13269
13270	}
13271
13272	clone() {
13273
13274		return new this.constructor().copy( this );
13275
13276	}
13277
13278}
13279
13280const _sphere$5 = /*@__PURE__*/ new Sphere();
13281const _vector$7 = /*@__PURE__*/ new Vector3();
13282
13283class Frustum {
13284
13285	constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {
13286
13287		this.planes = [ p0, p1, p2, p3, p4, p5 ];
13288
13289	}
13290
13291	set( p0, p1, p2, p3, p4, p5 ) {
13292
13293		const planes = this.planes;
13294
13295		planes[ 0 ].copy( p0 );
13296		planes[ 1 ].copy( p1 );
13297		planes[ 2 ].copy( p2 );
13298		planes[ 3 ].copy( p3 );
13299		planes[ 4 ].copy( p4 );
13300		planes[ 5 ].copy( p5 );
13301
13302		return this;
13303
13304	}
13305
13306	copy( frustum ) {
13307
13308		const planes = this.planes;
13309
13310		for ( let i = 0; i < 6; i ++ ) {
13311
13312			planes[ i ].copy( frustum.planes[ i ] );
13313
13314		}
13315
13316		return this;
13317
13318	}
13319
13320	setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) {
13321
13322		const planes = this.planes;
13323		const me = m.elements;
13324		const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
13325		const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
13326		const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
13327		const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
13328
13329		planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
13330		planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
13331		planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
13332		planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
13333		planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
13334
13335		if ( coordinateSystem === WebGLCoordinateSystem ) {
13336
13337			planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
13338
13339		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
13340
13341			planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();
13342
13343		} else {
13344
13345			throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );
13346
13347		}
13348
13349		return this;
13350
13351	}
13352
13353	intersectsObject( object ) {
13354
13355		if ( object.boundingSphere !== undefined ) {
13356
13357			if ( object.boundingSphere === null ) object.computeBoundingSphere();
13358
13359			_sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );
13360
13361		} else {
13362
13363			const geometry = object.geometry;
13364
13365			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
13366
13367			_sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
13368
13369		}
13370
13371		return this.intersectsSphere( _sphere$5 );
13372
13373	}
13374
13375	intersectsSprite( sprite ) {
13376
13377		_sphere$5.center.set( 0, 0, 0 );
13378		_sphere$5.radius = 0.7071067811865476;
13379		_sphere$5.applyMatrix4( sprite.matrixWorld );
13380
13381		return this.intersectsSphere( _sphere$5 );
13382
13383	}
13384
13385	intersectsSphere( sphere ) {
13386
13387		const planes = this.planes;
13388		const center = sphere.center;
13389		const negRadius = - sphere.radius;
13390
13391		for ( let i = 0; i < 6; i ++ ) {
13392
13393			const distance = planes[ i ].distanceToPoint( center );
13394
13395			if ( distance < negRadius ) {
13396
13397				return false;
13398
13399			}
13400
13401		}
13402
13403		return true;
13404
13405	}
13406
13407	intersectsBox( box ) {
13408
13409		const planes = this.planes;
13410
13411		for ( let i = 0; i < 6; i ++ ) {
13412
13413			const plane = planes[ i ];
13414
13415			// corner at max distance
13416
13417			_vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;
13418			_vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;
13419			_vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;
13420
13421			if ( plane.distanceToPoint( _vector$7 ) < 0 ) {
13422
13423				return false;
13424
13425			}
13426
13427		}
13428
13429		return true;
13430
13431	}
13432
13433	containsPoint( point ) {
13434
13435		const planes = this.planes;
13436
13437		for ( let i = 0; i < 6; i ++ ) {
13438
13439			if ( planes[ i ].distanceToPoint( point ) < 0 ) {
13440
13441				return false;
13442
13443			}
13444
13445		}
13446
13447		return true;
13448
13449	}
13450
13451	clone() {
13452
13453		return new this.constructor().copy( this );
13454
13455	}
13456
13457}
13458
13459function WebGLAnimation() {
13460
13461	let context = null;
13462	let isAnimating = false;
13463	let animationLoop = null;
13464	let requestId = null;
13465
13466	function onAnimationFrame( time, frame ) {
13467
13468		animationLoop( time, frame );
13469
13470		requestId = context.requestAnimationFrame( onAnimationFrame );
13471
13472	}
13473
13474	return {
13475
13476		start: function () {
13477
13478			if ( isAnimating === true ) return;
13479			if ( animationLoop === null ) return;
13480
13481			requestId = context.requestAnimationFrame( onAnimationFrame );
13482
13483			isAnimating = true;
13484
13485		},
13486
13487		stop: function () {
13488
13489			context.cancelAnimationFrame( requestId );
13490
13491			isAnimating = false;
13492
13493		},
13494
13495		setAnimationLoop: function ( callback ) {
13496
13497			animationLoop = callback;
13498
13499		},
13500
13501		setContext: function ( value ) {
13502
13503			context = value;
13504
13505		}
13506
13507	};
13508
13509}
13510
13511function WebGLAttributes( gl, capabilities ) {
13512
13513	const isWebGL2 = capabilities.isWebGL2;
13514
13515	const buffers = new WeakMap();
13516
13517	function createBuffer( attribute, bufferType ) {
13518
13519		const array = attribute.array;
13520		const usage = attribute.usage;
13521		const size = array.byteLength;
13522
13523		const buffer = gl.createBuffer();
13524
13525		gl.bindBuffer( bufferType, buffer );
13526		gl.bufferData( bufferType, array, usage );
13527
13528		attribute.onUploadCallback();
13529
13530		let type;
13531
13532		if ( array instanceof Float32Array ) {
13533
13534			type = gl.FLOAT;
13535
13536		} else if ( array instanceof Uint16Array ) {
13537
13538			if ( attribute.isFloat16BufferAttribute ) {
13539
13540				if ( isWebGL2 ) {
13541
13542					type = gl.HALF_FLOAT;
13543
13544				} else {
13545
13546					throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
13547
13548				}
13549
13550			} else {
13551
13552				type = gl.UNSIGNED_SHORT;
13553
13554			}
13555
13556		} else if ( array instanceof Int16Array ) {
13557
13558			type = gl.SHORT;
13559
13560		} else if ( array instanceof Uint32Array ) {
13561
13562			type = gl.UNSIGNED_INT;
13563
13564		} else if ( array instanceof Int32Array ) {
13565
13566			type = gl.INT;
13567
13568		} else if ( array instanceof Int8Array ) {
13569
13570			type = gl.BYTE;
13571
13572		} else if ( array instanceof Uint8Array ) {
13573
13574			type = gl.UNSIGNED_BYTE;
13575
13576		} else if ( array instanceof Uint8ClampedArray ) {
13577
13578			type = gl.UNSIGNED_BYTE;
13579
13580		} else {
13581
13582			throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );
13583
13584		}
13585
13586		return {
13587			buffer: buffer,
13588			type: type,
13589			bytesPerElement: array.BYTES_PER_ELEMENT,
13590			version: attribute.version,
13591			size: size
13592		};
13593
13594	}
13595
13596	function updateBuffer( buffer, attribute, bufferType ) {
13597
13598		const array = attribute.array;
13599		const updateRange = attribute._updateRange; // deprecated
13600		const updateRanges = attribute.updateRanges;
13601
13602		gl.bindBuffer( bufferType, buffer );
13603
13604		if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
13605
13606			// Not using update ranges
13607			gl.bufferSubData( bufferType, 0, array );
13608
13609		}
13610
13611		if ( updateRanges.length !== 0 ) {
13612
13613			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
13614
13615				const range = updateRanges[ i ];
13616				if ( isWebGL2 ) {
13617
13618					gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13619						array, range.start, range.count );
13620
13621				} else {
13622
13623					gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13624						array.subarray( range.start, range.start + range.count ) );
13625
13626				}
13627
13628			}
13629
13630			attribute.clearUpdateRanges();
13631
13632		}
13633
13634		// deprecated
13635		if ( updateRange.count !== - 1 ) {
13636
13637			if ( isWebGL2 ) {
13638
13639				gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13640					array, updateRange.offset, updateRange.count );
13641
13642			} else {
13643
13644				gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13645					array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
13646
13647			}
13648
13649			updateRange.count = - 1; // reset range
13650
13651		}
13652
13653		attribute.onUploadCallback();
13654
13655	}
13656
13657	//
13658
13659	function get( attribute ) {
13660
13661		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13662
13663		return buffers.get( attribute );
13664
13665	}
13666
13667	function remove( attribute ) {
13668
13669		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13670
13671		const data = buffers.get( attribute );
13672
13673		if ( data ) {
13674
13675			gl.deleteBuffer( data.buffer );
13676
13677			buffers.delete( attribute );
13678
13679		}
13680
13681	}
13682
13683	function update( attribute, bufferType ) {
13684
13685		if ( attribute.isGLBufferAttribute ) {
13686
13687			const cached = buffers.get( attribute );
13688
13689			if ( ! cached || cached.version < attribute.version ) {
13690
13691				buffers.set( attribute, {
13692					buffer: attribute.buffer,
13693					type: attribute.type,
13694					bytesPerElement: attribute.elementSize,
13695					version: attribute.version
13696				} );
13697
13698			}
13699
13700			return;
13701
13702		}
13703
13704		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13705
13706		const data = buffers.get( attribute );
13707
13708		if ( data === undefined ) {
13709
13710			buffers.set( attribute, createBuffer( attribute, bufferType ) );
13711
13712		} else if ( data.version < attribute.version ) {
13713
13714			if ( data.size !== attribute.array.byteLength ) {
13715
13716				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.' );
13717
13718			}
13719
13720			updateBuffer( data.buffer, attribute, bufferType );
13721
13722			data.version = attribute.version;
13723
13724		}
13725
13726	}
13727
13728	return {
13729
13730		get: get,
13731		remove: remove,
13732		update: update
13733
13734	};
13735
13736}
13737
13738class PlaneGeometry extends BufferGeometry {
13739
13740	constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
13741
13742		super();
13743
13744		this.type = 'PlaneGeometry';
13745
13746		this.parameters = {
13747			width: width,
13748			height: height,
13749			widthSegments: widthSegments,
13750			heightSegments: heightSegments
13751		};
13752
13753		const width_half = width / 2;
13754		const height_half = height / 2;
13755
13756		const gridX = Math.floor( widthSegments );
13757		const gridY = Math.floor( heightSegments );
13758
13759		const gridX1 = gridX + 1;
13760		const gridY1 = gridY + 1;
13761
13762		const segment_width = width / gridX;
13763		const segment_height = height / gridY;
13764
13765		//
13766
13767		const indices = [];
13768		const vertices = [];
13769		const normals = [];
13770		const uvs = [];
13771
13772		for ( let iy = 0; iy < gridY1; iy ++ ) {
13773
13774			const y = iy * segment_height - height_half;
13775
13776			for ( let ix = 0; ix < gridX1; ix ++ ) {
13777
13778				const x = ix * segment_width - width_half;
13779
13780				vertices.push( x, - y, 0 );
13781
13782				normals.push( 0, 0, 1 );
13783
13784				uvs.push( ix / gridX );
13785				uvs.push( 1 - ( iy / gridY ) );
13786
13787			}
13788
13789		}
13790
13791		for ( let iy = 0; iy < gridY; iy ++ ) {
13792
13793			for ( let ix = 0; ix < gridX; ix ++ ) {
13794
13795				const a = ix + gridX1 * iy;
13796				const b = ix + gridX1 * ( iy + 1 );
13797				const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
13798				const d = ( ix + 1 ) + gridX1 * iy;
13799
13800				indices.push( a, b, d );
13801				indices.push( b, c, d );
13802
13803			}
13804
13805		}
13806
13807		this.setIndex( indices );
13808		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
13809		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
13810		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
13811
13812	}
13813
13814	copy( source ) {
13815
13816		super.copy( source );
13817
13818		this.parameters = Object.assign( {}, source.parameters );
13819
13820		return this;
13821
13822	}
13823
13824	static fromJSON( data ) {
13825
13826		return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );
13827
13828	}
13829
13830}
13831
13832var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif";
13833
13834var 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";
13835
13836var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif";
13837
13838var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
13839
13840var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;
vendor: 6,502 bytes, lines 13840-13862
13840\n#endif";
13841
13842var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif";
13843
13844var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif";
13845
13846var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
13847
13848var 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";
13849
13850var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif";
13851
13852var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif";
13853
13854var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
13855
13856var 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";
13857
13858var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660,  0.0556434,\n\t\t-1.5371385,  1.8760108, -0.2040259,\n\t\t-0.4985314,  0.0415560,  1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif";
13859
13860var 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";
13861
13862var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#
13862pragma 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";
13863
13864var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
13865
13866var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
13867
13868var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
13869
13870var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif";
13871
13872var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif";
13873
13874var 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";
13875
13876var 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";
13877
13878var 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";
13879
13880var 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";
13881
13882var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
13882\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";
13883
13884var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
13885
13886var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif";
13887
13888var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
13889
13890var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
13891
13892var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
13893
13894var 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}";
13895
13896var 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";
13897
13898var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap
vendor: 9,428 bytes, lines 13898-13926
13898;\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";
13899
13900var 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";
13901
13902var 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";
13903
13904var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
13905
13906var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif";
13907
13908var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif";
13909
13910var 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";
13911
13912var 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";
13913
13914var 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}";
13915
13916var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif";
13917
13918var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
13919
13920var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;";
13921
13922var 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";
13923
13924var 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}\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";
13925
13926var 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, 
13926worldNormal, 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,
vendor: 32,390 bytes, lines 13926-13966
13926 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";
13927
13928var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
13929
13930var 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";
13931
13932var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
13933
13934var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong";
13935
13936var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_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";
13937
13938var 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}";
13939
13940var 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";
13941
13942var 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";
13943
13944var 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";
13945
13946var 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";
13947
13948var 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";
13949
13950var 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";
13951
13952var 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";
13953
13954var 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";
13955
13956var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
13957
13958var 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";
13959
13960var 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";
13961
13962var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
13963
13964var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
13965
13966var morph
13966color_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";
13967
13968var 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";
13969
13970var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];
vendor: 27,395 bytes, lines 13970-14032
13970\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";
13971
13972var 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";
13973
13974var 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;";
13975
13976var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
13977
13978var 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";
13979
13980var 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";
13981
13982var 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";
13983
13984var 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";
13985
13986var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif";
13987
13988var 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";
13989
13990var 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";
13991
13992var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif";
13993
13994var 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 );";
13995
13996var 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}";
13997
13998var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
13999
14000var 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;";
14001
14002var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
14003
14004var 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";
14005
14006var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
14007
14008var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
14009
14010var 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";
14011
14012var 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";
14013
14014var 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";
14015
14016var 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}";
14017
14018var 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";
14019
14020var 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";
14021
14022var 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";
14023
14024var 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";
14025
14026var 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";
14027
14028var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
14029
14030var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
14031
14032var 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 
14032= 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; }";
14033
14034var 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";
14035
14036var 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 );
vendor: 8,994 bytes, lines 14036-14052
14036\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";
14037
14038var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif";
14039
14040var 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";
14041
14042var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif";
14043
14044var 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";
14045
14046const 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}";
14047
14048const 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}";
14049
14050const 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}";
14051
14052const 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 
14052flipEnvMap;\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}";
14053
14054const 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}";
14055
14056const 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}";
14057
14058const 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}";
14059
14060const 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}";
14061
14062const 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}";
14063
14064const 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}";
14065
14066const 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}";
14067
14068const 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}";
14069
14070const 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}";
14071
14072const 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}";
14073
14074const 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}";
14075
14076const 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}";
14077
14078const 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}";
14079
14080const 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}";
14081
14082const 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>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
14083
14084const 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;
14084\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}";
14085
14086const 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}";
14087
14088const 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}";
14089
14090const 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}";
14091
14092const 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}";
14093
14094const 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}";
14095
14096const 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;
14096\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;
14096\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}";
14097
14098const 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}";
14099
14100const 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}";
14101
14102const 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}";
14103
14104const 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}";
14105
14106const 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}";
14107
14108const 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}";
14109
14110const 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}";
14111
14112const 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}";
14113
14114const ShaderChunk = {
14115	alphahash_fragment: alphahash_fragment,
14116	alphahash_pars_fragment: alphahash_pars_fragment,
14117	alphamap_fragment: alphamap_fragment,
14118	alphamap_pars_fragment: alphamap_pars_fragment,
14119	alphatest_fragment: alphatest_fragment,
14120	alphatest_pars_fragment: alphatest_pars_fragment,
14121	aomap_fragment: aomap_fragment,
14122	aomap_pars_fragment: aomap_pars_fragment,
14123	batching_pars_vertex: batching_pars_vertex,
14124	batching_vertex: batching_vertex,
14125	begin_vertex: begin_vertex,
14126	beginnormal_vertex: beginnormal_vertex,
14127	bsdfs: bsdfs,
14128	iridescence_fragment: iridescence_fragment,
14129	bumpmap_pars_fragment: bumpmap_pars_fragment,
14130	clipping_planes_fragment: clipping_planes_fragment,
14131	clipping_planes_pars_fragment: clipping_planes_pars_fragment,
14132	clipping_planes_pars_vertex: clipping_planes_pars_vertex,
14133	clipping_planes_vertex: clipping_planes_vertex,
14134	color_fragment: color_fragment,
14135	color_pars_fragment: color_pars_fragment,
14136	color_pars_vertex: color_pars_vertex,
14137	color_vertex: color_vertex,
14138	common: common,
14139	cube_uv_reflection_fragment: cube_uv_reflection_fragment,
14140	defaultnormal_vertex: defaultnormal_vertex,
14141	displacementmap_pars_vertex: displacementmap_pars_vertex,
14142	displacementmap_vertex: displacementmap_vertex,
14143	emissivemap_fragment: emissivemap_fragment,
14144	emissivemap_pars_fragment: emissivemap_pars_fragment,
14145	colorspace_fragment: colorspace_fragment,
14146	colorspace_pars_fragment: colorspace_pars_fragment,
14147	envmap_fragment: envmap_fragment,
14148	envmap_common_pars_fragment: envmap_common_pars_fragment,
14149	envmap_pars_fragment: envmap_pars_fragment,
14150	envmap_pars_vertex: envmap_pars_vertex,
14151	envmap_physical_pars_fragment: envmap_physical_pars_fragment,
14152	envmap_vertex: envmap_vertex,
14153	fog_vertex: fog_vertex,
14154	fog_pars_vertex: fog_pars_vertex,
14155	fog_fragment: fog_fragment,
14156	fog_pars_fragment: fog_pars_fragment,
14157	gradientmap_pars_fragment: gradientmap_pars_fragment,
14158	lightmap_fragment: lightmap_fragment,
14159	lightmap_pars_fragment: lightmap_pars_fragment,
14160	lights_lambert_fragment: lights_lambert_fragment,
14161	lights_lambert_pars_fragment: lights_lambert_pars_fragment,
14162	lights_pars_begin: lights_pars_begin,
14163	lights_toon_fragment: lights_toon_fragment,
14164	lights_toon_pars_fragment: lights_toon_pars_fragment,
14165	lights_phong_fragment: lights_phong_fragment,
14166	lights_phong_pars_fragment: lights_phong_pars_fragment,
14167	lights_physical_fragment: lights_physical_fragment,
14168	lights_physical_pars_fragment: lights_physical_pars_fragment,
14169	lights_fragment_begin: lights_fragment_begin,
14170	lights_fragment_maps: lights_fragment_maps,
14171	lights_fragment_end: lights_fragment_end,
14172	logdepthbuf_fragment: logdepthbuf_fragment,
14173	logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
14174	logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
14175	logdepthbuf_vertex: logdepthbuf_vertex,
14176	map_fragment: map_fragment,
14177	map_pars_fragment: map_pars_fragment,
14178	map_particle_fragment: map_particle_fragment,
14179	map_particle_pars_fragment: map_particle_pars_fragment,
14180	metalnessmap_fragment: metalnessmap_fragment,
14181	metalnessmap_pars_fragment: metalnessmap_pars_fragment,
14182	morphcolor_vertex: morphcolor_vertex,
14183	morphnormal_vertex: morphnormal_vertex,
14184	morphtarget_pars_vertex: morphtarget_pars_vertex,
14185	morphtarget_vertex: morphtarget_vertex,
14186	normal_fragment_begin: normal_fragment_begin,
14187	normal_fragment_maps: normal_fragment_maps,
14188	normal_pars_fragment: normal_pars_fragment,
14189	normal_pars_vertex: normal_pars_vertex,
14190	normal_vertex: normal_vertex,
14191	normalmap_pars_fragment: normalmap_pars_fragment,
14192	clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
14193	clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
14194	clearcoat_pars_fragment: clearcoat_pars_fragment,
14195	iridescence_pars_fragment: iridescence_pars_fragment,
14196	opaque_fragment: opaque_fragment,
14197	packing: packing,
14198	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
14199	project_vertex: project_vertex,
14200	dithering_fragment: dithering_fragment,
14201	dithering_pars_fragment: dithering_pars_fragment,
14202	roughnessmap_fragment: roughnessmap_fragment,
14203	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
14204	shadowmap_pars_fragment: shadowmap_pars_fragment,
14205	shadowmap_pars_vertex: shadowmap_pars_vertex,
14206	shadowmap_vertex: shadowmap_vertex,
14207	shadowmask_pars_fragment: shadowmask_pars_fragment,
14208	skinbase_vertex: skinbase_vertex,
14209	skinning_pars_vertex: skinning_pars_vertex,
14210	skinning_vertex: skinning_vertex,
14211	skinnormal_vertex: skinnormal_vertex,
14212	specularmap_fragment: specularmap_fragment,
14213	specularmap_pars_fragment: specularmap_pars_fragment,
14214	tonemapping_fragment: tonemapping_fragment,
14215	tonemapping_pars_fragment: tonemapping_pars_fragment,
14216	transmission_fragment: transmission_fragment,
14217	transmission_pars_fragment: transmission_pars_fragment,
14218	uv_pars_fragment: uv_pars_fragment,
14219	uv_pars_vertex: uv_pars_vertex,
14220	uv_vertex: uv_vertex,
14221	worldpos_vertex: worldpos_vertex,
14222
14223	background_vert: vertex$h,
14224	background_frag: fragment$h,
14225	backgroundCube_vert: vertex$g,
14226	backgroundCube_frag: fragment$g,
14227	cube_vert: vertex$f,
14228	cube_frag: fragment$f,
14229	depth_vert: vertex$e,
14230	depth_frag: fragment$e,
14231	distanceRGBA_vert: vertex$d,
14232	distanceRGBA_frag: fragment$d,
14233	equirect_vert: vertex$c,
14234	equirect_frag: fragment$c,
14235	linedashed_vert: vertex$b,
14236	linedashed_frag: fragment$b,
14237	meshbasic_vert: vertex$a,
14238	meshbasic_frag: fragment$a,
14239	meshlambert_vert: vertex$9,
14240	meshlambert_frag: fragment$9,
14241	meshmatcap_vert: vertex$8,
14242	meshmatcap_frag: fragment$8,
14243	meshnormal_vert: vertex$7,
14244	meshnormal_frag: fragment$7,
14245	meshphong_vert: vertex$6,
14246	meshphong_frag: fragment$6,
14247	meshphysical_vert: vertex$5,
14248	meshphysical_frag: fragment$5,
14249	meshtoon_vert: vertex$4,
14250	meshtoon_frag: fragment$4,
14251	points_vert: vertex$3,
14252	points_frag: fragment$3,
14253	shadow_vert: vertex$2,
14254	shadow_frag: fragment$2,
14255	sprite_vert: vertex$1,
14256	sprite_frag: fragment$1
14257};
14258
14259/**
14260 * Uniforms library for shared webgl shaders
14261 */
14262
14263const UniformsLib = {
14264
14265	common: {
14266
14267		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14268		opacity: { value: 1.0 },
14269
14270		map: { value: null },
14271		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14272
14273		alphaMap: { value: null },
14274		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14275
14276		alphaTest: { value: 0 }
14277
14278	},
14279
14280	specularmap: {
14281
14282		specularMap: { value: null },
14283		specularMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14284
14285	},
14286
14287	envmap: {
14288
14289		envMap: { value: null },
14290		flipEnvMap: { value: - 
vendor: 8,194 bytes, lines 14290-14708
142901 },
14291		reflectivity: { value: 1.0 }, // basic, lambert, phong
14292		ior: { value: 1.5 }, // physical
14293		refractionRatio: { value: 0.98 }, // basic, lambert, phong
14294
14295	},
14296
14297	aomap: {
14298
14299		aoMap: { value: null },
14300		aoMapIntensity: { value: 1 },
14301		aoMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14302
14303	},
14304
14305	lightmap: {
14306
14307		lightMap: { value: null },
14308		lightMapIntensity: { value: 1 },
14309		lightMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14310
14311	},
14312
14313	bumpmap: {
14314
14315		bumpMap: { value: null },
14316		bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14317		bumpScale: { value: 1 }
14318
14319	},
14320
14321	normalmap: {
14322
14323		normalMap: { value: null },
14324		normalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14325		normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }
14326
14327	},
14328
14329	displacementmap: {
14330
14331		displacementMap: { value: null },
14332		displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14333		displacementScale: { value: 1 },
14334		displacementBias: { value: 0 }
14335
14336	},
14337
14338	emissivemap: {
14339
14340		emissiveMap: { value: null },
14341		emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14342
14343	},
14344
14345	metalnessmap: {
14346
14347		metalnessMap: { value: null },
14348		metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14349
14350	},
14351
14352	roughnessmap: {
14353
14354		roughnessMap: { value: null },
14355		roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14356
14357	},
14358
14359	gradientmap: {
14360
14361		gradientMap: { value: null }
14362
14363	},
14364
14365	fog: {
14366
14367		fogDensity: { value: 0.00025 },
14368		fogNear: { value: 1 },
14369		fogFar: { value: 2000 },
14370		fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }
14371
14372	},
14373
14374	lights: {
14375
14376		ambientLightColor: { value: [] },
14377
14378		lightProbe: { value: [] },
14379
14380		directionalLights: { value: [], properties: {
14381			direction: {},
14382			color: {}
14383		} },
14384
14385		directionalLightShadows: { value: [], properties: {
14386			shadowBias: {},
14387			shadowNormalBias: {},
14388			shadowRadius: {},
14389			shadowMapSize: {}
14390		} },
14391
14392		directionalShadowMap: { value: [] },
14393		directionalShadowMatrix: { value: [] },
14394
14395		spotLights: { value: [], properties: {
14396			color: {},
14397			position: {},
14398			direction: {},
14399			distance: {},
14400			coneCos: {},
14401			penumbraCos: {},
14402			decay: {}
14403		} },
14404
14405		spotLightShadows: { value: [], properties: {
14406			shadowBias: {},
14407			shadowNormalBias: {},
14408			shadowRadius: {},
14409			shadowMapSize: {}
14410		} },
14411
14412		spotLightMap: { value: [] },
14413		spotShadowMap: { value: [] },
14414		spotLightMatrix: { value: [] },
14415
14416		pointLights: { value: [], properties: {
14417			color: {},
14418			position: {},
14419			decay: {},
14420			distance: {}
14421		} },
14422
14423		pointLightShadows: { value: [], properties: {
14424			shadowBias: {},
14425			shadowNormalBias: {},
14426			shadowRadius: {},
14427			shadowMapSize: {},
14428			shadowCameraNear: {},
14429			shadowCameraFar: {}
14430		} },
14431
14432		pointShadowMap: { value: [] },
14433		pointShadowMatrix: { value: [] },
14434
14435		hemisphereLights: { value: [], properties: {
14436			direction: {},
14437			skyColor: {},
14438			groundColor: {}
14439		} },
14440
14441		// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
14442		rectAreaLights: { value: [], properties: {
14443			color: {},
14444			position: {},
14445			width: {},
14446			height: {}
14447		} },
14448
14449		ltc_1: { value: null },
14450		ltc_2: { value: null }
14451
14452	},
14453
14454	points: {
14455
14456		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14457		opacity: { value: 1.0 },
14458		size: { value: 1.0 },
14459		scale: { value: 1.0 },
14460		map: { value: null },
14461		alphaMap: { value: null },
14462		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14463		alphaTest: { value: 0 },
14464		uvTransform: { value: /*@__PURE__*/ new Matrix3() }
14465
14466	},
14467
14468	sprite: {
14469
14470		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14471		opacity: { value: 1.0 },
14472		center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },
14473		rotation: { value: 0.0 },
14474		map: { value: null },
14475		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14476		alphaMap: { value: null },
14477		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14478		alphaTest: { value: 0 }
14479
14480	}
14481
14482};
14483
14484const ShaderLib = {
14485
14486	basic: {
14487
14488		uniforms: /*@__PURE__*/ mergeUniforms( [
14489			UniformsLib.common,
14490			UniformsLib.specularmap,
14491			UniformsLib.envmap,
14492			UniformsLib.aomap,
14493			UniformsLib.lightmap,
14494			UniformsLib.fog
14495		] ),
14496
14497		vertexShader: ShaderChunk.meshbasic_vert,
14498		fragmentShader: ShaderChunk.meshbasic_frag
14499
14500	},
14501
14502	lambert: {
14503
14504		uniforms: /*@__PURE__*/ mergeUniforms( [
14505			UniformsLib.common,
14506			UniformsLib.specularmap,
14507			UniformsLib.envmap,
14508			UniformsLib.aomap,
14509			UniformsLib.lightmap,
14510			UniformsLib.emissivemap,
14511			UniformsLib.bumpmap,
14512			UniformsLib.normalmap,
14513			UniformsLib.displacementmap,
14514			UniformsLib.fog,
14515			UniformsLib.lights,
14516			{
14517				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14518			}
14519		] ),
14520
14521		vertexShader: ShaderChunk.meshlambert_vert,
14522		fragmentShader: ShaderChunk.meshlambert_frag
14523
14524	},
14525
14526	phong: {
14527
14528		uniforms: /*@__PURE__*/ mergeUniforms( [
14529			UniformsLib.common,
14530			UniformsLib.specularmap,
14531			UniformsLib.envmap,
14532			UniformsLib.aomap,
14533			UniformsLib.lightmap,
14534			UniformsLib.emissivemap,
14535			UniformsLib.bumpmap,
14536			UniformsLib.normalmap,
14537			UniformsLib.displacementmap,
14538			UniformsLib.fog,
14539			UniformsLib.lights,
14540			{
14541				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14542				specular: { value: /*@__PURE__*/ new Color( 0x111111 ) },
14543				shininess: { value: 30 }
14544			}
14545		] ),
14546
14547		vertexShader: ShaderChunk.meshphong_vert,
14548		fragmentShader: ShaderChunk.meshphong_frag
14549
14550	},
14551
14552	standard: {
14553
14554		uniforms: /*@__PURE__*/ mergeUniforms( [
14555			UniformsLib.common,
14556			UniformsLib.envmap,
14557			UniformsLib.aomap,
14558			UniformsLib.lightmap,
14559			UniformsLib.emissivemap,
14560			UniformsLib.bumpmap,
14561			UniformsLib.normalmap,
14562			UniformsLib.displacementmap,
14563			UniformsLib.roughnessmap,
14564			UniformsLib.metalnessmap,
14565			UniformsLib.fog,
14566			UniformsLib.lights,
14567			{
14568				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14569				roughness: { value: 1.0 },
14570				metalness: { value: 0.0 },
14571				envMapIntensity: { value: 1 } // temporary
14572			}
14573		] ),
14574
14575		vertexShader: ShaderChunk.meshphysical_vert,
14576		fragmentShader: ShaderChunk.meshphysical_frag
14577
14578	},
14579
14580	toon: {
14581
14582		uniforms: /*@__PURE__*/ mergeUniforms( [
14583			UniformsLib.common,
14584			UniformsLib.aomap,
14585			UniformsLib.lightmap,
14586			UniformsLib.emissivemap,
14587			UniformsLib.bumpmap,
14588			UniformsLib.normalmap,
14589			UniformsLib.displacementmap,
14590			UniformsLib.gradientmap,
14591			UniformsLib.fog,
14592			UniformsLib.lights,
14593			{
14594				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14595			}
14596		] ),
14597
14598		vertexShader: ShaderChunk.meshtoon_vert,
14599		fragmentShader: ShaderChunk.meshtoon_frag
14600
14601	},
14602
14603	matcap: {
14604
14605		uniforms: /*@__PURE__*/ mergeUniforms( [
14606			UniformsLib.common,
14607			UniformsLib.bumpmap,
14608			UniformsLib.normalmap,
14609			UniformsLib.displacementmap,
14610			UniformsLib.fog,
14611			{
14612				matcap: { value: null }
14613			}
14614		] ),
14615
14616		vertexShader: ShaderChunk.meshmatcap_vert,
14617		fragmentShader: ShaderChunk.meshmatcap_frag
14618
14619	},
14620
14621	points: {
14622
14623		uniforms: /*@__PURE__*/ mergeUniforms( [
14624			UniformsLib.points,
14625			UniformsLib.fog
14626		] ),
14627
14628		vertexShader: ShaderChunk.points_vert,
14629		fragmentShader: ShaderChunk.points_frag
14630
14631	},
14632
14633	dashed: {
14634
14635		uniforms: /*@__PURE__*/ mergeUniforms( [
14636			UniformsLib.common,
14637			UniformsLib.fog,
14638			{
14639				scale: { value: 1 },
14640				dashSize: { value: 1 },
14641				totalSize: { value: 2 }
14642			}
14643		] ),
14644
14645		vertexShader: ShaderChunk.linedashed_vert,
14646		fragmentShader: ShaderChunk.linedashed_frag
14647
14648	},
14649
14650	depth: {
14651
14652		uniforms: /*@__PURE__*/ mergeUniforms( [
14653			UniformsLib.common,
14654			UniformsLib.displacementmap
14655		] ),
14656
14657		vertexShader: ShaderChunk.depth_vert,
14658		fragmentShader: ShaderChunk.depth_frag
14659
14660	},
14661
14662	normal: {
14663
14664		uniforms: /*@__PURE__*/ mergeUniforms( [
14665			UniformsLib.common,
14666			UniformsLib.bumpmap,
14667			UniformsLib.normalmap,
14668			UniformsLib.displacementmap,
14669			{
14670				opacity: { value: 1.0 }
14671			}
14672		] ),
14673
14674		vertexShader: ShaderChunk.meshnormal_vert,
14675		fragmentShader: ShaderChunk.meshnormal_frag
14676
14677	},
14678
14679	sprite: {
14680
14681		uniforms: /*@__PURE__*/ mergeUniforms( [
14682			UniformsLib.sprite,
14683			UniformsLib.fog
14684		] ),
14685
14686		vertexShader: ShaderChunk.sprite_vert,
14687		fragmentShader: ShaderChunk.sprite_frag
14688
14689	},
14690
14691	background: {
14692
14693		uniforms: {
14694			uvTransform: { value: /*@__PURE__*/ new Matrix3() },
14695			t2D: { value: null },
14696			backgroundIntensity: { value: 1 }
14697		},
14698
14699		vertexShader: ShaderChunk.background_vert,
14700		fragmentShader: ShaderChunk.background_frag
14701
14702	},
14703
14704	backgroundCube: {
14705
14706		uniforms: {
14707			envMap: { value: null },
14708			flipEnvMap: { value: -
vendor: 3,607 bytes, lines 14708-14834
14708 1 },
14709			backgroundBlurriness: { value: 0 },
14710			backgroundIntensity: { value: 1 }
14711		},
14712
14713		vertexShader: ShaderChunk.backgroundCube_vert,
14714		fragmentShader: ShaderChunk.backgroundCube_frag
14715
14716	},
14717
14718	cube: {
14719
14720		uniforms: {
14721			tCube: { value: null },
14722			tFlip: { value: - 1 },
14723			opacity: { value: 1.0 }
14724		},
14725
14726		vertexShader: ShaderChunk.cube_vert,
14727		fragmentShader: ShaderChunk.cube_frag
14728
14729	},
14730
14731	equirect: {
14732
14733		uniforms: {
14734			tEquirect: { value: null },
14735		},
14736
14737		vertexShader: ShaderChunk.equirect_vert,
14738		fragmentShader: ShaderChunk.equirect_frag
14739
14740	},
14741
14742	distanceRGBA: {
14743
14744		uniforms: /*@__PURE__*/ mergeUniforms( [
14745			UniformsLib.common,
14746			UniformsLib.displacementmap,
14747			{
14748				referencePosition: { value: /*@__PURE__*/ new Vector3() },
14749				nearDistance: { value: 1 },
14750				farDistance: { value: 1000 }
14751			}
14752		] ),
14753
14754		vertexShader: ShaderChunk.distanceRGBA_vert,
14755		fragmentShader: ShaderChunk.distanceRGBA_frag
14756
14757	},
14758
14759	shadow: {
14760
14761		uniforms: /*@__PURE__*/ mergeUniforms( [
14762			UniformsLib.lights,
14763			UniformsLib.fog,
14764			{
14765				color: { value: /*@__PURE__*/ new Color( 0x00000 ) },
14766				opacity: { value: 1.0 }
14767			},
14768		] ),
14769
14770		vertexShader: ShaderChunk.shadow_vert,
14771		fragmentShader: ShaderChunk.shadow_frag
14772
14773	}
14774
14775};
14776
14777ShaderLib.physical = {
14778
14779	uniforms: /*@__PURE__*/ mergeUniforms( [
14780		ShaderLib.standard.uniforms,
14781		{
14782			clearcoat: { value: 0 },
14783			clearcoatMap: { value: null },
14784			clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14785			clearcoatNormalMap: { value: null },
14786			clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14787			clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },
14788			clearcoatRoughness: { value: 0 },
14789			clearcoatRoughnessMap: { value: null },
14790			clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14791			iridescence: { value: 0 },
14792			iridescenceMap: { value: null },
14793			iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14794			iridescenceIOR: { value: 1.3 },
14795			iridescenceThicknessMinimum: { value: 100 },
14796			iridescenceThicknessMaximum: { value: 400 },
14797			iridescenceThicknessMap: { value: null },
14798			iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14799			sheen: { value: 0 },
14800			sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14801			sheenColorMap: { value: null },
14802			sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14803			sheenRoughness: { value: 1 },
14804			sheenRoughnessMap: { value: null },
14805			sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14806			transmission: { value: 0 },
14807			transmissionMap: { value: null },
14808			transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14809			transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },
14810			transmissionSamplerMap: { value: null },
14811			thickness: { value: 0 },
14812			thicknessMap: { value: null },
14813			thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14814			attenuationDistance: { value: 0 },
14815			attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14816			specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },
14817			specularColorMap: { value: null },
14818			specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14819			specularIntensity: { value: 1 },
14820			specularIntensityMap: { value: null },
14821			specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14822			anisotropyVector: { value: /*@__PURE__*/ new Vector2() },
14823			anisotropyMap: { value: null },
14824			anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14825		}
14826	] ),
14827
14828	vertexShader: ShaderChunk.meshphysical_vert,
14829	fragmentShader: ShaderChunk.meshphysical_frag
14830
14831};
14832
14833const _rgb = { r: 0, b: 0, g: 0 };
14834
vendor: 2,765 bytes, lines 14835-14933
14835function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) {
14836
14837	const clearColor = new Color( 0x000000 );
14838	let clearAlpha = alpha === true ? 0 : 1;
14839
14840	let planeMesh;
14841	let boxMesh;
14842
14843	let currentBackground = null;
14844	let currentBackgroundVersion = 0;
14845	let currentTonemapping = null;
14846
14847	function render( renderList, scene ) {
14848
14849		let forceClear = false;
14850		let background = scene.isScene === true ? scene.background : null;
14851
14852		if ( background && background.isTexture ) {
14853
14854			const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background
14855			background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );
14856
14857		}
14858
14859		if ( background === null ) {
14860
14861			setClear( clearColor, clearAlpha );
14862
14863		} else if ( background && background.isColor ) {
14864
14865			setClear( background, 1 );
14866			forceClear = true;
14867
14868		}
14869
14870		const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();
14871
14872		if ( environmentBlendMode === 'additive' ) {
14873
14874			state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
14875
14876		} else if ( environmentBlendMode === 'alpha-blend' ) {
14877
14878			state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
14879
14880		}
14881
14882		if ( renderer.autoClear || forceClear ) {
14883
14884			renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
14885
14886		}
14887
14888		if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {
14889
14890			if ( boxMesh === undefined ) {
14891
14892				boxMesh = new Mesh(
14893					new BoxGeometry( 1, 1, 1 ),
14894					new ShaderMaterial( {
14895						name: 'BackgroundCubeMaterial',
14896						uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
14897						vertexShader: ShaderLib.backgroundCube.vertexShader,
14898						fragmentShader: ShaderLib.backgroundCube.fragmentShader,
14899						side: BackSide,
14900						depthTest: false,
14901						depthWrite: false,
14902						fog: false
14903					} )
14904				);
14905
14906				boxMesh.geometry.deleteAttribute( 'normal' );
14907				boxMesh.geometry.deleteAttribute( 'uv' );
14908
14909				boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
14910
14911					this.matrixWorld.copyPosition( camera.matrixWorld );
14912
14913				};
14914
14915				// add "envMap" material property so the renderer can evaluate it like for built-in materials
14916				Object.defineProperty( boxMesh.material, 'envMap', {
14917
14918					get: function () {
14919
14920						return this.uniforms.envMap.value;
14921
14922					}
14923
14924				} );
14925
14926				objects.update( boxMesh );
14927
14928			}
14929
14930			boxMesh.material.uniforms.envMap.value = background;
14931			boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;
14932			boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
14933			boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity
vendor: 25,376 bytes, lines 14933-16100
14933;
14934			boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14935
14936			if ( currentBackground !== background ||
14937				currentBackgroundVersion !== background.version ||
14938				currentTonemapping !== renderer.toneMapping ) {
14939
14940				boxMesh.material.needsUpdate = true;
14941
14942				currentBackground = background;
14943				currentBackgroundVersion = background.version;
14944				currentTonemapping = renderer.toneMapping;
14945
14946			}
14947
14948			boxMesh.layers.enableAll();
14949
14950			// push to the pre-sorted opaque render list
14951			renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
14952
14953		} else if ( background && background.isTexture ) {
14954
14955			if ( planeMesh === undefined ) {
14956
14957				planeMesh = new Mesh(
14958					new PlaneGeometry( 2, 2 ),
14959					new ShaderMaterial( {
14960						name: 'BackgroundMaterial',
14961						uniforms: cloneUniforms( ShaderLib.background.uniforms ),
14962						vertexShader: ShaderLib.background.vertexShader,
14963						fragmentShader: ShaderLib.background.fragmentShader,
14964						side: FrontSide,
14965						depthTest: false,
14966						depthWrite: false,
14967						fog: false
14968					} )
14969				);
14970
14971				planeMesh.geometry.deleteAttribute( 'normal' );
14972
14973				// add "map" material property so the renderer can evaluate it like for built-in materials
14974				Object.defineProperty( planeMesh.material, 'map', {
14975
14976					get: function () {
14977
14978						return this.uniforms.t2D.value;
14979
14980					}
14981
14982				} );
14983
14984				objects.update( planeMesh );
14985
14986			}
14987
14988			planeMesh.material.uniforms.t2D.value = background;
14989			planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
14990			planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14991
14992			if ( background.matrixAutoUpdate === true ) {
14993
14994				background.updateMatrix();
14995
14996			}
14997
14998			planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
14999
15000			if ( currentBackground !== background ||
15001				currentBackgroundVersion !== background.version ||
15002				currentTonemapping !== renderer.toneMapping ) {
15003
15004				planeMesh.material.needsUpdate = true;
15005
15006				currentBackground = background;
15007				currentBackgroundVersion = background.version;
15008				currentTonemapping = renderer.toneMapping;
15009
15010			}
15011
15012			planeMesh.layers.enableAll();
15013
15014			// push to the pre-sorted opaque render list
15015			renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
15016
15017		}
15018
15019	}
15020
15021	function setClear( color, alpha ) {
15022
15023		color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );
15024
15025		state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );
15026
15027	}
15028
15029	return {
15030
15031		getClearColor: function () {
15032
15033			return clearColor;
15034
15035		},
15036		setClearColor: function ( color, alpha = 1 ) {
15037
15038			clearColor.set( color );
15039			clearAlpha = alpha;
15040			setClear( clearColor, clearAlpha );
15041
15042		},
15043		getClearAlpha: function () {
15044
15045			return clearAlpha;
15046
15047		},
15048		setClearAlpha: function ( alpha ) {
15049
15050			clearAlpha = alpha;
15051			setClear( clearColor, clearAlpha );
15052
15053		},
15054		render: render
15055
15056	};
15057
15058}
15059
15060function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
15061
15062	const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15063
15064	const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
15065	const vaoAvailable = capabilities.isWebGL2 || extension !== null;
15066
15067	const bindingStates = {};
15068
15069	const defaultState = createBindingState( null );
15070	let currentState = defaultState;
15071	let forceUpdate = false;
15072
15073	function setup( object, material, program, geometry, index ) {
15074
15075		let updateBuffers = false;
15076
15077		if ( vaoAvailable ) {
15078
15079			const state = getBindingState( geometry, program, material );
15080
15081			if ( currentState !== state ) {
15082
15083				currentState = state;
15084				bindVertexArrayObject( currentState.object );
15085
15086			}
15087
15088			updateBuffers = needsUpdate( object, geometry, program, index );
15089
15090			if ( updateBuffers ) saveCache( object, geometry, program, index );
15091
15092		} else {
15093
15094			const wireframe = ( material.wireframe === true );
15095
15096			if ( currentState.geometry !== geometry.id ||
15097				currentState.program !== program.id ||
15098				currentState.wireframe !== wireframe ) {
15099
15100				currentState.geometry = geometry.id;
15101				currentState.program = program.id;
15102				currentState.wireframe = wireframe;
15103
15104				updateBuffers = true;
15105
15106			}
15107
15108		}
15109
15110		if ( index !== null ) {
15111
15112			attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
15113
15114		}
15115
15116		if ( updateBuffers || forceUpdate ) {
15117
15118			forceUpdate = false;
15119
15120			setupVertexAttributes( object, material, program, geometry );
15121
15122			if ( index !== null ) {
15123
15124				gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );
15125
15126			}
15127
15128		}
15129
15130	}
15131
15132	function createVertexArrayObject() {
15133
15134		if ( capabilities.isWebGL2 ) return gl.createVertexArray();
15135
15136		return extension.createVertexArrayOES();
15137
15138	}
15139
15140	function bindVertexArrayObject( vao ) {
15141
15142		if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
15143
15144		return extension.bindVertexArrayOES( vao );
15145
15146	}
15147
15148	function deleteVertexArrayObject( vao ) {
15149
15150		if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
15151
15152		return extension.deleteVertexArrayOES( vao );
15153
15154	}
15155
15156	function getBindingState( geometry, program, material ) {
15157
15158		const wireframe = ( material.wireframe === true );
15159
15160		let programMap = bindingStates[ geometry.id ];
15161
15162		if ( programMap === undefined ) {
15163
15164			programMap = {};
15165			bindingStates[ geometry.id ] = programMap;
15166
15167		}
15168
15169		let stateMap = programMap[ program.id ];
15170
15171		if ( stateMap === undefined ) {
15172
15173			stateMap = {};
15174			programMap[ program.id ] = stateMap;
15175
15176		}
15177
15178		let state = stateMap[ wireframe ];
15179
15180		if ( state === undefined ) {
15181
15182			state = createBindingState( createVertexArrayObject() );
15183			stateMap[ wireframe ] = state;
15184
15185		}
15186
15187		return state;
15188
15189	}
15190
15191	function createBindingState( vao ) {
15192
15193		const newAttributes = [];
15194		const enabledAttributes = [];
15195		const attributeDivisors = [];
15196
15197		for ( let i = 0; i < maxVertexAttributes; i ++ ) {
15198
15199			newAttributes[ i ] = 0;
15200			enabledAttributes[ i ] = 0;
15201			attributeDivisors[ i ] = 0;
15202
15203		}
15204
15205		return {
15206
15207			// for backward compatibility on non-VAO support browser
15208			geometry: null,
15209			program: null,
15210			wireframe: false,
15211
15212			newAttributes: newAttributes,
15213			enabledAttributes: enabledAttributes,
15214			attributeDivisors: attributeDivisors,
15215			object: vao,
15216			attributes: {},
15217			index: null
15218
15219		};
15220
15221	}
15222
15223	function needsUpdate( object, geometry, program, index ) {
15224
15225		const cachedAttributes = currentState.attributes;
15226		const geometryAttributes = geometry.attributes;
15227
15228		let attributesNum = 0;
15229
15230		const programAttributes = program.getAttributes();
15231
15232		for ( const name in programAttributes ) {
15233
15234			const programAttribute = programAttributes[ name ];
15235
15236			if ( programAttribute.location >= 0 ) {
15237
15238				const cachedAttribute = cachedAttributes[ name ];
15239				let geometryAttribute = geometryAttributes[ name ];
15240
15241				if ( geometryAttribute === undefined ) {
15242
15243					if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15244					if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15245
15246				}
15247
15248				if ( cachedAttribute === undefined ) return true;
15249
15250				if ( cachedAttribute.attribute !== geometryAttribute ) return true;
15251
15252				if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;
15253
15254				attributesNum ++;
15255
15256			}
15257
15258		}
15259
15260		if ( currentState.attributesNum !== attributesNum ) return true;
15261
15262		if ( currentState.index !== index ) return true;
15263
15264		return false;
15265
15266	}
15267
15268	function saveCache( object, geometry, program, index ) {
15269
15270		const cache = {};
15271		const attributes = geometry.attributes;
15272		let attributesNum = 0;
15273
15274		const programAttributes = program.getAttributes();
15275
15276		for ( const name in programAttributes ) {
15277
15278			const programAttribute = programAttributes[ name ];
15279
15280			if ( programAttribute.location >= 0 ) {
15281
15282				let attribute = attributes[ name ];
15283
15284				if ( attribute === undefined ) {
15285
15286					if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;
15287					if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;
15288
15289				}
15290
15291				const data = {};
15292				data.attribute = attribute;
15293
15294				if ( attribute && attribute.data ) {
15295
15296					data.data = attribute.data;
15297
15298				}
15299
15300				cache[ name ] = data;
15301
15302				attributesNum ++;
15303
15304			}
15305
15306		}
15307
15308		currentState.attributes = cache;
15309		currentState.attributesNum = attributesNum;
15310
15311		currentState.index = index;
15312
15313	}
15314
15315	function initAttributes() {
15316
15317		const newAttributes = currentState.newAttributes;
15318
15319		for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
15320
15321			newAttributes[ i ] = 0;
15322
15323		}
15324
15325	}
15326
15327	function enableAttribute( attribute ) {
15328
15329		enableAttributeAndDivisor( attribute, 0 );
15330
15331	}
15332
15333	function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
15334
15335		const newAttributes = currentState.newAttributes;
15336		const enabledAttributes = currentState.enabledAttributes;
15337		const attributeDivisors = currentState.attributeDivisors;
15338
15339		newAttributes[ attribute ] = 1;
15340
15341		if ( enabledAttributes[ attribute ] === 0 ) {
15342
15343			gl.enableVertexAttribArray( attribute );
15344			enabledAttributes[ attribute ] = 1;
15345
15346		}
15347
15348		if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
15349
15350			const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
15351
15352			extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
15353			attributeDivisors[ attribute ] = meshPerAttribute;
15354
15355		}
15356
15357	}
15358
15359	function disableUnusedAttributes() {
15360
15361		const newAttributes = currentState.newAttributes;
15362		const enabledAttributes = currentState.enabledAttributes;
15363
15364		for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
15365
15366			if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
15367
15368				gl.disableVertexAttribArray( i );
15369				enabledAttributes[ i ] = 0;
15370
15371			}
15372
15373		}
15374
15375	}
15376
15377	function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {
15378
15379		if ( integer === true ) {
15380
15381			gl.vertexAttribIPointer( index, size, type, stride, offset );
15382
15383		} else {
15384
15385			gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
15386
15387		}
15388
15389	}
15390
15391	function setupVertexAttributes( object, material, program, geometry ) {
15392
15393		if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
15394
15395			if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
15396
15397		}
15398
15399		initAttributes();
15400
15401		const geometryAttributes = geometry.attributes;
15402
15403		const programAttributes = program.getAttributes();
15404
15405		const materialDefaultAttributeValues = material.defaultAttributeValues;
15406
15407		for ( const name in programAttributes ) {
15408
15409			const programAttribute = programAttributes[ name ];
15410
15411			if ( programAttribute.location >= 0 ) {
15412
15413				let geometryAttribute = geometryAttributes[ name ];
15414
15415				if ( geometryAttribute === undefined ) {
15416
15417					if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15418					if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15419
15420				}
15421
15422				if ( geometryAttribute !== undefined ) {
15423
15424					const normalized = geometryAttribute.normalized;
15425					const size = geometryAttribute.itemSize;
15426
15427					const attribute = attributes.get( geometryAttribute );
15428
15429					// TODO Attribute may not be available on context restore
15430
15431					if ( attribute === undefined ) continue;
15432
15433					const buffer = attribute.buffer;
15434					const type = attribute.type;
15435					const bytesPerElement = attribute.bytesPerElement;
15436
15437					// check for integer attributes (WebGL 2 only)
15438
15439					const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) );
15440
15441					if ( geometryAttribute.isInterleavedBufferAttribute ) {
15442
15443						const data = geometryAttribute.data;
15444						const stride = data.stride;
15445						const offset = geometryAttribute.offset;
15446
15447						if ( data.isInstancedInterleavedBuffer ) {
15448
15449							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15450
15451								enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );
15452
15453							}
15454
15455							if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15456
15457								geometry._maxInstanceCount = data.meshPerAttribute * data.count;
15458
15459							}
15460
15461						} else {
15462
15463							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15464
15465								enableAttribute( programAttribute.location + i );
15466
15467							}
15468
15469						}
15470
15471						gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15472
15473						for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15474
15475							vertexAttribPointer(
15476								programAttribute.location + i,
15477								size / programAttribute.locationSize,
15478								type,
15479								normalized,
15480								stride * bytesPerElement,
15481								( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,
15482								integer
15483							);
15484
15485						}
15486
15487					} else {
15488
15489						if ( geometryAttribute.isInstancedBufferAttribute ) {
15490
15491							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15492
15493								enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );
15494
15495							}
15496
15497							if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15498
15499								geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
15500
15501							}
15502
15503						} else {
15504
15505							for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15506
15507								enableAttribute( programAttribute.location + i );
15508
15509							}
15510
15511						}
15512
15513						gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15514
15515						for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15516
15517							vertexAttribPointer(
15518								programAttribute.location + i,
15519								size / programAttribute.locationSize,
15520								type,
15521								normalized,
15522								size * bytesPerElement,
15523								( size / programAttribute.locationSize ) * i * bytesPerElement,
15524								integer
15525							);
15526
15527						}
15528
15529					}
15530
15531				} else if ( materialDefaultAttributeValues !== undefined ) {
15532
15533					const value = materialDefaultAttributeValues[ name ];
15534
15535					if ( value !== undefined ) {
15536
15537						switch ( value.length ) {
15538
15539							case 2:
15540								gl.vertexAttrib2fv( programAttribute.location, value );
15541								break;
15542
15543							case 3:
15544								gl.vertexAttrib3fv( programAttribute.location, value );
15545								break;
15546
15547							case 4:
15548								gl.vertexAttrib4fv( programAttribute.location, value );
15549								break;
15550
15551							default:
15552								gl.vertexAttrib1fv( programAttribute.location, value );
15553
15554						}
15555
15556					}
15557
15558				}
15559
15560			}
15561
15562		}
15563
15564		disableUnusedAttributes();
15565
15566	}
15567
15568	function dispose() {
15569
15570		reset();
15571
15572		for ( const geometryId in bindingStates ) {
15573
15574			const programMap = bindingStates[ geometryId ];
15575
15576			for ( const programId in programMap ) {
15577
15578				const stateMap = programMap[ programId ];
15579
15580				for ( const wireframe in stateMap ) {
15581
15582					deleteVertexArrayObject( stateMap[ wireframe ].object );
15583
15584					delete stateMap[ wireframe ];
15585
15586				}
15587
15588				delete programMap[ programId ];
15589
15590			}
15591
15592			delete bindingStates[ geometryId ];
15593
15594		}
15595
15596	}
15597
15598	function releaseStatesOfGeometry( geometry ) {
15599
15600		if ( bindingStates[ geometry.id ] === undefined ) return;
15601
15602		const programMap = bindingStates[ geometry.id ];
15603
15604		for ( const programId in programMap ) {
15605
15606			const stateMap = programMap[ programId ];
15607
15608			for ( const wireframe in stateMap ) {
15609
15610				deleteVertexArrayObject( stateMap[ wireframe ].object );
15611
15612				delete stateMap[ wireframe ];
15613
15614			}
15615
15616			delete programMap[ programId ];
15617
15618		}
15619
15620		delete bindingStates[ geometry.id ];
15621
15622	}
15623
15624	function releaseStatesOfProgram( program ) {
15625
15626		for ( const geometryId in bindingStates ) {
15627
15628			const programMap = bindingStates[ geometryId ];
15629
15630			if ( programMap[ program.id ] === undefined ) continue;
15631
15632			const stateMap = programMap[ program.id ];
15633
15634			for ( const wireframe in stateMap ) {
15635
15636				deleteVertexArrayObject( stateMap[ wireframe ].object );
15637
15638				delete stateMap[ wireframe ];
15639
15640			}
15641
15642			delete programMap[ program.id ];
15643
15644		}
15645
15646	}
15647
15648	function reset() {
15649
15650		resetDefaultState();
15651		forceUpdate = true;
15652
15653		if ( currentState === defaultState ) return;
15654
15655		currentState = defaultState;
15656		bindVertexArrayObject( currentState.object );
15657
15658	}
15659
15660	// for backward-compatibility
15661
15662	function resetDefaultState() {
15663
15664		defaultState.geometry = null;
15665		defaultState.program = null;
15666		defaultState.wireframe = false;
15667
15668	}
15669
15670	return {
15671
15672		setup: setup,
15673		reset: reset,
15674		resetDefaultState: resetDefaultState,
15675		dispose: dispose,
15676		releaseStatesOfGeometry: releaseStatesOfGeometry,
15677		releaseStatesOfProgram: releaseStatesOfProgram,
15678
15679		initAttributes: initAttributes,
15680		enableAttribute: enableAttribute,
15681		disableUnusedAttributes: disableUnusedAttributes
15682
15683	};
15684
15685}
15686
15687function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
15688
15689	const isWebGL2 = capabilities.isWebGL2;
15690
15691	let mode;
15692
15693	function setMode( value ) {
15694
15695		mode = value;
15696
15697	}
15698
15699	function render( start, count ) {
15700
15701		gl.drawArrays( mode, start, count );
15702
15703		info.update( count, mode, 1 );
15704
15705	}
15706
15707	function renderInstances( start, count, primcount ) {
15708
15709		if ( primcount === 0 ) return;
15710
15711		let extension, methodName;
15712
15713		if ( isWebGL2 ) {
15714
15715			extension = gl;
15716			methodName = 'drawArraysInstanced';
15717
15718		} else {
15719
15720			extension = extensions.get( 'ANGLE_instanced_arrays' );
15721			methodName = 'drawArraysInstancedANGLE';
15722
15723			if ( extension === null ) {
15724
15725				console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
15726				return;
15727
15728			}
15729
15730		}
15731
15732		extension[ methodName ]( mode, start, count, primcount );
15733
15734		info.update( count, mode, primcount );
15735
15736	}
15737
15738	function renderMultiDraw( starts, counts, drawCount ) {
15739
15740		if ( drawCount === 0 ) return;
15741
15742		const extension = extensions.get( 'WEBGL_multi_draw' );
15743		if ( extension === null ) {
15744
15745			for ( let i = 0; i < drawCount; i ++ ) {
15746
15747				this.render( starts[ i ], counts[ i ] );
15748
15749			}
15750
15751		} else {
15752
15753			extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );
15754
15755			let elementCount = 0;
15756			for ( let i = 0; i < drawCount; i ++ ) {
15757
15758				elementCount += counts[ i ];
15759
15760			}
15761
15762			info.update( elementCount, mode, 1 );
15763
15764		}
15765
15766	}
15767
15768	//
15769
15770	this.setMode = setMode;
15771	this.render = render;
15772	this.renderInstances = renderInstances;
15773	this.renderMultiDraw = renderMultiDraw;
15774
15775}
15776
15777function WebGLCapabilities( gl, extensions, parameters ) {
15778
15779	let maxAnisotropy;
15780
15781	function getMaxAnisotropy() {
15782
15783		if ( maxAnisotropy !== undefined ) return maxAnisotropy;
15784
15785		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
15786
15787			const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
15788
15789			maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
15790
15791		} else {
15792
15793			maxAnisotropy = 0;
15794
15795		}
15796
15797		return maxAnisotropy;
15798
15799	}
15800
15801	function getMaxPrecision( precision ) {
15802
15803		if ( precision === 'highp' ) {
15804
15805			if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
15806				gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
15807
15808				return 'highp';
15809
15810			}
15811
15812			precision = 'mediump';
15813
15814		}
15815
15816		if ( precision === 'mediump' ) {
15817
15818			if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
15819				gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
15820
15821				return 'mediump';
15822
15823			}
15824
15825		}
15826
15827		return 'lowp';
15828
15829	}
15830
15831	const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext';
15832
15833	let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
15834	const maxPrecision = getMaxPrecision( precision );
15835
15836	if ( maxPrecision !== precision ) {
15837
15838		console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
15839		precision = maxPrecision;
15840
15841	}
15842
15843	const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' );
15844
15845	const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
15846
15847	const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
15848	const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
15849	const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
15850	const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
15851
15852	const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15853	const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
15854	const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
15855	const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
15856
15857	const vertexTextures = maxVertexTextures > 0;
15858	const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' );
15859	const floatVertexTextures = vertexTextures && floatFragmentTextures;
15860
15861	const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0;
15862
15863	return {
15864
15865		isWebGL2: isWebGL2,
15866
15867		drawBuffers: drawBuffers,
15868
15869		getMaxAnisotropy: getMaxAnisotropy,
15870		getMaxPrecision: getMaxPrecision,
15871
15872		precision: precision,
15873		logarithmicDepthBuffer: logarithmicDepthBuffer,
15874
15875		maxTextures: maxTextures,
15876		maxVertexTextures: maxVertexTextures,
15877		maxTextureSize: maxTextureSize,
15878		maxCubemapSize: maxCubemapSize,
15879
15880		maxAttributes: maxAttributes,
15881		maxVertexUniforms: maxVertexUniforms,
15882		maxVaryings: maxVaryings,
15883		maxFragmentUniforms: maxFragmentUniforms,
15884
15885		vertexTextures: vertexTextures,
15886		floatFragmentTextures: floatFragmentTextures,
15887		floatVertexTextures: floatVertexTextures,
15888
15889		maxSamples: maxSamples
15890
15891	};
15892
15893}
15894
15895function WebGLClipping( properties ) {
15896
15897	const scope = this;
15898
15899	let globalState = null,
15900		numGlobalPlanes = 0,
15901		localClippingEnabled = false,
15902		renderingShadows = false;
15903
15904	const plane = new Plane(),
15905		viewNormalMatrix = new Matrix3(),
15906
15907		uniform = { value: null, needsUpdate: false };
15908
15909	this.uniform = uniform;
15910	this.numPlanes = 0;
15911	this.numIntersection = 0;
15912
15913	this.init = function ( planes, enableLocalClipping ) {
15914
15915		const enabled =
15916			planes.length !== 0 ||
15917			enableLocalClipping ||
15918			// enable state of previous frame - the clipping code has to
15919			// run another frame in order to reset the state:
15920			numGlobalPlanes !== 0 ||
15921			localClippingEnabled;
15922
15923		localClippingEnabled = enableLocalClipping;
15924
15925		numGlobalPlanes = planes.length;
15926
15927		return enabled;
15928
15929	};
15930
15931	this.beginShadows = function () {
15932
15933		renderingShadows = true;
15934		projectPlanes( null );
15935
15936	};
15937
15938	this.endShadows = function () {
15939
15940		renderingShadows = false;
15941
15942	};
15943
15944	this.setGlobalState = function ( planes, camera ) {
15945
15946		globalState = projectPlanes( planes, camera, 0 );
15947
15948	};
15949
15950	this.setState = function ( material, camera, useCache ) {
15951
15952		const planes = material.clippingPlanes,
15953			clipIntersection = material.clipIntersection,
15954			clipShadows = material.clipShadows;
15955
15956		const materialProperties = properties.get( material );
15957
15958		if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
15959
15960			// there's no local clipping
15961
15962			if ( renderingShadows ) {
15963
15964				// there's no global clipping
15965
15966				projectPlanes( null );
15967
15968			} else {
15969
15970				resetGlobalState();
15971
15972			}
15973
15974		} else {
15975
15976			const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
15977				lGlobal = nGlobal * 4;
15978
15979			let dstArray = materialProperties.clippingState || null;
15980
15981			uniform.value = dstArray; // ensure unique state
15982
15983			dstArray = projectPlanes( planes, camera, lGlobal, useCache );
15984
15985			for ( let i = 0; i !== lGlobal; ++ i ) {
15986
15987				dstArray[ i ] = globalState[ i ];
15988
15989			}
15990
15991			materialProperties.clippingState = dstArray;
15992			this.numIntersection = clipIntersection ? this.numPlanes : 0;
15993			this.numPlanes += nGlobal;
15994
15995		}
15996
15997
15998	};
15999
16000	function resetGlobalState() {
16001
16002		if ( uniform.value !== globalState ) {
16003
16004			uniform.value = globalState;
16005			uniform.needsUpdate = numGlobalPlanes > 0;
16006
16007		}
16008
16009		scope.numPlanes = numGlobalPlanes;
16010		scope.numIntersection = 0;
16011
16012	}
16013
16014	function projectPlanes( planes, camera, dstOffset, skipTransform ) {
16015
16016		const nPlanes = planes !== null ? planes.length : 0;
16017		let dstArray = null;
16018
16019		if ( nPlanes !== 0 ) {
16020
16021			dstArray = uniform.value;
16022
16023			if ( skipTransform !== true || dstArray === null ) {
16024
16025				const flatSize = dstOffset + nPlanes * 4,
16026					viewMatrix = camera.matrixWorldInverse;
16027
16028				viewNormalMatrix.getNormalMatrix( viewMatrix );
16029
16030				if ( dstArray === null || dstArray.length < flatSize ) {
16031
16032					dstArray = new Float32Array( flatSize );
16033
16034				}
16035
16036				for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
16037
16038					plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
16039
16040					plane.normal.toArray( dstArray, i4 );
16041					dstArray[ i4 + 3 ] = plane.constant;
16042
16043				}
16044
16045			}
16046
16047			uniform.value = dstArray;
16048			uniform.needsUpdate = true;
16049
16050		}
16051
16052		scope.numPlanes = nPlanes;
16053		scope.numIntersection = 0;
16054
16055		return dstArray;
16056
16057	}
16058
16059}
16060
16061function WebGLCubeMaps( renderer ) {
16062
16063	let cubemaps = new WeakMap();
16064
16065	function mapTextureMapping( texture, mapping ) {
16066
16067		if ( mapping === EquirectangularReflectionMapping ) {
16068
16069			texture.mapping = CubeReflectionMapping;
16070
16071		} else if ( mapping === EquirectangularRefractionMapping ) {
16072
16073			texture.mapping = CubeRefractionMapping;
16074
16075		}
16076
16077		return texture;
16078
16079	}
16080
16081	function get( texture ) {
16082
16083		if ( texture && texture.isTexture ) {
16084
16085			const mapping = texture.mapping;
16086
16087			if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
16088
16089				if ( cubemaps.has( texture ) ) {
16090
16091					const cubemap = cubemaps.get( texture ).texture;
16092					return mapTextureMapping( cubemap, texture.mapping );
16093
16094				} else {
16095
16096					const image = texture.image;
16097
16098					if ( image && image.height > 0 ) {
16099
16100						const renderTarget = new WebGLCubeRenderTarget( image.height 
vendor: 20,344 bytes, lines 16100-16931
16100/ 2 );
16101						renderTarget.fromEquirectangularTexture( renderer, texture );
16102						cubemaps.set( texture, renderTarget );
16103
16104						texture.addEventListener( 'dispose', onTextureDispose );
16105
16106						return mapTextureMapping( renderTarget.texture, texture.mapping );
16107
16108					} else {
16109
16110						// image not yet ready. try the conversion next frame
16111
16112						return null;
16113
16114					}
16115
16116				}
16117
16118			}
16119
16120		}
16121
16122		return texture;
16123
16124	}
16125
16126	function onTextureDispose( event ) {
16127
16128		const texture = event.target;
16129
16130		texture.removeEventListener( 'dispose', onTextureDispose );
16131
16132		const cubemap = cubemaps.get( texture );
16133
16134		if ( cubemap !== undefined ) {
16135
16136			cubemaps.delete( texture );
16137			cubemap.dispose();
16138
16139		}
16140
16141	}
16142
16143	function dispose() {
16144
16145		cubemaps = new WeakMap();
16146
16147	}
16148
16149	return {
16150		get: get,
16151		dispose: dispose
16152	};
16153
16154}
16155
16156class OrthographicCamera extends Camera {
16157
16158	constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
16159
16160		super();
16161
16162		this.isOrthographicCamera = true;
16163
16164		this.type = 'OrthographicCamera';
16165
16166		this.zoom = 1;
16167		this.view = null;
16168
16169		this.left = left;
16170		this.right = right;
16171		this.top = top;
16172		this.bottom = bottom;
16173
16174		this.near = near;
16175		this.far = far;
16176
16177		this.updateProjectionMatrix();
16178
16179	}
16180
16181	copy( source, recursive ) {
16182
16183		super.copy( source, recursive );
16184
16185		this.left = source.left;
16186		this.right = source.right;
16187		this.top = source.top;
16188		this.bottom = source.bottom;
16189		this.near = source.near;
16190		this.far = source.far;
16191
16192		this.zoom = source.zoom;
16193		this.view = source.view === null ? null : Object.assign( {}, source.view );
16194
16195		return this;
16196
16197	}
16198
16199	setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
16200
16201		if ( this.view === null ) {
16202
16203			this.view = {
16204				enabled: true,
16205				fullWidth: 1,
16206				fullHeight: 1,
16207				offsetX: 0,
16208				offsetY: 0,
16209				width: 1,
16210				height: 1
16211			};
16212
16213		}
16214
16215		this.view.enabled = true;
16216		this.view.fullWidth = fullWidth;
16217		this.view.fullHeight = fullHeight;
16218		this.view.offsetX = x;
16219		this.view.offsetY = y;
16220		this.view.width = width;
16221		this.view.height = height;
16222
16223		this.updateProjectionMatrix();
16224
16225	}
16226
16227	clearViewOffset() {
16228
16229		if ( this.view !== null ) {
16230
16231			this.view.enabled = false;
16232
16233		}
16234
16235		this.updateProjectionMatrix();
16236
16237	}
16238
16239	updateProjectionMatrix() {
16240
16241		const dx = ( this.right - this.left ) / ( 2 * this.zoom );
16242		const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
16243		const cx = ( this.right + this.left ) / 2;
16244		const cy = ( this.top + this.bottom ) / 2;
16245
16246		let left = cx - dx;
16247		let right = cx + dx;
16248		let top = cy + dy;
16249		let bottom = cy - dy;
16250
16251		if ( this.view !== null && this.view.enabled ) {
16252
16253			const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
16254			const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
16255
16256			left += scaleW * this.view.offsetX;
16257			right = left + scaleW * this.view.width;
16258			top -= scaleH * this.view.offsetY;
16259			bottom = top - scaleH * this.view.height;
16260
16261		}
16262
16263		this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem );
16264
16265		this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
16266
16267	}
16268
16269	toJSON( meta ) {
16270
16271		const data = super.toJSON( meta );
16272
16273		data.object.zoom = this.zoom;
16274		data.object.left = this.left;
16275		data.object.right = this.right;
16276		data.object.top = this.top;
16277		data.object.bottom = this.bottom;
16278		data.object.near = this.near;
16279		data.object.far = this.far;
16280
16281		if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
16282
16283		return data;
16284
16285	}
16286
16287}
16288
16289const LOD_MIN = 4;
16290
16291// The standard deviations (radians) associated with the extra mips. These are
16292// chosen to approximate a Trowbridge-Reitz distribution function times the
16293// geometric shadowing function. These sigma values squared must match the
16294// variance #defines in cube_uv_reflection_fragment.glsl.js.
16295const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
16296
16297// The maximum length of the blur for loop. Smaller sigmas will use fewer
16298// samples and exit early, but not recompile the shader.
16299const MAX_SAMPLES = 20;
16300
16301const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
16302const _clearColor = /*@__PURE__*/ new Color();
16303let _oldTarget = null;
16304let _oldActiveCubeFace = 0;
16305let _oldActiveMipmapLevel = 0;
16306
16307// Golden Ratio
16308const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
16309const INV_PHI = 1 / PHI;
16310
16311// Vertices of a dodecahedron (except the opposites, which represent the
16312// same axis), used as axis directions evenly spread on a sphere.
16313const _axisDirections = [
16314	/*@__PURE__*/ new Vector3( 1, 1, 1 ),
16315	/*@__PURE__*/ new Vector3( - 1, 1, 1 ),
16316	/*@__PURE__*/ new Vector3( 1, 1, - 1 ),
16317	/*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
16318	/*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
16319	/*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
16320	/*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
16321	/*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
16322	/*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
16323	/*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
16324
16325/**
16326 * This class generates a Prefiltered, Mipmapped Radiance Environment Map
16327 * (PMREM) from a cubeMap environment texture. This allows different levels of
16328 * blur to be quickly accessed based on material roughness. It is packed into a
16329 * special CubeUV format that allows us to perform custom interpolation so that
16330 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
16331 * chain, it only goes down to the LOD_MIN level (above), and then creates extra
16332 * even more filtered 'mips' at the same LOD_MIN resolution, associated with
16333 * higher roughness levels. In this way we maintain resolution to smoothly
16334 * interpolate diffuse lighting while limiting sampling computation.
16335 *
16336 * Paper: Fast, Accurate Image-Based Lighting
16337 * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view
16338*/
16339
16340class PMREMGenerator {
16341
16342	constructor( renderer ) {
16343
16344		this._renderer = renderer;
16345		this._pingPongRenderTarget = null;
16346
16347		this._lodMax = 0;
16348		this._cubeSize = 0;
16349		this._lodPlanes = [];
16350		this._sizeLods = [];
16351		this._sigmas = [];
16352
16353		this._blurMaterial = null;
16354		this._cubemapMaterial = null;
16355		this._equirectMaterial = null;
16356
16357		this._compileMaterial( this._blurMaterial );
16358
16359	}
16360
16361	/**
16362	 * Generates a PMREM from a supplied Scene, which can be faster than using an
16363	 * image if networking bandwidth is low. Optional sigma specifies a blur radius
16364	 * in radians to be applied to the scene before PMREM generation. Optional near
16365	 * and far planes ensure the scene is rendered in its entirety (the cubeCamera
16366	 * is placed at the origin).
16367	 */
16368	fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
16369
16370		_oldTarget = this._renderer.getRenderTarget();
16371		_oldActiveCubeFace = this._renderer.getActiveCubeFace();
16372		_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16373
16374		this._setSize( 256 );
16375
16376		const cubeUVRenderTarget = this._allocateTargets();
16377		cubeUVRenderTarget.depthBuffer = true;
16378
16379		this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
16380
16381		if ( sigma > 0 ) {
16382
16383			this._blur( cubeUVRenderTarget, 0, 0, sigma );
16384
16385		}
16386
16387		this._applyPMREM( cubeUVRenderTarget );
16388		this._cleanup( cubeUVRenderTarget );
16389
16390		return cubeUVRenderTarget;
16391
16392	}
16393
16394	/**
16395	 * Generates a PMREM from an equirectangular texture, which can be either LDR
16396	 * or HDR. The ideal input image size is 1k (1024 x 512),
16397	 * as this matches best with the 256 x 256 cubemap output.
16398	 */
16399	fromEquirectangular( equirectangular, renderTarget = null ) {
16400
16401		return this._fromTexture( equirectangular, renderTarget );
16402
16403	}
16404
16405	/**
16406	 * Generates a PMREM from an cubemap texture, which can be either LDR
16407	 * or HDR. The ideal input cube size is 256 x 256,
16408	 * as this matches best with the 256 x 256 cubemap output.
16409	 */
16410	fromCubemap( cubemap, renderTarget = null ) {
16411
16412		return this._fromTexture( cubemap, renderTarget );
16413
16414	}
16415
16416	/**
16417	 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
16418	 * your texture's network fetch for increased concurrency.
16419	 */
16420	compileCubemapShader() {
16421
16422		if ( this._cubemapMaterial === null ) {
16423
16424			this._cubemapMaterial = _getCubemapMaterial();
16425			this._compileMaterial( this._cubemapMaterial );
16426
16427		}
16428
16429	}
16430
16431	/**
16432	 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
16433	 * your texture's network fetch for increased concurrency.
16434	 */
16435	compileEquirectangularShader() {
16436
16437		if ( this._equirectMaterial === null ) {
16438
16439			this._equirectMaterial = _getEquirectMaterial();
16440			this._compileMaterial( this._equirectMaterial );
16441
16442		}
16443
16444	}
16445
16446	/**
16447	 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
16448	 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
16449	 * one of them will cause any others to also become unusable.
16450	 */
16451	dispose() {
16452
16453		this._dispose();
16454
16455		if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
16456		if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
16457
16458	}
16459
16460	// private interface
16461
16462	_setSize( cubeSize ) {
16463
16464		this._lodMax = Math.floor( Math.log2( cubeSize ) );
16465		this._cubeSize = Math.pow( 2, this._lodMax );
16466
16467	}
16468
16469	_dispose() {
16470
16471		if ( this._blurMaterial !== null ) this._blurMaterial.dispose();
16472
16473		if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();
16474
16475		for ( let i = 0; i < this._lodPlanes.length; i ++ ) {
16476
16477			this._lodPlanes[ i ].dispose();
16478
16479		}
16480
16481	}
16482
16483	_cleanup( outputTarget ) {
16484
16485		this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
16486		outputTarget.scissorTest = false;
16487		_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
16488
16489	}
16490
16491	_fromTexture( texture, renderTarget ) {
16492
16493		if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
16494
16495			this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
16496
16497		} else { // Equirectangular
16498
16499			this._setSize( texture.image.width / 4 );
16500
16501		}
16502
16503		_oldTarget = this._renderer.getRenderTarget();
16504		_oldActiveCubeFace = this._renderer.getActiveCubeFace();
16505		_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16506
16507		const cubeUVRenderTarget = renderTarget || this._allocateTargets();
16508		this._textureToCubeUV( texture, cubeUVRenderTarget );
16509		this._applyPMREM( cubeUVRenderTarget );
16510		this._cleanup( cubeUVRenderTarget );
16511
16512		return cubeUVRenderTarget;
16513
16514	}
16515
16516	_allocateTargets() {
16517
16518		const width = 3 * Math.max( this._cubeSize, 16 * 7 );
16519		const height = 4 * this._cubeSize;
16520
16521		const params = {
16522			magFilter: LinearFilter,
16523			minFilter: LinearFilter,
16524			generateMipmaps: false,
16525			type: HalfFloatType,
16526			format: RGBAFormat,
16527			colorSpace: LinearSRGBColorSpace,
16528			depthBuffer: false
16529		};
16530
16531		const cubeUVRenderTarget = _createRenderTarget( width, height, params );
16532
16533		if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {
16534
16535			if ( this._pingPongRenderTarget !== null ) {
16536
16537				this._dispose();
16538
16539			}
16540
16541			this._pingPongRenderTarget = _createRenderTarget( width, height, params );
16542
16543			const { _lodMax } = this;
16544			( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );
16545
16546			this._blurMaterial = _getBlurShader( _lodMax, width, height );
16547
16548		}
16549
16550		return cubeUVRenderTarget;
16551
16552	}
16553
16554	_compileMaterial( material ) {
16555
16556		const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
16557		this._renderer.compile( tmpMesh, _flatCamera );
16558
16559	}
16560
16561	_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
16562
16563		const fov = 90;
16564		const aspect = 1;
16565		const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
16566		const upSign = [ 1, - 1, 1, 1, 1, 1 ];
16567		const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
16568		const renderer = this._renderer;
16569
16570		const originalAutoClear = renderer.autoClear;
16571		const toneMapping = renderer.toneMapping;
16572		renderer.getClearColor( _clearColor );
16573
16574		renderer.toneMapping = NoToneMapping;
16575		renderer.autoClear = false;
16576
16577		const backgroundMaterial = new MeshBasicMaterial( {
16578			name: 'PMREM.Background',
16579			side: BackSide,
16580			depthWrite: false,
16581			depthTest: false,
16582		} );
16583
16584		const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
16585
16586		let useSolidColor = false;
16587		const background = scene.background;
16588
16589		if ( background ) {
16590
16591			if ( background.isColor ) {
16592
16593				backgroundMaterial.color.copy( background );
16594				scene.background = null;
16595				useSolidColor = true;
16596
16597			}
16598
16599		} else {
16600
16601			backgroundMaterial.color.copy( _clearColor );
16602			useSolidColor = true;
16603
16604		}
16605
16606		for ( let i = 0; i < 6; i ++ ) {
16607
16608			const col = i % 3;
16609
16610			if ( col === 0 ) {
16611
16612				cubeCamera.up.set( 0, upSign[ i ], 0 );
16613				cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
16614
16615			} else if ( col === 1 ) {
16616
16617				cubeCamera.up.set( 0, 0, upSign[ i ] );
16618				cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
16619
16620			} else {
16621
16622				cubeCamera.up.set( 0, upSign[ i ], 0 );
16623				cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
16624
16625			}
16626
16627			const size = this._cubeSize;
16628
16629			_setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );
16630
16631			renderer.setRenderTarget( cubeUVRenderTarget );
16632
16633			if ( useSolidColor ) {
16634
16635				renderer.render( backgroundBox, cubeCamera );
16636
16637			}
16638
16639			renderer.render( scene, cubeCamera );
16640
16641		}
16642
16643		backgroundBox.geometry.dispose();
16644		backgroundBox.material.dispose();
16645
16646		renderer.toneMapping = toneMapping;
16647		renderer.autoClear = originalAutoClear;
16648		scene.background = background;
16649
16650	}
16651
16652	_textureToCubeUV( texture, cubeUVRenderTarget ) {
16653
16654		const renderer = this._renderer;
16655
16656		const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
16657
16658		if ( isCubeTexture ) {
16659
16660			if ( this._cubemapMaterial === null ) {
16661
16662				this._cubemapMaterial = _getCubemapMaterial();
16663
16664			}
16665
16666			this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
16667
16668		} else {
16669
16670			if ( this._equirectMaterial === null ) {
16671
16672				this._equirectMaterial = _getEquirectMaterial();
16673
16674			}
16675
16676		}
16677
16678		const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
16679		const mesh = new Mesh( this._lodPlanes[ 0 ], material );
16680
16681		const uniforms = material.uniforms;
16682
16683		uniforms[ 'envMap' ].value = texture;
16684
16685		const size = this._cubeSize;
16686
16687		_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
16688
16689		renderer.setRenderTarget( cubeUVRenderTarget );
16690		renderer.render( mesh, _flatCamera );
16691
16692	}
16693
16694	_applyPMREM( cubeUVRenderTarget ) {
16695
16696		const renderer = this._renderer;
16697		const autoClear = renderer.autoClear;
16698		renderer.autoClear = false;
16699
16700		for ( let i = 1; i < this._lodPlanes.length; i ++ ) {
16701
16702			const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );
16703
16704			const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
16705
16706			this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
16707
16708		}
16709
16710		renderer.autoClear = autoClear;
16711
16712	}
16713
16714	/**
16715	 * This is a two-pass Gaussian blur for a cubemap. Normally this is done
16716	 * vertically and horizontally, but this breaks down on a cube. Here we apply
16717	 * the blur latitudinally (around the poles), and then longitudinally (towards
16718	 * the poles) to approximate the orthogonally-separable blur. It is least
16719	 * accurate at the poles, but still does a decent job.
16720	 */
16721	_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
16722
16723		const pingPongRenderTarget = this._pingPongRenderTarget;
16724
16725		this._halfBlur(
16726			cubeUVRenderTarget,
16727			pingPongRenderTarget,
16728			lodIn,
16729			lodOut,
16730			sigma,
16731			'latitudinal',
16732			poleAxis );
16733
16734		this._halfBlur(
16735			pingPongRenderTarget,
16736			cubeUVRenderTarget,
16737			lodOut,
16738			lodOut,
16739			sigma,
16740			'longitudinal',
16741			poleAxis );
16742
16743	}
16744
16745	_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
16746
16747		const renderer = this._renderer;
16748		const blurMaterial = this._blurMaterial;
16749
16750		if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
16751
16752			console.error(
16753				'blur direction must be either latitudinal or longitudinal!' );
16754
16755		}
16756
16757		// Number of standard deviations at which to cut off the discrete approximation.
16758		const STANDARD_DEVIATIONS = 3;
16759
16760		const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
16761		const blurUniforms = blurMaterial.uniforms;
16762
16763		const pixels = this._sizeLods[ lodIn ] - 1;
16764		const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
16765		const sigmaPixels = sigmaRadians / radiansPerPixel;
16766		const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
16767
16768		if ( samples > MAX_SAMPLES ) {
16769
16770			console.warn( `sigmaRadians, ${
16771				sigmaRadians}, is too large and will clip, as it requested ${
16772				samples} samples when the maximum is set to ${MAX_SAMPLES}` );
16773
16774		}
16775
16776		const weights = [];
16777		let sum = 0;
16778
16779		for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
16780
16781			const x = i / sigmaPixels;
16782			const weight = Math.exp( - x * x / 2 );
16783			weights.push( weight );
16784
16785			if ( i === 0 ) {
16786
16787				sum += weight;
16788
16789			} else if ( i < samples ) {
16790
16791				sum += 2 * weight;
16792
16793			}
16794
16795		}
16796
16797		for ( let i = 0; i < weights.length; i ++ ) {
16798
16799			weights[ i ] = weights[ i ] / sum;
16800
16801		}
16802
16803		blurUniforms[ 'envMap' ].value = targetIn.texture;
16804		blurUniforms[ 'samples' ].value = samples;
16805		blurUniforms[ 'weights' ].value = weights;
16806		blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
16807
16808		if ( poleAxis ) {
16809
16810			blurUniforms[ 'poleAxis' ].value = poleAxis;
16811
16812		}
16813
16814		const { _lodMax } = this;
16815		blurUniforms[ 'dTheta' ].value = radiansPerPixel;
16816		blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;
16817
16818		const outputSize = this._sizeLods[ lodOut ];
16819		const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
16820		const y = 4 * ( this._cubeSize - outputSize );
16821
16822		_setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
16823		renderer.setRenderTarget( targetOut );
16824		renderer.render( blurMesh, _flatCamera );
16825
16826	}
16827
16828}
16829
16830
16831
16832function _createPlanes( lodMax ) {
16833
16834	const lodPlanes = [];
16835	const sizeLods = [];
16836	const sigmas = [];
16837
16838	let lod = lodMax;
16839
16840	const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
16841
16842	for ( let i = 0; i < totalLods; i ++ ) {
16843
16844		const sizeLod = Math.pow( 2, lod );
16845		sizeLods.push( sizeLod );
16846		let sigma = 1.0 / sizeLod;
16847
16848		if ( i > lodMax - LOD_MIN ) {
16849
16850			sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];
16851
16852		} else if ( i === 0 ) {
16853
16854			sigma = 0;
16855
16856		}
16857
16858		sigmas.push( sigma );
16859
16860		const texelSize = 1.0 / ( sizeLod - 2 );
16861		const min = - texelSize;
16862		const max = 1 + texelSize;
16863		const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
16864
16865		const cubeFaces = 6;
16866		const vertices = 6;
16867		const positionSize = 3;
16868		const uvSize = 2;
16869		const faceIndexSize = 1;
16870
16871		const position = new Float32Array( positionSize * vertices * cubeFaces );
16872		const uv = new Float32Array( uvSize * vertices * cubeFaces );
16873		const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
16874
16875		for ( let face = 0; face < cubeFaces; face ++ ) {
16876
16877			const x = ( face % 3 ) * 2 / 3 - 1;
16878			const y = face > 2 ? 0 : - 1;
16879			const coordinates = [
16880				x, y, 0,
16881				x + 2 / 3, y, 0,
16882				x + 2 / 3, y + 1, 0,
16883				x, y, 0,
16884				x + 2 / 3, y + 1, 0,
16885				x, y + 1, 0
16886			];
16887			position.set( coordinates, positionSize * vertices * face );
16888			uv.set( uv1, uvSize * vertices * face );
16889			const fill = [ face, face, face, face, face, face ];
16890			faceIndex.set( fill, faceIndexSize * vertices * face );
16891
16892		}
16893
16894		const planes = new BufferGeometry();
16895		planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
16896		planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
16897		planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
16898		lodPlanes.push( planes );
16899
16900		if ( lod > LOD_MIN ) {
16901
16902			lod --;
16903
16904		}
16905
16906	}
16907
16908	return { lodPlanes, sizeLods, sigmas };
16909
16910}
16911
16912function _createRenderTarget( width, height, params ) {
16913
16914	const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );
16915	cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
16916	cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
16917	cubeUVRenderTarget.scissorTest = true;
16918	return cubeUVRenderTarget;
16919
16920}
16921
16922function _setViewport( target, x, y, width, height ) {
16923
16924	target.viewport.set( x, y, width, height );
16925	target.scissor.set( x, y, width, height );
16926
16927}
16928
16929function _getBlurShader( lodMax, width, height ) {
16930
16931	const weights = new Float32Array( MAX_SAMPLES );
vendor: 2,857 bytes, lines 16932-17077
16932	const poleAxis = new Vector3( 0, 1, 0 );
16933	const shaderMaterial = new ShaderMaterial( {
16934
16935		name: 'SphericalGaussianBlur',
16936
16937		defines: {
16938			'n': MAX_SAMPLES,
16939			'CUBEUV_TEXEL_WIDTH': 1.0 / width,
16940			'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
16941			'CUBEUV_MAX_MIP': `${lodMax}.0`,
16942		},
16943
16944		uniforms: {
16945			'envMap': { value: null },
16946			'samples': { value: 1 },
16947			'weights': { value: weights },
16948			'latitudinal': { value: false },
16949			'dTheta': { value: 0 },
16950			'mipInt': { value: 0 },
16951			'poleAxis': { value: poleAxis }
16952		},
16953
16954		vertexShader: _getCommonVertexShader(),
16955
16956		fragmentShader: /* glsl */`
16957
16958			precision mediump float;
16959			precision mediump int;
16960
16961			varying vec3 vOutputDirection;
16962
16963			uniform sampler2D envMap;
16964			uniform int samples;
16965			uniform float weights[ n ];
16966			uniform bool latitudinal;
16967			uniform float dTheta;
16968			uniform float mipInt;
16969			uniform vec3 poleAxis;
16970
16971			#define ENVMAP_TYPE_CUBE_UV
16972			#include <cube_uv_reflection_fragment>
16973
16974			vec3 getSample( float theta, vec3 axis ) {
16975
16976				float cosTheta = cos( theta );
16977				// Rodrigues' axis-angle rotation
16978				vec3 sampleDirection = vOutputDirection * cosTheta
16979					+ cross( axis, vOutputDirection ) * sin( theta )
16980					+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
16981
16982				return bilinearCubeUV( envMap, sampleDirection, mipInt );
16983
16984			}
16985
16986			void main() {
16987
16988				vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
16989
16990				if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
16991
16992					axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
16993
16994				}
16995
16996				axis = normalize( axis );
16997
16998				gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
16999				gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
17000
17001				for ( int i = 1; i < n; i++ ) {
17002
17003					if ( i >= samples ) {
17004
17005						break;
17006
17007					}
17008
17009					float theta = dTheta * float( i );
17010					gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
17011					gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
17012
17013				}
17014
17015			}
17016		`,
17017
17018		blending: NoBlending,
17019		depthTest: false,
17020		depthWrite: false
17021
17022	} );
17023
17024	return shaderMaterial;
17025
17026}
17027
17028function _getEquirectMaterial() {
17029
17030	return new ShaderMaterial( {
17031
17032		name: 'EquirectangularToCubeUV',
17033
17034		uniforms: {
17035			'envMap': { value: null }
17036		},
17037
17038		vertexShader: _getCommonVertexShader(),
17039
17040		fragmentShader: /* glsl */`
17041
17042			precision mediump float;
17043			precision mediump int;
17044
17045			varying vec3 vOutputDirection;
17046
17047			uniform sampler2D envMap;
17048
17049			#include <common>
17050
17051			void main() {
17052
17053				vec3 outputDirection = normalize( vOutputDirection );
17054				vec2 uv = equirectUv( outputDirection );
17055
17056				gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );
17057
17058			}
17059		`,
17060
17061		blending: NoBlending,
17062		depthTest: false,
17063		depthWrite: false
17064
17065	} );
17066
17067}
17068
17069function _getCubemapMaterial() {
17070
17071	return new ShaderMaterial( {
17072
17073		name: 'CubemapToCubeUV',
17074
17075		uniforms: {
17076			'envMap': { value: null },
17077			'flipEnvMap': { value: - 
vendor: 16,828 bytes, lines 17077-17915
170771 }
17078		},
17079
17080		vertexShader: _getCommonVertexShader(),
17081
17082		fragmentShader: /* glsl */`
17083
17084			precision mediump float;
17085			precision mediump int;
17086
17087			uniform float flipEnvMap;
17088
17089			varying vec3 vOutputDirection;
17090
17091			uniform samplerCube envMap;
17092
17093			void main() {
17094
17095				gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );
17096
17097			}
17098		`,
17099
17100		blending: NoBlending,
17101		depthTest: false,
17102		depthWrite: false
17103
17104	} );
17105
17106}
17107
17108function _getCommonVertexShader() {
17109
17110	return /* glsl */`
17111
17112		precision mediump float;
17113		precision mediump int;
17114
17115		attribute float faceIndex;
17116
17117		varying vec3 vOutputDirection;
17118
17119		// RH coordinate system; PMREM face-indexing convention
17120		vec3 getDirection( vec2 uv, float face ) {
17121
17122			uv = 2.0 * uv - 1.0;
17123
17124			vec3 direction = vec3( uv, 1.0 );
17125
17126			if ( face == 0.0 ) {
17127
17128				direction = direction.zyx; // ( 1, v, u ) pos x
17129
17130			} else if ( face == 1.0 ) {
17131
17132				direction = direction.xzy;
17133				direction.xz *= -1.0; // ( -u, 1, -v ) pos y
17134
17135			} else if ( face == 2.0 ) {
17136
17137				direction.x *= -1.0; // ( -u, v, 1 ) pos z
17138
17139			} else if ( face == 3.0 ) {
17140
17141				direction = direction.zyx;
17142				direction.xz *= -1.0; // ( -1, v, -u ) neg x
17143
17144			} else if ( face == 4.0 ) {
17145
17146				direction = direction.xzy;
17147				direction.xy *= -1.0; // ( -u, -1, v ) neg y
17148
17149			} else if ( face == 5.0 ) {
17150
17151				direction.z *= -1.0; // ( u, v, -1 ) neg z
17152
17153			}
17154
17155			return direction;
17156
17157		}
17158
17159		void main() {
17160
17161			vOutputDirection = getDirection( uv, faceIndex );
17162			gl_Position = vec4( position, 1.0 );
17163
17164		}
17165	`;
17166
17167}
17168
17169function WebGLCubeUVMaps( renderer ) {
17170
17171	let cubeUVmaps = new WeakMap();
17172
17173	let pmremGenerator = null;
17174
17175	function get( texture ) {
17176
17177		if ( texture && texture.isTexture ) {
17178
17179			const mapping = texture.mapping;
17180
17181			const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );
17182			const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
17183
17184			// equirect/cube map to cubeUV conversion
17185
17186			if ( isEquirectMap || isCubeMap ) {
17187
17188				if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) {
17189
17190					texture.needsPMREMUpdate = false;
17191
17192					let renderTarget = cubeUVmaps.get( texture );
17193
17194					if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17195
17196					renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );
17197					cubeUVmaps.set( texture, renderTarget );
17198
17199					return renderTarget.texture;
17200
17201				} else {
17202
17203					if ( cubeUVmaps.has( texture ) ) {
17204
17205						return cubeUVmaps.get( texture ).texture;
17206
17207					} else {
17208
17209						const image = texture.image;
17210
17211						if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {
17212
17213							if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17214
17215							const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
17216							cubeUVmaps.set( texture, renderTarget );
17217
17218							texture.addEventListener( 'dispose', onTextureDispose );
17219
17220							return renderTarget.texture;
17221
17222						} else {
17223
17224							// image not yet ready. try the conversion next frame
17225
17226							return null;
17227
17228						}
17229
17230					}
17231
17232				}
17233
17234			}
17235
17236		}
17237
17238		return texture;
17239
17240	}
17241
17242	function isCubeTextureComplete( image ) {
17243
17244		let count = 0;
17245		const length = 6;
17246
17247		for ( let i = 0; i < length; i ++ ) {
17248
17249			if ( image[ i ] !== undefined ) count ++;
17250
17251		}
17252
17253		return count === length;
17254
17255
17256	}
17257
17258	function onTextureDispose( event ) {
17259
17260		const texture = event.target;
17261
17262		texture.removeEventListener( 'dispose', onTextureDispose );
17263
17264		const cubemapUV = cubeUVmaps.get( texture );
17265
17266		if ( cubemapUV !== undefined ) {
17267
17268			cubeUVmaps.delete( texture );
17269			cubemapUV.dispose();
17270
17271		}
17272
17273	}
17274
17275	function dispose() {
17276
17277		cubeUVmaps = new WeakMap();
17278
17279		if ( pmremGenerator !== null ) {
17280
17281			pmremGenerator.dispose();
17282			pmremGenerator = null;
17283
17284		}
17285
17286	}
17287
17288	return {
17289		get: get,
17290		dispose: dispose
17291	};
17292
17293}
17294
17295function WebGLExtensions( gl ) {
17296
17297	const extensions = {};
17298
17299	function getExtension( name ) {
17300
17301		if ( extensions[ name ] !== undefined ) {
17302
17303			return extensions[ name ];
17304
17305		}
17306
17307		let extension;
17308
17309		switch ( name ) {
17310
17311			case 'WEBGL_depth_texture':
17312				extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
17313				break;
17314
17315			case 'EXT_texture_filter_anisotropic':
17316				extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
17317				break;
17318
17319			case 'WEBGL_compressed_texture_s3tc':
17320				extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
17321				break;
17322
17323			case 'WEBGL_compressed_texture_pvrtc':
17324				extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
17325				break;
17326
17327			default:
17328				extension = gl.getExtension( name );
17329
17330		}
17331
17332		extensions[ name ] = extension;
17333
17334		return extension;
17335
17336	}
17337
17338	return {
17339
17340		has: function ( name ) {
17341
17342			return getExtension( name ) !== null;
17343
17344		},
17345
17346		init: function ( capabilities ) {
17347
17348			if ( capabilities.isWebGL2 ) {
17349
17350				getExtension( 'EXT_color_buffer_float' );
17351				getExtension( 'WEBGL_clip_cull_distance' );
17352
17353			} else {
17354
17355				getExtension( 'WEBGL_depth_texture' );
17356				getExtension( 'OES_texture_float' );
17357				getExtension( 'OES_texture_half_float' );
17358				getExtension( 'OES_texture_half_float_linear' );
17359				getExtension( 'OES_standard_derivatives' );
17360				getExtension( 'OES_element_index_uint' );
17361				getExtension( 'OES_vertex_array_object' );
17362				getExtension( 'ANGLE_instanced_arrays' );
17363
17364			}
17365
17366			getExtension( 'OES_texture_float_linear' );
17367			getExtension( 'EXT_color_buffer_half_float' );
17368			getExtension( 'WEBGL_multisampled_render_to_texture' );
17369
17370		},
17371
17372		get: function ( name ) {
17373
17374			const extension = getExtension( name );
17375
17376			if ( extension === null ) {
17377
17378				console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
17379
17380			}
17381
17382			return extension;
17383
17384		}
17385
17386	};
17387
17388}
17389
17390function WebGLGeometries( gl, attributes, info, bindingStates ) {
17391
17392	const geometries = {};
17393	const wireframeAttributes = new WeakMap();
17394
17395	function onGeometryDispose( event ) {
17396
17397		const geometry = event.target;
17398
17399		if ( geometry.index !== null ) {
17400
17401			attributes.remove( geometry.index );
17402
17403		}
17404
17405		for ( const name in geometry.attributes ) {
17406
17407			attributes.remove( geometry.attributes[ name ] );
17408
17409		}
17410
17411		for ( const name in geometry.morphAttributes ) {
17412
17413			const array = geometry.morphAttributes[ name ];
17414
17415			for ( let i = 0, l = array.length; i < l; i ++ ) {
17416
17417				attributes.remove( array[ i ] );
17418
17419			}
17420
17421		}
17422
17423		geometry.removeEventListener( 'dispose', onGeometryDispose );
17424
17425		delete geometries[ geometry.id ];
17426
17427		const attribute = wireframeAttributes.get( geometry );
17428
17429		if ( attribute ) {
17430
17431			attributes.remove( attribute );
17432			wireframeAttributes.delete( geometry );
17433
17434		}
17435
17436		bindingStates.releaseStatesOfGeometry( geometry );
17437
17438		if ( geometry.isInstancedBufferGeometry === true ) {
17439
17440			delete geometry._maxInstanceCount;
17441
17442		}
17443
17444		//
17445
17446		info.memory.geometries --;
17447
17448	}
17449
17450	function get( object, geometry ) {
17451
17452		if ( geometries[ geometry.id ] === true ) return geometry;
17453
17454		geometry.addEventListener( 'dispose', onGeometryDispose );
17455
17456		geometries[ geometry.id ] = true;
17457
17458		info.memory.geometries ++;
17459
17460		return geometry;
17461
17462	}
17463
17464	function update( geometry ) {
17465
17466		const geometryAttributes = geometry.attributes;
17467
17468		// Updating index buffer in VAO now. See WebGLBindingStates.
17469
17470		for ( const name in geometryAttributes ) {
17471
17472			attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
17473
17474		}
17475
17476		// morph targets
17477
17478		const morphAttributes = geometry.morphAttributes;
17479
17480		for ( const name in morphAttributes ) {
17481
17482			const array = morphAttributes[ name ];
17483
17484			for ( let i = 0, l = array.length; i < l; i ++ ) {
17485
17486				attributes.update( array[ i ], gl.ARRAY_BUFFER );
17487
17488			}
17489
17490		}
17491
17492	}
17493
17494	function updateWireframeAttribute( geometry ) {
17495
17496		const indices = [];
17497
17498		const geometryIndex = geometry.index;
17499		const geometryPosition = geometry.attributes.position;
17500		let version = 0;
17501
17502		if ( geometryIndex !== null ) {
17503
17504			const array = geometryIndex.array;
17505			version = geometryIndex.version;
17506
17507			for ( let i = 0, l = array.length; i < l; i += 3 ) {
17508
17509				const a = array[ i + 0 ];
17510				const b = array[ i + 1 ];
17511				const c = array[ i + 2 ];
17512
17513				indices.push( a, b, b, c, c, a );
17514
17515			}
17516
17517		} else if ( geometryPosition !== undefined ) {
17518
17519			const array = geometryPosition.array;
17520			version = geometryPosition.version;
17521
17522			for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
17523
17524				const a = i + 0;
17525				const b = i + 1;
17526				const c = i + 2;
17527
17528				indices.push( a, b, b, c, c, a );
17529
17530			}
17531
17532		} else {
17533
17534			return;
17535
17536		}
17537
17538		const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
17539		attribute.version = version;
17540
17541		// Updating index buffer in VAO now. See WebGLBindingStates
17542
17543		//
17544
17545		const previousAttribute = wireframeAttributes.get( geometry );
17546
17547		if ( previousAttribute ) attributes.remove( previousAttribute );
17548
17549		//
17550
17551		wireframeAttributes.set( geometry, attribute );
17552
17553	}
17554
17555	function getWireframeAttribute( geometry ) {
17556
17557		const currentAttribute = wireframeAttributes.get( geometry );
17558
17559		if ( currentAttribute ) {
17560
17561			const geometryIndex = geometry.index;
17562
17563			if ( geometryIndex !== null ) {
17564
17565				// if the attribute is obsolete, create a new one
17566
17567				if ( currentAttribute.version < geometryIndex.version ) {
17568
17569					updateWireframeAttribute( geometry );
17570
17571				}
17572
17573			}
17574
17575		} else {
17576
17577			updateWireframeAttribute( geometry );
17578
17579		}
17580
17581		return wireframeAttributes.get( geometry );
17582
17583	}
17584
17585	return {
17586
17587		get: get,
17588		update: update,
17589
17590		getWireframeAttribute: getWireframeAttribute
17591
17592	};
17593
17594}
17595
17596function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
17597
17598	const isWebGL2 = capabilities.isWebGL2;
17599
17600	let mode;
17601
17602	function setMode( value ) {
17603
17604		mode = value;
17605
17606	}
17607
17608	let type, bytesPerElement;
17609
17610	function setIndex( value ) {
17611
17612		type = value.type;
17613		bytesPerElement = value.bytesPerElement;
17614
17615	}
17616
17617	function render( start, count ) {
17618
17619		gl.drawElements( mode, count, type, start * bytesPerElement );
17620
17621		info.update( count, mode, 1 );
17622
17623	}
17624
17625	function renderInstances( start, count, primcount ) {
17626
17627		if ( primcount === 0 ) return;
17628
17629		let extension, methodName;
17630
17631		if ( isWebGL2 ) {
17632
17633			extension = gl;
17634			methodName = 'drawElementsInstanced';
17635
17636		} else {
17637
17638			extension = extensions.get( 'ANGLE_instanced_arrays' );
17639			methodName = 'drawElementsInstancedANGLE';
17640
17641			if ( extension === null ) {
17642
17643				console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
17644				return;
17645
17646			}
17647
17648		}
17649
17650		extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
17651
17652		info.update( count, mode, primcount );
17653
17654	}
17655
17656	function renderMultiDraw( starts, counts, drawCount ) {
17657
17658		if ( drawCount === 0 ) return;
17659
17660		const extension = extensions.get( 'WEBGL_multi_draw' );
17661		if ( extension === null ) {
17662
17663			for ( let i = 0; i < drawCount; i ++ ) {
17664
17665				this.render( starts[ i ] / bytesPerElement, counts[ i ] );
17666
17667			}
17668
17669		} else {
17670
17671			extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );
17672
17673			let elementCount = 0;
17674			for ( let i = 0; i < drawCount; i ++ ) {
17675
17676				elementCount += counts[ i ];
17677
17678			}
17679
17680			info.update( elementCount, mode, 1 );
17681
17682		}
17683
17684	}
17685
17686	//
17687
17688	this.setMode = setMode;
17689	this.setIndex = setIndex;
17690	this.render = render;
17691	this.renderInstances = renderInstances;
17692	this.renderMultiDraw = renderMultiDraw;
17693
17694}
17695
17696function WebGLInfo( gl ) {
17697
17698	const memory = {
17699		geometries: 0,
17700		textures: 0
17701	};
17702
17703	const render = {
17704		frame: 0,
17705		calls: 0,
17706		triangles: 0,
17707		points: 0,
17708		lines: 0
17709	};
17710
17711	function update( count, mode, instanceCount ) {
17712
17713		render.calls ++;
17714
17715		switch ( mode ) {
17716
17717			case gl.TRIANGLES:
17718				render.triangles += instanceCount * ( count / 3 );
17719				break;
17720
17721			case gl.LINES:
17722				render.lines += instanceCount * ( count / 2 );
17723				break;
17724
17725			case gl.LINE_STRIP:
17726				render.lines += instanceCount * ( count - 1 );
17727				break;
17728
17729			case gl.LINE_LOOP:
17730				render.lines += instanceCount * count;
17731				break;
17732
17733			case gl.POINTS:
17734				render.points += instanceCount * count;
17735				break;
17736
17737			default:
17738				console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
17739				break;
17740
17741		}
17742
17743	}
17744
17745	function reset() {
17746
17747		render.calls = 0;
17748		render.triangles = 0;
17749		render.points = 0;
17750		render.lines = 0;
17751
17752	}
17753
17754	return {
17755		memory: memory,
17756		render: render,
17757		programs: null,
17758		autoReset: true,
17759		reset: reset,
17760		update: update
17761	};
17762
17763}
17764
17765function numericalSort( a, b ) {
17766
17767	return a[ 0 ] - b[ 0 ];
17768
17769}
17770
17771function absNumericalSort( a, b ) {
17772
17773	return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
17774
17775}
17776
17777function WebGLMorphtargets( gl, capabilities, textures ) {
17778
17779	const influencesList = {};
17780	const morphInfluences = new Float32Array( 8 );
17781	const morphTextures = new WeakMap();
17782	const morph = new Vector4();
17783
17784	const workInfluences = [];
17785
17786	for ( let i = 0; i < 8; i ++ ) {
17787
17788		workInfluences[ i ] = [ i, 0 ];
17789
17790	}
17791
17792	function update( object, geometry, program ) {
17793
17794		const objectInfluences = object.morphTargetInfluences;
17795
17796		if ( capabilities.isWebGL2 === true ) {
17797
17798			// instead of using attributes, the WebGL 2 code path encodes morph targets
17799			// into an array of data textures. Each layer represents a single morph target.
17800
17801			const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
17802			const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
17803
17804			let entry = morphTextures.get( geometry );
17805
17806			if ( entry === undefined || entry.count !== morphTargetsCount ) {
17807
17808				if ( entry !== undefined ) entry.texture.dispose();
17809
17810				const hasMorphPosition = geometry.morphAttributes.position !== undefined;
17811				const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
17812				const hasMorphColors = geometry.morphAttributes.color !== undefined;
17813
17814				const morphTargets = geometry.morphAttributes.position || [];
17815				const morphNormals = geometry.morphAttributes.normal || [];
17816				const morphColors = geometry.morphAttributes.color || [];
17817
17818				let vertexDataCount = 0;
17819
17820				if ( hasMorphPosition === true ) vertexDataCount = 1;
17821				if ( hasMorphNormals === true ) vertexDataCount = 2;
17822				if ( hasMorphColors === true ) vertexDataCount = 3;
17823
17824				let width = geometry.attributes.position.count * vertexDataCount;
17825				let height = 1;
17826
17827				if ( width > capabilities.maxTextureSize ) {
17828
17829					height = Math.ceil( width / capabilities.maxTextureSize );
17830					width = capabilities.maxTextureSize;
17831
17832				}
17833
17834				const buffer = new Float32Array( width * height * 4 * morphTargetsCount );
17835
17836				const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
17837				texture.type = FloatType;
17838				texture.needsUpdate = true;
17839
17840				// fill buffer
17841
17842				const vertexDataStride = vertexDataCount * 4;
17843
17844				for ( let i = 0; i < morphTargetsCount; i ++ ) {
17845
17846					const morphTarget = morphTargets[ i ];
17847					const morphNormal = morphNormals[ i ];
17848					const morphColor = morphColors[ i ];
17849
17850					const offset = width * height * 4 * i;
17851
17852					for ( let j = 0; j < morphTarget.count; j ++ ) {
17853
17854						const stride = j * vertexDataStride;
17855
17856						if ( hasMorphPosition === true ) {
17857
17858							morph.fromBufferAttribute( morphTarget, j );
17859
17860							buffer[ offset + stride + 0 ] = morph.x;
17861							buffer[ offset + stride + 1 ] = morph.y;
17862							buffer[ offset + stride + 2 ] = morph.z;
17863							buffer[ offset + stride + 3 ] = 0;
17864
17865						}
17866
17867						if ( hasMorphNormals === true ) {
17868
17869							morph.fromBufferAttribute( morphNormal, j );
17870
17871							buffer[ offset + stride + 4 ] = morph.x;
17872							buffer[ offset + stride + 5 ] = morph.y;
17873							buffer[ offset + stride + 6 ] = morph.z;
17874							buffer[ offset + stride + 7 ] = 0;
17875
17876						}
17877
17878						if ( hasMorphColors === true ) {
17879
17880							morph.fromBufferAttribute( morphColor, j );
17881
17882							buffer[ offset + stride + 8 ] = morph.x;
17883							buffer[ offset + stride + 9 ] = morph.y;
17884							buffer[ offset + stride + 10 ] = morph.z;
17885							buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;
17886
17887						}
17888
17889					}
17890
17891				}
17892
17893				entry = {
17894					count: morphTargetsCount,
17895					texture: texture,
17896					size: new Vector2( width, height )
17897				};
17898
17899				morphTextures.set( geometry, entry );
17900
17901				function disposeTexture() {
17902
17903					texture.dispose();
17904
17905					morphTextures.delete( geometry );
17906
17907					geometry.removeEventListener( 'dispose', disposeTexture );
17908
17909				}
17910
17911				geometry.addEventListener( 'dispose', disposeTexture );
17912
17913			}
17914
17915			//
17916
17917			let morphInfluencesSum = 0;
17918
17919			for ( let i = 0; i < objectInfluences.length; i ++ ) {
17920
17921				morphInfluencesSum += objectInfluences[ i ];
17922
17923			}
17924
17925			const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
17926
17927			program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
17928			program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );
17929
17930			program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
17931			program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );
vendor: 29,081 bytes, lines 17932-19482
17932
17933
17934		} else {
17935
17936			// When object doesn't have morph target influences defined, we treat it as a 0-length array
17937			// This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
17938
17939			const length = objectInfluences === undefined ? 0 : objectInfluences.length;
17940
17941			let influences = influencesList[ geometry.id ];
17942
17943			if ( influences === undefined || influences.length !== length ) {
17944
17945				// initialise list
17946
17947				influences = [];
17948
17949				for ( let i = 0; i < length; i ++ ) {
17950
17951					influences[ i ] = [ i, 0 ];
17952
17953				}
17954
17955				influencesList[ geometry.id ] = influences;
17956
17957			}
17958
17959			// Collect influences
17960
17961			for ( let i = 0; i < length; i ++ ) {
17962
17963				const influence = influences[ i ];
17964
17965				influence[ 0 ] = i;
17966				influence[ 1 ] = objectInfluences[ i ];
17967
17968			}
17969
17970			influences.sort( absNumericalSort );
17971
17972			for ( let i = 0; i < 8; i ++ ) {
17973
17974				if ( i < length && influences[ i ][ 1 ] ) {
17975
17976					workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
17977					workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
17978
17979				} else {
17980
17981					workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
17982					workInfluences[ i ][ 1 ] = 0;
17983
17984				}
17985
17986			}
17987
17988			workInfluences.sort( numericalSort );
17989
17990			const morphTargets = geometry.morphAttributes.position;
17991			const morphNormals = geometry.morphAttributes.normal;
17992
17993			let morphInfluencesSum = 0;
17994
17995			for ( let i = 0; i < 8; i ++ ) {
17996
17997				const influence = workInfluences[ i ];
17998				const index = influence[ 0 ];
17999				const value = influence[ 1 ];
18000
18001				if ( index !== Number.MAX_SAFE_INTEGER && value ) {
18002
18003					if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
18004
18005						geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
18006
18007					}
18008
18009					if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
18010
18011						geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
18012
18013					}
18014
18015					morphInfluences[ i ] = value;
18016					morphInfluencesSum += value;
18017
18018				} else {
18019
18020					if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
18021
18022						geometry.deleteAttribute( 'morphTarget' + i );
18023
18024					}
18025
18026					if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
18027
18028						geometry.deleteAttribute( 'morphNormal' + i );
18029
18030					}
18031
18032					morphInfluences[ i ] = 0;
18033
18034				}
18035
18036			}
18037
18038			// GLSL shader uses formula baseinfluence * base + sum(target * influence)
18039			// This allows us to switch between absolute morphs and relative morphs without changing shader code
18040			// When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
18041			const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
18042
18043			program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
18044			program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
18045
18046		}
18047
18048	}
18049
18050	return {
18051
18052		update: update
18053
18054	};
18055
18056}
18057
18058function WebGLObjects( gl, geometries, attributes, info ) {
18059
18060	let updateMap = new WeakMap();
18061
18062	function update( object ) {
18063
18064		const frame = info.render.frame;
18065
18066		const geometry = object.geometry;
18067		const buffergeometry = geometries.get( object, geometry );
18068
18069		// Update once per frame
18070
18071		if ( updateMap.get( buffergeometry ) !== frame ) {
18072
18073			geometries.update( buffergeometry );
18074
18075			updateMap.set( buffergeometry, frame );
18076
18077		}
18078
18079		if ( object.isInstancedMesh ) {
18080
18081			if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
18082
18083				object.addEventListener( 'dispose', onInstancedMeshDispose );
18084
18085			}
18086
18087			if ( updateMap.get( object ) !== frame ) {
18088
18089				attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );
18090
18091				if ( object.instanceColor !== null ) {
18092
18093					attributes.update( object.instanceColor, gl.ARRAY_BUFFER );
18094
18095				}
18096
18097				updateMap.set( object, frame );
18098
18099			}
18100
18101		}
18102
18103		if ( object.isSkinnedMesh ) {
18104
18105			const skeleton = object.skeleton;
18106
18107			if ( updateMap.get( skeleton ) !== frame ) {
18108
18109				skeleton.update();
18110
18111				updateMap.set( skeleton, frame );
18112
18113			}
18114
18115		}
18116
18117		return buffergeometry;
18118
18119	}
18120
18121	function dispose() {
18122
18123		updateMap = new WeakMap();
18124
18125	}
18126
18127	function onInstancedMeshDispose( event ) {
18128
18129		const instancedMesh = event.target;
18130
18131		instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
18132
18133		attributes.remove( instancedMesh.instanceMatrix );
18134
18135		if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
18136
18137	}
18138
18139	return {
18140
18141		update: update,
18142		dispose: dispose
18143
18144	};
18145
18146}
18147
18148class DepthTexture extends Texture {
18149
18150	constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
18151
18152		format = format !== undefined ? format : DepthFormat;
18153
18154		if ( format !== DepthFormat && format !== DepthStencilFormat ) {
18155
18156			throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
18157
18158		}
18159
18160		if ( type === undefined && format === DepthFormat ) type = UnsignedIntType;
18161		if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
18162
18163		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
18164
18165		this.isDepthTexture = true;
18166
18167		this.image = { width: width, height: height };
18168
18169		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
18170		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
18171
18172		this.flipY = false;
18173		this.generateMipmaps = false;
18174
18175		this.compareFunction = null;
18176
18177	}
18178
18179
18180	copy( source ) {
18181
18182		super.copy( source );
18183
18184		this.compareFunction = source.compareFunction;
18185
18186		return this;
18187
18188	}
18189
18190	toJSON( meta ) {
18191
18192		const data = super.toJSON( meta );
18193
18194		if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction;
18195
18196		return data;
18197
18198	}
18199
18200}
18201
18202/**
18203 * Uniforms of a program.
18204 * Those form a tree structure with a special top-level container for the root,
18205 * which you get by calling 'new WebGLUniforms( gl, program )'.
18206 *
18207 *
18208 * Properties of inner nodes including the top-level container:
18209 *
18210 * .seq - array of nested uniforms
18211 * .map - nested uniforms by name
18212 *
18213 *
18214 * Methods of all nodes except the top-level container:
18215 *
18216 * .setValue( gl, value, [textures] )
18217 *
18218 * 		uploads a uniform value(s)
18219 *  	the 'textures' parameter is needed for sampler uniforms
18220 *
18221 *
18222 * Static methods of the top-level container (textures factorizations):
18223 *
18224 * .upload( gl, seq, values, textures )
18225 *
18226 * 		sets uniforms in 'seq' to 'values[id].value'
18227 *
18228 * .seqWithValue( seq, values ) : filteredSeq
18229 *
18230 * 		filters 'seq' entries with corresponding entry in values
18231 *
18232 *
18233 * Methods of the top-level container (textures factorizations):
18234 *
18235 * .setValue( gl, name, value, textures )
18236 *
18237 * 		sets uniform with  name 'name' to 'value'
18238 *
18239 * .setOptional( gl, obj, prop )
18240 *
18241 * 		like .set for an optional property of the object
18242 *
18243 */
18244
18245
18246const emptyTexture = /*@__PURE__*/ new Texture();
18247
18248const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );
18249emptyShadowTexture.compareFunction = LessEqualCompare;
18250
18251const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
18252const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
18253const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
18254
18255// --- Utilities ---
18256
18257// Array Caches (provide typed arrays for temporary by size)
18258
18259const arrayCacheF32 = [];
18260const arrayCacheI32 = [];
18261
18262// Float32Array caches used for uploading Matrix uniforms
18263
18264const mat4array = new Float32Array( 16 );
18265const mat3array = new Float32Array( 9 );
18266const mat2array = new Float32Array( 4 );
18267
18268// Flattening for arrays of vectors and matrices
18269
18270function flatten( array, nBlocks, blockSize ) {
18271
18272	const firstElem = array[ 0 ];
18273
18274	if ( firstElem <= 0 || firstElem > 0 ) return array;
18275	// unoptimized: ! isNaN( firstElem )
18276	// see http://jacksondunstan.com/articles/983
18277
18278	const n = nBlocks * blockSize;
18279	let r = arrayCacheF32[ n ];
18280
18281	if ( r === undefined ) {
18282
18283		r = new Float32Array( n );
18284		arrayCacheF32[ n ] = r;
18285
18286	}
18287
18288	if ( nBlocks !== 0 ) {
18289
18290		firstElem.toArray( r, 0 );
18291
18292		for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
18293
18294			offset += blockSize;
18295			array[ i ].toArray( r, offset );
18296
18297		}
18298
18299	}
18300
18301	return r;
18302
18303}
18304
18305function arraysEqual( a, b ) {
18306
18307	if ( a.length !== b.length ) return false;
18308
18309	for ( let i = 0, l = a.length; i < l; i ++ ) {
18310
18311		if ( a[ i ] !== b[ i ] ) return false;
18312
18313	}
18314
18315	return true;
18316
18317}
18318
18319function copyArray( a, b ) {
18320
18321	for ( let i = 0, l = b.length; i < l; i ++ ) {
18322
18323		a[ i ] = b[ i ];
18324
18325	}
18326
18327}
18328
18329// Texture unit allocation
18330
18331function allocTexUnits( textures, n ) {
18332
18333	let r = arrayCacheI32[ n ];
18334
18335	if ( r === undefined ) {
18336
18337		r = new Int32Array( n );
18338		arrayCacheI32[ n ] = r;
18339
18340	}
18341
18342	for ( let i = 0; i !== n; ++ i ) {
18343
18344		r[ i ] = textures.allocateTextureUnit();
18345
18346	}
18347
18348	return r;
18349
18350}
18351
18352// --- Setters ---
18353
18354// Note: Defining these methods externally, because they come in a bunch
18355// and this way their names minify.
18356
18357// Single scalar
18358
18359function setValueV1f( gl, v ) {
18360
18361	const cache = this.cache;
18362
18363	if ( cache[ 0 ] === v ) return;
18364
18365	gl.uniform1f( this.addr, v );
18366
18367	cache[ 0 ] = v;
18368
18369}
18370
18371// Single float vector (from flat array or THREE.VectorN)
18372
18373function setValueV2f( gl, v ) {
18374
18375	const cache = this.cache;
18376
18377	if ( v.x !== undefined ) {
18378
18379		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18380
18381			gl.uniform2f( this.addr, v.x, v.y );
18382
18383			cache[ 0 ] = v.x;
18384			cache[ 1 ] = v.y;
18385
18386		}
18387
18388	} else {
18389
18390		if ( arraysEqual( cache, v ) ) return;
18391
18392		gl.uniform2fv( this.addr, v );
18393
18394		copyArray( cache, v );
18395
18396	}
18397
18398}
18399
18400function setValueV3f( gl, v ) {
18401
18402	const cache = this.cache;
18403
18404	if ( v.x !== undefined ) {
18405
18406		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18407
18408			gl.uniform3f( this.addr, v.x, v.y, v.z );
18409
18410			cache[ 0 ] = v.x;
18411			cache[ 1 ] = v.y;
18412			cache[ 2 ] = v.z;
18413
18414		}
18415
18416	} else if ( v.r !== undefined ) {
18417
18418		if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
18419
18420			gl.uniform3f( this.addr, v.r, v.g, v.b );
18421
18422			cache[ 0 ] = v.r;
18423			cache[ 1 ] = v.g;
18424			cache[ 2 ] = v.b;
18425
18426		}
18427
18428	} else {
18429
18430		if ( arraysEqual( cache, v ) ) return;
18431
18432		gl.uniform3fv( this.addr, v );
18433
18434		copyArray( cache, v );
18435
18436	}
18437
18438}
18439
18440function setValueV4f( gl, v ) {
18441
18442	const cache = this.cache;
18443
18444	if ( v.x !== undefined ) {
18445
18446		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18447
18448			gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
18449
18450			cache[ 0 ] = v.x;
18451			cache[ 1 ] = v.y;
18452			cache[ 2 ] = v.z;
18453			cache[ 3 ] = v.w;
18454
18455		}
18456
18457	} else {
18458
18459		if ( arraysEqual( cache, v ) ) return;
18460
18461		gl.uniform4fv( this.addr, v );
18462
18463		copyArray( cache, v );
18464
18465	}
18466
18467}
18468
18469// Single matrix (from flat array or THREE.MatrixN)
18470
18471function setValueM2( gl, v ) {
18472
18473	const cache = this.cache;
18474	const elements = v.elements;
18475
18476	if ( elements === undefined ) {
18477
18478		if ( arraysEqual( cache, v ) ) return;
18479
18480		gl.uniformMatrix2fv( this.addr, false, v );
18481
18482		copyArray( cache, v );
18483
18484	} else {
18485
18486		if ( arraysEqual( cache, elements ) ) return;
18487
18488		mat2array.set( elements );
18489
18490		gl.uniformMatrix2fv( this.addr, false, mat2array );
18491
18492		copyArray( cache, elements );
18493
18494	}
18495
18496}
18497
18498function setValueM3( gl, v ) {
18499
18500	const cache = this.cache;
18501	const elements = v.elements;
18502
18503	if ( elements === undefined ) {
18504
18505		if ( arraysEqual( cache, v ) ) return;
18506
18507		gl.uniformMatrix3fv( this.addr, false, v );
18508
18509		copyArray( cache, v );
18510
18511	} else {
18512
18513		if ( arraysEqual( cache, elements ) ) return;
18514
18515		mat3array.set( elements );
18516
18517		gl.uniformMatrix3fv( this.addr, false, mat3array );
18518
18519		copyArray( cache, elements );
18520
18521	}
18522
18523}
18524
18525function setValueM4( gl, v ) {
18526
18527	const cache = this.cache;
18528	const elements = v.elements;
18529
18530	if ( elements === undefined ) {
18531
18532		if ( arraysEqual( cache, v ) ) return;
18533
18534		gl.uniformMatrix4fv( this.addr, false, v );
18535
18536		copyArray( cache, v );
18537
18538	} else {
18539
18540		if ( arraysEqual( cache, elements ) ) return;
18541
18542		mat4array.set( elements );
18543
18544		gl.uniformMatrix4fv( this.addr, false, mat4array );
18545
18546		copyArray( cache, elements );
18547
18548	}
18549
18550}
18551
18552// Single integer / boolean
18553
18554function setValueV1i( gl, v ) {
18555
18556	const cache = this.cache;
18557
18558	if ( cache[ 0 ] === v ) return;
18559
18560	gl.uniform1i( this.addr, v );
18561
18562	cache[ 0 ] = v;
18563
18564}
18565
18566// Single integer / boolean vector (from flat array or THREE.VectorN)
18567
18568function setValueV2i( gl, v ) {
18569
18570	const cache = this.cache;
18571
18572	if ( v.x !== undefined ) {
18573
18574		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18575
18576			gl.uniform2i( this.addr, v.x, v.y );
18577
18578			cache[ 0 ] = v.x;
18579			cache[ 1 ] = v.y;
18580
18581		}
18582
18583	} else {
18584
18585		if ( arraysEqual( cache, v ) ) return;
18586
18587		gl.uniform2iv( this.addr, v );
18588
18589		copyArray( cache, v );
18590
18591	}
18592
18593}
18594
18595function setValueV3i( gl, v ) {
18596
18597	const cache = this.cache;
18598
18599	if ( v.x !== undefined ) {
18600
18601		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18602
18603			gl.uniform3i( this.addr, v.x, v.y, v.z );
18604
18605			cache[ 0 ] = v.x;
18606			cache[ 1 ] = v.y;
18607			cache[ 2 ] = v.z;
18608
18609		}
18610
18611	} else {
18612
18613		if ( arraysEqual( cache, v ) ) return;
18614
18615		gl.uniform3iv( this.addr, v );
18616
18617		copyArray( cache, v );
18618
18619	}
18620
18621}
18622
18623function setValueV4i( gl, v ) {
18624
18625	const cache = this.cache;
18626
18627	if ( v.x !== undefined ) {
18628
18629		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18630
18631			gl.uniform4i( this.addr, v.x, v.y, v.z, v.w );
18632
18633			cache[ 0 ] = v.x;
18634			cache[ 1 ] = v.y;
18635			cache[ 2 ] = v.z;
18636			cache[ 3 ] = v.w;
18637
18638		}
18639
18640	} else {
18641
18642		if ( arraysEqual( cache, v ) ) return;
18643
18644		gl.uniform4iv( this.addr, v );
18645
18646		copyArray( cache, v );
18647
18648	}
18649
18650}
18651
18652// Single unsigned integer
18653
18654function setValueV1ui( gl, v ) {
18655
18656	const cache = this.cache;
18657
18658	if ( cache[ 0 ] === v ) return;
18659
18660	gl.uniform1ui( this.addr, v );
18661
18662	cache[ 0 ] = v;
18663
18664}
18665
18666// Single unsigned integer vector (from flat array or THREE.VectorN)
18667
18668function setValueV2ui( gl, v ) {
18669
18670	const cache = this.cache;
18671
18672	if ( v.x !== undefined ) {
18673
18674		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18675
18676			gl.uniform2ui( this.addr, v.x, v.y );
18677
18678			cache[ 0 ] = v.x;
18679			cache[ 1 ] = v.y;
18680
18681		}
18682
18683	} else {
18684
18685		if ( arraysEqual( cache, v ) ) return;
18686
18687		gl.uniform2uiv( this.addr, v );
18688
18689		copyArray( cache, v );
18690
18691	}
18692
18693}
18694
18695function setValueV3ui( gl, v ) {
18696
18697	const cache = this.cache;
18698
18699	if ( v.x !== undefined ) {
18700
18701		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18702
18703			gl.uniform3ui( this.addr, v.x, v.y, v.z );
18704
18705			cache[ 0 ] = v.x;
18706			cache[ 1 ] = v.y;
18707			cache[ 2 ] = v.z;
18708
18709		}
18710
18711	} else {
18712
18713		if ( arraysEqual( cache, v ) ) return;
18714
18715		gl.uniform3uiv( this.addr, v );
18716
18717		copyArray( cache, v );
18718
18719	}
18720
18721}
18722
18723function setValueV4ui( gl, v ) {
18724
18725	const cache = this.cache;
18726
18727	if ( v.x !== undefined ) {
18728
18729		if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18730
18731			gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );
18732
18733			cache[ 0 ] = v.x;
18734			cache[ 1 ] = v.y;
18735			cache[ 2 ] = v.z;
18736			cache[ 3 ] = v.w;
18737
18738		}
18739
18740	} else {
18741
18742		if ( arraysEqual( cache, v ) ) return;
18743
18744		gl.uniform4uiv( this.addr, v );
18745
18746		copyArray( cache, v );
18747
18748	}
18749
18750}
18751
18752
18753// Single texture (2D / Cube)
18754
18755function setValueT1( gl, v, textures ) {
18756
18757	const cache = this.cache;
18758	const unit = textures.allocateTextureUnit();
18759
18760	if ( cache[ 0 ] !== unit ) {
18761
18762		gl.uniform1i( this.addr, unit );
18763		cache[ 0 ] = unit;
18764
18765	}
18766
18767	const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture;
18768
18769	textures.setTexture2D( v || emptyTexture2D, unit );
18770
18771}
18772
18773function setValueT3D1( gl, v, textures ) {
18774
18775	const cache = this.cache;
18776	const unit = textures.allocateTextureUnit();
18777
18778	if ( cache[ 0 ] !== unit ) {
18779
18780		gl.uniform1i( this.addr, unit );
18781		cache[ 0 ] = unit;
18782
18783	}
18784
18785	textures.setTexture3D( v || empty3dTexture, unit );
18786
18787}
18788
18789function setValueT6( gl, v, textures ) {
18790
18791	const cache = this.cache;
18792	const unit = textures.allocateTextureUnit();
18793
18794	if ( cache[ 0 ] !== unit ) {
18795
18796		gl.uniform1i( this.addr, unit );
18797		cache[ 0 ] = unit;
18798
18799	}
18800
18801	textures.setTextureCube( v || emptyCubeTexture, unit );
18802
18803}
18804
18805function setValueT2DArray1( gl, v, textures ) {
18806
18807	const cache = this.cache;
18808	const unit = textures.allocateTextureUnit();
18809
18810	if ( cache[ 0 ] !== unit ) {
18811
18812		gl.uniform1i( this.addr, unit );
18813		cache[ 0 ] = unit;
18814
18815	}
18816
18817	textures.setTexture2DArray( v || emptyArrayTexture, unit );
18818
18819}
18820
18821// Helper to pick the right setter for the singular case
18822
18823function getSingularSetter( type ) {
18824
18825	switch ( type ) {
18826
18827		case 0x1406: return setValueV1f; // FLOAT
18828		case 0x8b50: return setValueV2f; // _VEC2
18829		case 0x8b51: return setValueV3f; // _VEC3
18830		case 0x8b52: return setValueV4f; // _VEC4
18831
18832		case 0x8b5a: return setValueM2; // _MAT2
18833		case 0x8b5b: return setValueM3; // _MAT3
18834		case 0x8b5c: return setValueM4; // _MAT4
18835
18836		case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
18837		case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
18838		case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
18839		case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
18840
18841		case 0x1405: return setValueV1ui; // UINT
18842		case 0x8dc6: return setValueV2ui; // _VEC2
18843		case 0x8dc7: return setValueV3ui; // _VEC3
18844		case 0x8dc8: return setValueV4ui; // _VEC4
18845
18846		case 0x8b5e: // SAMPLER_2D
18847		case 0x8d66: // SAMPLER_EXTERNAL_OES
18848		case 0x8dca: // INT_SAMPLER_2D
18849		case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
18850		case 0x8b62: // SAMPLER_2D_SHADOW
18851			return setValueT1;
18852
18853		case 0x8b5f: // SAMPLER_3D
18854		case 0x8dcb: // INT_SAMPLER_3D
18855		case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
18856			return setValueT3D1;
18857
18858		case 0x8b60: // SAMPLER_CUBE
18859		case 0x8dcc: // INT_SAMPLER_CUBE
18860		case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
18861		case 0x8dc5: // SAMPLER_CUBE_SHADOW
18862			return setValueT6;
18863
18864		case 0x8dc1: // SAMPLER_2D_ARRAY
18865		case 0x8dcf: // INT_SAMPLER_2D_ARRAY
18866		case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
18867		case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
18868			return setValueT2DArray1;
18869
18870	}
18871
18872}
18873
18874
18875// Array of scalars
18876
18877function setValueV1fArray( gl, v ) {
18878
18879	gl.uniform1fv( this.addr, v );
18880
18881}
18882
18883// Array of vectors (from flat array or array of THREE.VectorN)
18884
18885function setValueV2fArray( gl, v ) {
18886
18887	const data = flatten( v, this.size, 2 );
18888
18889	gl.uniform2fv( this.addr, data );
18890
18891}
18892
18893function setValueV3fArray( gl, v ) {
18894
18895	const data = flatten( v, this.size, 3 );
18896
18897	gl.uniform3fv( this.addr, data );
18898
18899}
18900
18901function setValueV4fArray( gl, v ) {
18902
18903	const data = flatten( v, this.size, 4 );
18904
18905	gl.uniform4fv( this.addr, data );
18906
18907}
18908
18909// Array of matrices (from flat array or array of THREE.MatrixN)
18910
18911function setValueM2Array( gl, v ) {
18912
18913	const data = flatten( v, this.size, 4 );
18914
18915	gl.uniformMatrix2fv( this.addr, false, data );
18916
18917}
18918
18919function setValueM3Array( gl, v ) {
18920
18921	const data = flatten( v, this.size, 9 );
18922
18923	gl.uniformMatrix3fv( this.addr, false, data );
18924
18925}
18926
18927function setValueM4Array( gl, v ) {
18928
18929	const data = flatten( v, this.size, 16 );
18930
18931	gl.uniformMatrix4fv( this.addr, false, data );
18932
18933}
18934
18935// Array of integer / boolean
18936
18937function setValueV1iArray( gl, v ) {
18938
18939	gl.uniform1iv( this.addr, v );
18940
18941}
18942
18943// Array of integer / boolean vectors (from flat array)
18944
18945function setValueV2iArray( gl, v ) {
18946
18947	gl.uniform2iv( this.addr, v );
18948
18949}
18950
18951function setValueV3iArray( gl, v ) {
18952
18953	gl.uniform3iv( this.addr, v );
18954
18955}
18956
18957function setValueV4iArray( gl, v ) {
18958
18959	gl.uniform4iv( this.addr, v );
18960
18961}
18962
18963// Array of unsigned integer
18964
18965function setValueV1uiArray( gl, v ) {
18966
18967	gl.uniform1uiv( this.addr, v );
18968
18969}
18970
18971// Array of unsigned integer vectors (from flat array)
18972
18973function setValueV2uiArray( gl, v ) {
18974
18975	gl.uniform2uiv( this.addr, v );
18976
18977}
18978
18979function setValueV3uiArray( gl, v ) {
18980
18981	gl.uniform3uiv( this.addr, v );
18982
18983}
18984
18985function setValueV4uiArray( gl, v ) {
18986
18987	gl.uniform4uiv( this.addr, v );
18988
18989}
18990
18991
18992// Array of textures (2D / 3D / Cube / 2DArray)
18993
18994function setValueT1Array( gl, v, textures ) {
18995
18996	const cache = this.cache;
18997
18998	const n = v.length;
18999
19000	const units = allocTexUnits( textures, n );
19001
19002	if ( ! arraysEqual( cache, units ) ) {
19003
19004		gl.uniform1iv( this.addr, units );
19005
19006		copyArray( cache, units );
19007
19008	}
19009
19010	for ( let i = 0; i !== n; ++ i ) {
19011
19012		textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
19013
19014	}
19015
19016}
19017
19018function setValueT3DArray( gl, v, textures ) {
19019
19020	const cache = this.cache;
19021
19022	const n = v.length;
19023
19024	const units = allocTexUnits( textures, n );
19025
19026	if ( ! arraysEqual( cache, units ) ) {
19027
19028		gl.uniform1iv( this.addr, units );
19029
19030		copyArray( cache, units );
19031
19032	}
19033
19034	for ( let i = 0; i !== n; ++ i ) {
19035
19036		textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );
19037
19038	}
19039
19040}
19041
19042function setValueT6Array( gl, v, textures ) {
19043
19044	const cache = this.cache;
19045
19046	const n = v.length;
19047
19048	const units = allocTexUnits( textures, n );
19049
19050	if ( ! arraysEqual( cache, units ) ) {
19051
19052		gl.uniform1iv( this.addr, units );
19053
19054		copyArray( cache, units );
19055
19056	}
19057
19058	for ( let i = 0; i !== n; ++ i ) {
19059
19060		textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
19061
19062	}
19063
19064}
19065
19066function setValueT2DArrayArray( gl, v, textures ) {
19067
19068	const cache = this.cache;
19069
19070	const n = v.length;
19071
19072	const units = allocTexUnits( textures, n );
19073
19074	if ( ! arraysEqual( cache, units ) ) {
19075
19076		gl.uniform1iv( this.addr, units );
19077
19078		copyArray( cache, units );
19079
19080	}
19081
19082	for ( let i = 0; i !== n; ++ i ) {
19083
19084		textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );
19085
19086	}
19087
19088}
19089
19090
19091// Helper to pick the right setter for a pure (bottom-level) array
19092
19093function getPureArraySetter( type ) {
19094
19095	switch ( type ) {
19096
19097		case 0x1406: return setValueV1fArray; // FLOAT
19098		case 0x8b50: return setValueV2fArray; // _VEC2
19099		case 0x8b51: return setValueV3fArray; // _VEC3
19100		case 0x8b52: return setValueV4fArray; // _VEC4
19101
19102		case 0x8b5a: return setValueM2Array; // _MAT2
19103		case 0x8b5b: return setValueM3Array; // _MAT3
19104		case 0x8b5c: return setValueM4Array; // _MAT4
19105
19106		case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
19107		case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
19108		case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
19109		case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
19110
19111		case 0x1405: return setValueV1uiArray; // UINT
19112		case 0x8dc6: return setValueV2uiArray; // _VEC2
19113		case 0x8dc7: return setValueV3uiArray; // _VEC3
19114		case 0x8dc8: return setValueV4uiArray; // _VEC4
19115
19116		case 0x8b5e: // SAMPLER_2D
19117		case 0x8d66: // SAMPLER_EXTERNAL_OES
19118		case 0x8dca: // INT_SAMPLER_2D
19119		case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
19120		case 0x8b62: // SAMPLER_2D_SHADOW
19121			return setValueT1Array;
19122
19123		case 0x8b5f: // SAMPLER_3D
19124		case 0x8dcb: // INT_SAMPLER_3D
19125		case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
19126			return setValueT3DArray;
19127
19128		case 0x8b60: // SAMPLER_CUBE
19129		case 0x8dcc: // INT_SAMPLER_CUBE
19130		case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
19131		case 0x8dc5: // SAMPLER_CUBE_SHADOW
19132			return setValueT6Array;
19133
19134		case 0x8dc1: // SAMPLER_2D_ARRAY
19135		case 0x8dcf: // INT_SAMPLER_2D_ARRAY
19136		case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
19137		case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
19138			return setValueT2DArrayArray;
19139
19140	}
19141
19142}
19143
19144// --- Uniform Classes ---
19145
19146class SingleUniform {
19147
19148	constructor( id, activeInfo, addr ) {
19149
19150		this.id = id;
19151		this.addr = addr;
19152		this.cache = [];
19153		this.type = activeInfo.type;
19154		this.setValue = getSingularSetter( activeInfo.type );
19155
19156		// this.path = activeInfo.name; // DEBUG
19157
19158	}
19159
19160}
19161
19162class PureArrayUniform {
19163
19164	constructor( id, activeInfo, addr ) {
19165
19166		this.id = id;
19167		this.addr = addr;
19168		this.cache = [];
19169		this.type = activeInfo.type;
19170		this.size = activeInfo.size;
19171		this.setValue = getPureArraySetter( activeInfo.type );
19172
19173		// this.path = activeInfo.name; // DEBUG
19174
19175	}
19176
19177}
19178
19179class StructuredUniform {
19180
19181	constructor( id ) {
19182
19183		this.id = id;
19184
19185		this.seq = [];
19186		this.map = {};
19187
19188	}
19189
19190	setValue( gl, value, textures ) {
19191
19192		const seq = this.seq;
19193
19194		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19195
19196			const u = seq[ i ];
19197			u.setValue( gl, value[ u.id ], textures );
19198
19199		}
19200
19201	}
19202
19203}
19204
19205// --- Top-level ---
19206
19207// Parser - builds up the property tree from the path strings
19208
19209const RePathPart = /(\w+)(\])?(\[|\.)?/g;
19210
19211// extracts
19212// 	- the identifier (member name or array index)
19213//  - followed by an optional right bracket (found when array index)
19214//  - followed by an optional left bracket or dot (type of subscript)
19215//
19216// Note: These portions can be read in a non-overlapping fashion and
19217// allow straightforward parsing of the hierarchy that WebGL encodes
19218// in the uniform names.
19219
19220function addUniform( container, uniformObject ) {
19221
19222	container.seq.push( uniformObject );
19223	container.map[ uniformObject.id ] = uniformObject;
19224
19225}
19226
19227function parseUniform( activeInfo, addr, container ) {
19228
19229	const path = activeInfo.name,
19230		pathLength = path.length;
19231
19232	// reset RegExp object, because of the early exit of a previous run
19233	RePathPart.lastIndex = 0;
19234
19235	while ( true ) {
19236
19237		const match = RePathPart.exec( path ),
19238			matchEnd = RePathPart.lastIndex;
19239
19240		let id = match[ 1 ];
19241		const idIsIndex = match[ 2 ] === ']',
19242			subscript = match[ 3 ];
19243
19244		if ( idIsIndex ) id = id | 0; // convert to integer
19245
19246		if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
19247
19248			// bare name or "pure" bottom-level array "[0]" suffix
19249
19250			addUniform( container, subscript === undefined ?
19251				new SingleUniform( id, activeInfo, addr ) :
19252				new PureArrayUniform( id, activeInfo, addr ) );
19253
19254			break;
19255
19256		} else {
19257
19258			// step into inner node / create it in case it doesn't exist
19259
19260			const map = container.map;
19261			let next = map[ id ];
19262
19263			if ( next === undefined ) {
19264
19265				next = new StructuredUniform( id );
19266				addUniform( container, next );
19267
19268			}
19269
19270			container = next;
19271
19272		}
19273
19274	}
19275
19276}
19277
19278// Root Container
19279
19280class WebGLUniforms {
19281
19282	constructor( gl, program ) {
19283
19284		this.seq = [];
19285		this.map = {};
19286
19287		const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
19288
19289		for ( let i = 0; i < n; ++ i ) {
19290
19291			const info = gl.getActiveUniform( program, i ),
19292				addr = gl.getUniformLocation( program, info.name );
19293
19294			parseUniform( info, addr, this );
19295
19296		}
19297
19298	}
19299
19300	setValue( gl, name, value, textures ) {
19301
19302		const u = this.map[ name ];
19303
19304		if ( u !== undefined ) u.setValue( gl, value, textures );
19305
19306	}
19307
19308	setOptional( gl, object, name ) {
19309
19310		const v = object[ name ];
19311
19312		if ( v !== undefined ) this.setValue( gl, name, v );
19313
19314	}
19315
19316	static upload( gl, seq, values, textures ) {
19317
19318		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19319
19320			const u = seq[ i ],
19321				v = values[ u.id ];
19322
19323			if ( v.needsUpdate !== false ) {
19324
19325				// note: always updating when .needsUpdate is undefined
19326				u.setValue( gl, v.value, textures );
19327
19328			}
19329
19330		}
19331
19332	}
19333
19334	static seqWithValue( seq, values ) {
19335
19336		const r = [];
19337
19338		for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19339
19340			const u = seq[ i ];
19341			if ( u.id in values ) r.push( u );
19342
19343		}
19344
19345		return r;
19346
19347	}
19348
19349}
19350
19351function WebGLShader( gl, type, string ) {
19352
19353	const shader = gl.createShader( type );
19354
19355	gl.shaderSource( shader, string );
19356	gl.compileShader( shader );
19357
19358	return shader;
19359
19360}
19361
19362// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
19363const COMPLETION_STATUS_KHR = 0x91B1;
19364
19365let programIdCount = 0;
19366
19367function handleSource( string, errorLine ) {
19368
19369	const lines = string.split( '\n' );
19370	const lines2 = [];
19371
19372	const from = Math.max( errorLine - 6, 0 );
19373	const to = Math.min( errorLine + 6, lines.length );
19374
19375	for ( let i = from; i < to; i ++ ) {
19376
19377		const line = i + 1;
19378		lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );
19379
19380	}
19381
19382	return lines2.join( '\n' );
19383
19384}
19385
19386function getEncodingComponents( colorSpace ) {
19387
19388	const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
19389	const encodingPrimaries = ColorManagement.getPrimaries( colorSpace );
19390
19391	let gamutMapping;
19392
19393	if ( workingPrimaries === encodingPrimaries ) {
19394
19395		gamutMapping = '';
19396
19397	} else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) {
19398
19399		gamutMapping = 'LinearDisplayP3ToLinearSRGB';
19400
19401	} else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) {
19402
19403		gamutMapping = 'LinearSRGBToLinearDisplayP3';
19404
19405	}
19406
19407	switch ( colorSpace ) {
19408
19409		case LinearSRGBColorSpace:
19410		case LinearDisplayP3ColorSpace:
19411			return [ gamutMapping, 'LinearTransferOETF' ];
19412
19413		case SRGBColorSpace:
19414		case DisplayP3ColorSpace:
19415			return [ gamutMapping, 'sRGBTransferOETF' ];
19416
19417		default:
19418			console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );
19419			return [ gamutMapping, 'LinearTransferOETF' ];
19420
19421	}
19422
19423}
19424
19425function getShaderErrors( gl, shader, type ) {
19426
19427	const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );
19428	const errors = gl.getShaderInfoLog( shader ).trim();
19429
19430	if ( status && errors === '' ) return '';
19431
19432	const errorMatches = /ERROR: 0:(\d+)/.exec( errors );
19433	if ( errorMatches ) {
19434
19435		// --enable-privileged-webgl-extension
19436		// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
19437
19438		const errorLine = parseInt( errorMatches[ 1 ] );
19439		return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine );
19440
19441	} else {
19442
19443		return errors;
19444
19445	}
19446
19447}
19448
19449function getTexelEncodingFunction( functionName, colorSpace ) {
19450
19451	const components = getEncodingComponents( colorSpace );
19452	return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;
19453
19454}
19455
19456function getToneMappingFunction( functionName, toneMapping ) {
19457
19458	let toneMappingName;
19459
19460	switch ( toneMapping ) {
19461
19462		case LinearToneMapping:
19463			toneMappingName = 'Linear';
19464			break;
19465
19466		case ReinhardToneMapping:
19467			toneMappingName = 'Reinhard';
19468			break;
19469
19470		case CineonToneMapping:
19471			toneMappingName = 'OptimizedCineon';
19472			break;
19473
19474		case ACESFilmicToneMapping:
19475			toneMappingName = 'ACESFilmic';
19476			break;
19477
19478		case AgXToneMapping:
19479			toneMappingName = 'AgX';
19480			break;
19481
19482		case 
vendor: 17,767 bytes, lines 19482-20098
19482CustomToneMapping:
19483			toneMappingName = 'Custom';
19484			break;
19485
19486		default:
19487			console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
19488			toneMappingName = 'Linear';
19489
19490	}
19491
19492	return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
19493
19494}
19495
19496function generateExtensions( parameters ) {
19497
19498	const chunks = [
19499		( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
19500		( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
19501		( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
19502		( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
19503	];
19504
19505	return chunks.filter( filterEmptyLine ).join( '\n' );
19506
19507}
19508
19509function generateVertexExtensions( parameters ) {
19510
19511	const chunks = [
19512		parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : ''
19513	];
19514
19515	return chunks.filter( filterEmptyLine ).join( '\n' );
19516
19517}
19518
19519function generateDefines( defines ) {
19520
19521	const chunks = [];
19522
19523	for ( const name in defines ) {
19524
19525		const value = defines[ name ];
19526
19527		if ( value === false ) continue;
19528
19529		chunks.push( '#define ' + name + ' ' + value );
19530
19531	}
19532
19533	return chunks.join( '\n' );
19534
19535}
19536
19537function fetchAttributeLocations( gl, program ) {
19538
19539	const attributes = {};
19540
19541	const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
19542
19543	for ( let i = 0; i < n; i ++ ) {
19544
19545		const info = gl.getActiveAttrib( program, i );
19546		const name = info.name;
19547
19548		let locationSize = 1;
19549		if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
19550		if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
19551		if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;
19552
19553		// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
19554
19555		attributes[ name ] = {
19556			type: info.type,
19557			location: gl.getAttribLocation( program, name ),
19558			locationSize: locationSize
19559		};
19560
19561	}
19562
19563	return attributes;
19564
19565}
19566
19567function filterEmptyLine( string ) {
19568
19569	return string !== '';
19570
19571}
19572
19573function replaceLightNums( string, parameters ) {
19574
19575	const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;
19576
19577	return string
19578		.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
19579		.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
19580		.replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
19581		.replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )
19582		.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
19583		.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
19584		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
19585		.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
19586		.replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )
19587		.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
19588		.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
19589
19590}
19591
19592function replaceClippingPlaneNums( string, parameters ) {
19593
19594	return string
19595		.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
19596		.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
19597
19598}
19599
19600// Resolve Includes
19601
19602const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
19603
19604function resolveIncludes( string ) {
19605
19606	return string.replace( includePattern, includeReplacer );
19607
19608}
19609
19610const shaderChunkMap = new Map( [
19611	[ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154
19612	[ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154
19613	[ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154
19614] );
19615
19616function includeReplacer( match, include ) {
19617
19618	let string = ShaderChunk[ include ];
19619
19620	if ( string === undefined ) {
19621
19622		const newInclude = shaderChunkMap.get( include );
19623
19624		if ( newInclude !== undefined ) {
19625
19626			string = ShaderChunk[ newInclude ];
19627			console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude );
19628
19629		} else {
19630
19631			throw new Error( 'Can not resolve #include <' + include + '>' );
19632
19633		}
19634
19635	}
19636
19637	return resolveIncludes( string );
19638
19639}
19640
19641// Unroll Loops
19642
19643const 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;
19644
19645function unrollLoops( string ) {
19646
19647	return string.replace( unrollLoopPattern, loopReplacer );
19648
19649}
19650
19651function loopReplacer( match, start, end, snippet ) {
19652
19653	let string = '';
19654
19655	for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
19656
19657		string += snippet
19658			.replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
19659			.replace( /UNROLLED_LOOP_INDEX/g, i );
19660
19661	}
19662
19663	return string;
19664
19665}
19666
19667//
19668
19669function generatePrecision( parameters ) {
19670
19671	let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
19672
19673	if ( parameters.precision === 'highp' ) {
19674
19675		precisionstring += '\n#define HIGH_PRECISION';
19676
19677	} else if ( parameters.precision === 'mediump' ) {
19678
19679		precisionstring += '\n#define MEDIUM_PRECISION';
19680
19681	} else if ( parameters.precision === 'lowp' ) {
19682
19683		precisionstring += '\n#define LOW_PRECISION';
19684
19685	}
19686
19687	return precisionstring;
19688
19689}
19690
19691function generateShadowMapTypeDefine( parameters ) {
19692
19693	let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
19694
19695	if ( parameters.shadowMapType === PCFShadowMap ) {
19696
19697		shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
19698
19699	} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
19700
19701		shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
19702
19703	} else if ( parameters.shadowMapType === VSMShadowMap ) {
19704
19705		shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
19706
19707	}
19708
19709	return shadowMapTypeDefine;
19710
19711}
19712
19713function generateEnvMapTypeDefine( parameters ) {
19714
19715	let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19716
19717	if ( parameters.envMap ) {
19718
19719		switch ( parameters.envMapMode ) {
19720
19721			case CubeReflectionMapping:
19722			case CubeRefractionMapping:
19723				envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19724				break;
19725
19726			case CubeUVReflectionMapping:
19727				envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
19728				break;
19729
19730		}
19731
19732	}
19733
19734	return envMapTypeDefine;
19735
19736}
19737
19738function generateEnvMapModeDefine( parameters ) {
19739
19740	let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
19741
19742	if ( parameters.envMap ) {
19743
19744		switch ( parameters.envMapMode ) {
19745
19746			case CubeRefractionMapping:
19747
19748				envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
19749				break;
19750
19751		}
19752
19753	}
19754
19755	return envMapModeDefine;
19756
19757}
19758
19759function generateEnvMapBlendingDefine( parameters ) {
19760
19761	let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
19762
19763	if ( parameters.envMap ) {
19764
19765		switch ( parameters.combine ) {
19766
19767			case MultiplyOperation:
19768				envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
19769				break;
19770
19771			case MixOperation:
19772				envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
19773				break;
19774
19775			case AddOperation:
19776				envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
19777				break;
19778
19779		}
19780
19781	}
19782
19783	return envMapBlendingDefine;
19784
19785}
19786
19787function generateCubeUVSize( parameters ) {
19788
19789	const imageHeight = parameters.envMapCubeUVHeight;
19790
19791	if ( imageHeight === null ) return null;
19792
19793	const maxMip = Math.log2( imageHeight ) - 2;
19794
19795	const texelHeight = 1.0 / imageHeight;
19796
19797	const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
19798
19799	return { texelWidth, texelHeight, maxMip };
19800
19801}
19802
19803function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
19804
19805	// TODO Send this event to Three.js DevTools
19806	// console.log( 'WebGLProgram', cacheKey );
19807
19808	const gl = renderer.getContext();
19809
19810	const defines = parameters.defines;
19811
19812	let vertexShader = parameters.vertexShader;
19813	let fragmentShader = parameters.fragmentShader;
19814
19815	const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
19816	const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
19817	const envMapModeDefine = generateEnvMapModeDefine( parameters );
19818	const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
19819	const envMapCubeUVSize = generateCubeUVSize( parameters );
19820
19821	const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
19822
19823	const customVertexExtensions = generateVertexExtensions( parameters );
19824
19825	const customDefines = generateDefines( defines );
19826
19827	const program = gl.createProgram();
19828
19829	let prefixVertex, prefixFragment;
19830	let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
19831
19832	if ( parameters.isRawShaderMaterial ) {
19833
19834		prefixVertex = [
19835
19836			'#define SHADER_TYPE ' + parameters.shaderType,
19837			'#define SHADER_NAME ' + parameters.shaderName,
19838
19839			customDefines
19840
19841		].filter( filterEmptyLine ).join( '\n' );
19842
19843		if ( prefixVertex.length > 0 ) {
19844
19845			prefixVertex += '\n';
19846
19847		}
19848
19849		prefixFragment = [
19850
19851			customExtensions,
19852
19853			'#define SHADER_TYPE ' + parameters.shaderType,
19854			'#define SHADER_NAME ' + parameters.shaderName,
19855
19856			customDefines
19857
19858		].filter( filterEmptyLine ).join( '\n' );
19859
19860		if ( prefixFragment.length > 0 ) {
19861
19862			prefixFragment += '\n';
19863
19864		}
19865
19866	} else {
19867
19868		prefixVertex = [
19869
19870			generatePrecision( parameters ),
19871
19872			'#define SHADER_TYPE ' + parameters.shaderType,
19873			'#define SHADER_NAME ' + parameters.shaderName,
19874
19875			customDefines,
19876
19877			parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
19878			parameters.batching ? '#define USE_BATCHING' : '',
19879			parameters.instancing ? '#define USE_INSTANCING' : '',
19880			parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
19881
19882			parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
19883			parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
19884
19885			parameters.map ? '#define USE_MAP' : '',
19886			parameters.envMap ? '#define USE_ENVMAP' : '',
19887			parameters.envMap ? '#define ' + envMapModeDefine : '',
19888			parameters.lightMap ? '#define USE_LIGHTMAP' : '',
19889			parameters.aoMap ? '#define USE_AOMAP' : '',
19890			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
19891			parameters.normalMap ? '#define USE_NORMALMAP' : '',
19892			parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
19893			parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
19894			parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',
19895			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
19896
19897			parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
19898			parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
19899
19900			parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
19901			parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
19902			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
19903
19904			parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
19905			parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
19906
19907			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
19908			parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
19909			parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
19910
19911			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
19912			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
19913			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
19914			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
19915
19916			parameters.transmission ? '#define USE_TRANSMISSION' : '',
19917			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
19918			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
19919
19920			parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
19921			parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
19922
19923			//
19924
19925			parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',
19926			parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',
19927			parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',
19928			parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',
19929			parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',
19930			parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',
19931			parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',
19932			parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',
19933
19934			parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',
19935			parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',
19936
19937			parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',
19938
19939			parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',
19940			parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',
19941			parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',
19942
19943			parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',
19944			parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',
19945
19946			parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',
19947			parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',
19948
19949			parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',
19950			parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',
19951			parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',
19952
19953			parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',
19954			parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',
19955
19956			//
19957
19958			parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
19959			parameters.vertexColors ? '#define USE_COLOR' : '',
19960			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
19961			parameters.vertexUv1s ? '#define USE_UV1' : '',
19962			parameters.vertexUv2s ? '#define USE_UV2' : '',
19963			parameters.vertexUv3s ? '#define USE_UV3' : '',
19964
19965			parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
19966
19967			parameters.flatShading ? '#define FLAT_SHADED' : '',
19968
19969			parameters.skinning ? '#define USE_SKINNING' : '',
19970
19971			parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
19972			parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
19973			( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '',
19974			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
19975			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
19976			( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
19977			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
19978			parameters.flipSided ? '#define FLIP_SIDED' : '',
19979
19980			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
19981			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
19982
19983			parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
19984
19985			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
19986
19987			parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
19988
19989			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
19990			( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
19991
19992			'uniform mat4 modelMatrix;',
19993			'uniform mat4 modelViewMatrix;',
19994			'uniform mat4 projectionMatrix;',
19995			'uniform mat4 viewMatrix;',
19996			'uniform mat3 normalMatrix;',
19997			'uniform vec3 cameraPosition;',
19998			'uniform bool isOrthographic;',
19999
20000			'#ifdef USE_INSTANCING',
20001
20002			'	attribute mat4 instanceMatrix;',
20003
20004			'#endif',
20005
20006			'#ifdef USE_INSTANCING_COLOR',
20007
20008			'	attribute vec3 instanceColor;',
20009
20010			'#endif',
20011
20012			'attribute vec3 position;',
20013			'attribute vec3 normal;',
20014			'attribute vec2 uv;',
20015
20016			'#ifdef USE_UV1',
20017
20018			'	attribute vec2 uv1;',
20019
20020			'#endif',
20021
20022			'#ifdef USE_UV2',
20023
20024			'	attribute vec2 uv2;',
20025
20026			'#endif',
20027
20028			'#ifdef USE_UV3',
20029
20030			'	attribute vec2 uv3;',
20031
20032			'#endif',
20033
20034			'#ifdef USE_TANGENT',
20035
20036			'	attribute vec4 tangent;',
20037
20038			'#endif',
20039
20040			'#if defined( USE_COLOR_ALPHA )',
20041
20042			'	attribute vec4 color;',
20043
20044			'#elif defined( USE_COLOR )',
20045
20046			'	attribute vec3 color;',
20047
20048			'#endif',
20049
20050			'#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
20051
20052			'	attribute vec3 morphTarget0;',
20053			'	attribute vec3 morphTarget1;',
20054			'	attribute vec3 morphTarget2;',
20055			'	attribute vec3 morphTarget3;',
20056
20057			'	#ifdef USE_MORPHNORMALS',
20058
20059			'		attribute vec3 morphNormal0;',
20060			'		attribute vec3 morphNormal1;',
20061			'		attribute vec3 morphNormal2;',
20062			'		attribute vec3 morphNormal3;',
20063
20064			'	#else',
20065
20066			'		attribute vec3 morphTarget4;',
20067			'		attribute vec3 morphTarget5;',
20068			'		attribute vec3 morphTarget6;',
20069			'		attribute vec3 morphTarget7;',
20070
20071			'	#endif',
20072
20073			'#endif',
20074
20075			'#ifdef USE_SKINNING',
20076
20077			'	attribute vec4 skinIndex;',
20078			'	attribute vec4 skinWeight;',
20079
20080			'#endif',
20081
20082			'\n'
20083
20084		].filter( filterEmptyLine ).join( '\n' );
20085
20086		prefixFragment = [
20087
20088			customExtensions,
20089
20090			generatePrecision( parameters ),
20091
20092			'#define SHADER_TYPE ' + parameters.shaderType,
20093			'#define SHADER_NAME ' + parameters.shaderName,
20094
20095			customDefines,
20096
20097			parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
20098			parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
vendor: 8,229 bytes, lines 20099-20301
20099
20100			parameters.map ? '#define USE_MAP' : '',
20101			parameters.matcap ? '#define USE_MATCAP' : '',
20102			parameters.envMap ? '#define USE_ENVMAP' : '',
20103			parameters.envMap ? '#define ' + envMapTypeDefine : '',
20104			parameters.envMap ? '#define ' + envMapModeDefine : '',
20105			parameters.envMap ? '#define ' + envMapBlendingDefine : '',
20106			envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
20107			envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
20108			envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
20109			parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20110			parameters.aoMap ? '#define USE_AOMAP' : '',
20111			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20112			parameters.normalMap ? '#define USE_NORMALMAP' : '',
20113			parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
20114			parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
20115			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20116
20117			parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
20118			parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
20119
20120			parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
20121			parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
20122			parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
20123			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
20124
20125			parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
20126			parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
20127			parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
20128
20129			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20130			parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
20131			parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
20132
20133			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20134			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20135
20136			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20137			parameters.alphaTest ? '#define USE_ALPHATEST' : '',
20138			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
20139
20140			parameters.sheen ? '#define USE_SHEEN' : '',
20141			parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
20142			parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
20143
20144			parameters.transmission ? '#define USE_TRANSMISSION' : '',
20145			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
20146			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
20147
20148			parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
20149			parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
20150			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
20151			parameters.vertexUv1s ? '#define USE_UV1' : '',
20152			parameters.vertexUv2s ? '#define USE_UV2' : '',
20153			parameters.vertexUv3s ? '#define USE_UV3' : '',
20154
20155			parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
20156
20157			parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
20158
20159			parameters.flatShading ? '#define FLAT_SHADED' : '',
20160
20161			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20162			parameters.flipSided ? '#define FLIP_SIDED' : '',
20163
20164			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20165			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20166
20167			parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
20168
20169			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
20170
20171			parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
20172
20173			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
20174
20175			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20176			( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20177
20178			'uniform mat4 viewMatrix;',
20179			'uniform vec3 cameraPosition;',
20180			'uniform bool isOrthographic;',
20181
20182			( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
20183			( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
20184			( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
20185
20186			parameters.dithering ? '#define DITHERING' : '',
20187			parameters.opaque ? '#define OPAQUE' : '',
20188
20189			ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
20190			getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),
20191
20192			parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
20193
20194			'\n'
20195
20196		].filter( filterEmptyLine ).join( '\n' );
20197
20198	}
20199
20200	vertexShader = resolveIncludes( vertexShader );
20201	vertexShader = replaceLightNums( vertexShader, parameters );
20202	vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
20203
20204	fragmentShader = resolveIncludes( fragmentShader );
20205	fragmentShader = replaceLightNums( fragmentShader, parameters );
20206	fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
20207
20208	vertexShader = unrollLoops( vertexShader );
20209	fragmentShader = unrollLoops( fragmentShader );
20210
20211	if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
20212
20213		// GLSL 3.0 conversion for built-in materials and ShaderMaterial
20214
20215		versionString = '#version 300 es\n';
20216
20217		prefixVertex = [
20218			customVertexExtensions,
20219			'precision mediump sampler2DArray;',
20220			'#define attribute in',
20221			'#define varying out',
20222			'#define texture2D texture'
20223		].join( '\n' ) + '\n' + prefixVertex;
20224
20225		prefixFragment = [
20226			'precision mediump sampler2DArray;',
20227			'#define varying in',
20228			( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
20229			( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
20230			'#define gl_FragDepthEXT gl_FragDepth',
20231			'#define texture2D texture',
20232			'#define textureCube texture',
20233			'#define texture2DProj textureProj',
20234			'#define texture2DLodEXT textureLod',
20235			'#define texture2DProjLodEXT textureProjLod',
20236			'#define textureCubeLodEXT textureLod',
20237			'#define texture2DGradEXT textureGrad',
20238			'#define texture2DProjGradEXT textureProjGrad',
20239			'#define textureCubeGradEXT textureGrad'
20240		].join( '\n' ) + '\n' + prefixFragment;
20241
20242	}
20243
20244	const vertexGlsl = versionString + prefixVertex + vertexShader;
20245	const fragmentGlsl = versionString + prefixFragment + fragmentShader;
20246
20247	// console.log( '*VERTEX*', vertexGlsl );
20248	// console.log( '*FRAGMENT*', fragmentGlsl );
20249
20250	const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
20251	const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
20252
20253	gl.attachShader( program, glVertexShader );
20254	gl.attachShader( program, glFragmentShader );
20255
20256	// Force a particular attribute to index 0.
20257
20258	if ( parameters.index0AttributeName !== undefined ) {
20259
20260		gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
20261
20262	} else if ( parameters.morphTargets === true ) {
20263
20264		// programs with morphTargets displace position out of attribute 0
20265		gl.bindAttribLocation( program, 0, 'position' );
20266
20267	}
20268
20269	gl.linkProgram( program );
20270
20271	function onFirstUse( self ) {
20272
20273		// check for link errors
20274		if ( renderer.debug.checkShaderErrors ) {
20275
20276			const programLog = gl.getProgramInfoLog( program ).trim();
20277			const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
20278			const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
20279
20280			let runnable = true;
20281			let haveDiagnostics = true;
20282
20283			if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
20284
20285				runnable = false;
20286
20287				if ( typeof renderer.debug.onShaderError === 'function' ) {
20288
20289					renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );
20290
20291				} else {
20292
20293					// default error reporting
20294
20295					const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
20296					const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
20297
20298					console.error(
20299						'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
20300						'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
20301						'
vendor: 24,726 bytes, lines 20301-21198
20301Program Info Log: ' + programLog + '\n' +
20302						vertexErrors + '\n' +
20303						fragmentErrors
20304					);
20305
20306				}
20307
20308			} else if ( programLog !== '' ) {
20309
20310				console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );
20311
20312			} else if ( vertexLog === '' || fragmentLog === '' ) {
20313
20314				haveDiagnostics = false;
20315
20316			}
20317
20318			if ( haveDiagnostics ) {
20319
20320				self.diagnostics = {
20321
20322					runnable: runnable,
20323
20324					programLog: programLog,
20325
20326					vertexShader: {
20327
20328						log: vertexLog,
20329						prefix: prefixVertex
20330
20331					},
20332
20333					fragmentShader: {
20334
20335						log: fragmentLog,
20336						prefix: prefixFragment
20337
20338					}
20339
20340				};
20341
20342			}
20343
20344		}
20345
20346		// Clean up
20347
20348		// Crashes in iOS9 and iOS10. #18402
20349		// gl.detachShader( program, glVertexShader );
20350		// gl.detachShader( program, glFragmentShader );
20351
20352		gl.deleteShader( glVertexShader );
20353		gl.deleteShader( glFragmentShader );
20354
20355		cachedUniforms = new WebGLUniforms( gl, program );
20356		cachedAttributes = fetchAttributeLocations( gl, program );
20357
20358	}
20359
20360	// set up caching for uniform locations
20361
20362	let cachedUniforms;
20363
20364	this.getUniforms = function () {
20365
20366		if ( cachedUniforms === undefined ) {
20367
20368			// Populates cachedUniforms and cachedAttributes
20369			onFirstUse( this );
20370
20371		}
20372
20373		return cachedUniforms;
20374
20375	};
20376
20377	// set up caching for attribute locations
20378
20379	let cachedAttributes;
20380
20381	this.getAttributes = function () {
20382
20383		if ( cachedAttributes === undefined ) {
20384
20385			// Populates cachedAttributes and cachedUniforms
20386			onFirstUse( this );
20387
20388		}
20389
20390		return cachedAttributes;
20391
20392	};
20393
20394	// indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,
20395	// flag the program as ready immediately. It may cause a stall when it's first used.
20396
20397	let programReady = ( parameters.rendererExtensionParallelShaderCompile === false );
20398
20399	this.isReady = function () {
20400
20401		if ( programReady === false ) {
20402
20403			programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );
20404
20405		}
20406
20407		return programReady;
20408
20409	};
20410
20411	// free resource
20412
20413	this.destroy = function () {
20414
20415		bindingStates.releaseStatesOfProgram( this );
20416
20417		gl.deleteProgram( program );
20418		this.program = undefined;
20419
20420	};
20421
20422	//
20423
20424	this.type = parameters.shaderType;
20425	this.name = parameters.shaderName;
20426	this.id = programIdCount ++;
20427	this.cacheKey = cacheKey;
20428	this.usedTimes = 1;
20429	this.program = program;
20430	this.vertexShader = glVertexShader;
20431	this.fragmentShader = glFragmentShader;
20432
20433	return this;
20434
20435}
20436
20437let _id$1 = 0;
20438
20439class WebGLShaderCache {
20440
20441	constructor() {
20442
20443		this.shaderCache = new Map();
20444		this.materialCache = new Map();
20445
20446	}
20447
20448	update( material ) {
20449
20450		const vertexShader = material.vertexShader;
20451		const fragmentShader = material.fragmentShader;
20452
20453		const vertexShaderStage = this._getShaderStage( vertexShader );
20454		const fragmentShaderStage = this._getShaderStage( fragmentShader );
20455
20456		const materialShaders = this._getShaderCacheForMaterial( material );
20457
20458		if ( materialShaders.has( vertexShaderStage ) === false ) {
20459
20460			materialShaders.add( vertexShaderStage );
20461			vertexShaderStage.usedTimes ++;
20462
20463		}
20464
20465		if ( materialShaders.has( fragmentShaderStage ) === false ) {
20466
20467			materialShaders.add( fragmentShaderStage );
20468			fragmentShaderStage.usedTimes ++;
20469
20470		}
20471
20472		return this;
20473
20474	}
20475
20476	remove( material ) {
20477
20478		const materialShaders = this.materialCache.get( material );
20479
20480		for ( const shaderStage of materialShaders ) {
20481
20482			shaderStage.usedTimes --;
20483
20484			if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );
20485
20486		}
20487
20488		this.materialCache.delete( material );
20489
20490		return this;
20491
20492	}
20493
20494	getVertexShaderID( material ) {
20495
20496		return this._getShaderStage( material.vertexShader ).id;
20497
20498	}
20499
20500	getFragmentShaderID( material ) {
20501
20502		return this._getShaderStage( material.fragmentShader ).id;
20503
20504	}
20505
20506	dispose() {
20507
20508		this.shaderCache.clear();
20509		this.materialCache.clear();
20510
20511	}
20512
20513	_getShaderCacheForMaterial( material ) {
20514
20515		const cache = this.materialCache;
20516		let set = cache.get( material );
20517
20518		if ( set === undefined ) {
20519
20520			set = new Set();
20521			cache.set( material, set );
20522
20523		}
20524
20525		return set;
20526
20527	}
20528
20529	_getShaderStage( code ) {
20530
20531		const cache = this.shaderCache;
20532		let stage = cache.get( code );
20533
20534		if ( stage === undefined ) {
20535
20536			stage = new WebGLShaderStage( code );
20537			cache.set( code, stage );
20538
20539		}
20540
20541		return stage;
20542
20543	}
20544
20545}
20546
20547class WebGLShaderStage {
20548
20549	constructor( code ) {
20550
20551		this.id = _id$1 ++;
20552
20553		this.code = code;
20554		this.usedTimes = 0;
20555
20556	}
20557
20558}
20559
20560function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
20561
20562	const _programLayers = new Layers();
20563	const _customShaders = new WebGLShaderCache();
20564	const programs = [];
20565
20566	const IS_WEBGL2 = capabilities.isWebGL2;
20567	const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
20568	const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;
20569
20570	let precision = capabilities.precision;
20571
20572	const shaderIDs = {
20573		MeshDepthMaterial: 'depth',
20574		MeshDistanceMaterial: 'distanceRGBA',
20575		MeshNormalMaterial: 'normal',
20576		MeshBasicMaterial: 'basic',
20577		MeshLambertMaterial: 'lambert',
20578		MeshPhongMaterial: 'phong',
20579		MeshToonMaterial: 'toon',
20580		MeshStandardMaterial: 'physical',
20581		MeshPhysicalMaterial: 'physical',
20582		MeshMatcapMaterial: 'matcap',
20583		LineBasicMaterial: 'basic',
20584		LineDashedMaterial: 'dashed',
20585		PointsMaterial: 'points',
20586		ShadowMaterial: 'shadow',
20587		SpriteMaterial: 'sprite'
20588	};
20589
20590	function getChannel( value ) {
20591
20592		if ( value === 0 ) return 'uv';
20593
20594		return `uv${ value }`;
20595
20596	}
20597
20598	function getParameters( material, lights, shadows, scene, object ) {
20599
20600		const fog = scene.fog;
20601		const geometry = object.geometry;
20602		const environment = material.isMeshStandardMaterial ? scene.environment : null;
20603
20604		const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
20605		const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;
20606
20607		const shaderID = shaderIDs[ material.type ];
20608
20609		// heuristics to create shader parameters according to lights in the scene
20610		// (not to blow over maxLights budget)
20611
20612		if ( material.precision !== null ) {
20613
20614			precision = capabilities.getMaxPrecision( material.precision );
20615
20616			if ( precision !== material.precision ) {
20617
20618				console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
20619
20620			}
20621
20622		}
20623
20624		//
20625
20626		const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
20627		const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
20628
20629		let morphTextureStride = 0;
20630
20631		if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
20632		if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
20633		if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;
20634
20635		//
20636
20637		let vertexShader, fragmentShader;
20638		let customVertexShaderID, customFragmentShaderID;
20639
20640		if ( shaderID ) {
20641
20642			const shader = ShaderLib[ shaderID ];
20643
20644			vertexShader = shader.vertexShader;
20645			fragmentShader = shader.fragmentShader;
20646
20647		} else {
20648
20649			vertexShader = material.vertexShader;
20650			fragmentShader = material.fragmentShader;
20651
20652			_customShaders.update( material );
20653
20654			customVertexShaderID = _customShaders.getVertexShaderID( material );
20655			customFragmentShaderID = _customShaders.getFragmentShaderID( material );
20656
20657		}
20658
20659		const currentRenderTarget = renderer.getRenderTarget();
20660
20661		const IS_INSTANCEDMESH = object.isInstancedMesh === true;
20662		const IS_BATCHEDMESH = object.isBatchedMesh === true;
20663
20664		const HAS_MAP = !! material.map;
20665		const HAS_MATCAP = !! material.matcap;
20666		const HAS_ENVMAP = !! envMap;
20667		const HAS_AOMAP = !! material.aoMap;
20668		const HAS_LIGHTMAP = !! material.lightMap;
20669		const HAS_BUMPMAP = !! material.bumpMap;
20670		const HAS_NORMALMAP = !! material.normalMap;
20671		const HAS_DISPLACEMENTMAP = !! material.displacementMap;
20672		const HAS_EMISSIVEMAP = !! material.emissiveMap;
20673
20674		const HAS_METALNESSMAP = !! material.metalnessMap;
20675		const HAS_ROUGHNESSMAP = !! material.roughnessMap;
20676
20677		const HAS_ANISOTROPY = material.anisotropy > 0;
20678		const HAS_CLEARCOAT = material.clearcoat > 0;
20679		const HAS_IRIDESCENCE = material.iridescence > 0;
20680		const HAS_SHEEN = material.sheen > 0;
20681		const HAS_TRANSMISSION = material.transmission > 0;
20682
20683		const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap;
20684
20685		const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap;
20686		const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap;
20687		const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap;
20688
20689		const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap;
20690		const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap;
20691
20692		const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap;
20693		const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap;
20694
20695		const HAS_SPECULARMAP = !! material.specularMap;
20696		const HAS_SPECULAR_COLORMAP = !! material.specularColorMap;
20697		const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap;
20698
20699		const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap;
20700		const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap;
20701
20702		const HAS_GRADIENTMAP = !! material.gradientMap;
20703
20704		const HAS_ALPHAMAP = !! material.alphaMap;
20705
20706		const HAS_ALPHATEST = material.alphaTest > 0;
20707
20708		const HAS_ALPHAHASH = !! material.alphaHash;
20709
20710		const HAS_EXTENSIONS = !! material.extensions;
20711
20712		const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1;
20713		const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2;
20714		const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3;
20715
20716		let toneMapping = NoToneMapping;
20717
20718		if ( material.toneMapped ) {
20719
20720			if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {
20721
20722				toneMapping = renderer.toneMapping;
20723
20724			}
20725
20726		}
20727
20728		const parameters = {
20729
20730			isWebGL2: IS_WEBGL2,
20731
20732			shaderID: shaderID,
20733			shaderType: material.type,
20734			shaderName: material.name,
20735
20736			vertexShader: vertexShader,
20737			fragmentShader: fragmentShader,
20738			defines: material.defines,
20739
20740			customVertexShaderID: customVertexShaderID,
20741			customFragmentShaderID: customFragmentShaderID,
20742
20743			isRawShaderMaterial: material.isRawShaderMaterial === true,
20744			glslVersion: material.glslVersion,
20745
20746			precision: precision,
20747
20748			batching: IS_BATCHEDMESH,
20749			instancing: IS_INSTANCEDMESH,
20750			instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
20751
20752			supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,
20753			outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
20754
20755			map: HAS_MAP,
20756			matcap: HAS_MATCAP,
20757			envMap: HAS_ENVMAP,
20758			envMapMode: HAS_ENVMAP && envMap.mapping,
20759			envMapCubeUVHeight: envMapCubeUVHeight,
20760			aoMap: HAS_AOMAP,
20761			lightMap: HAS_LIGHTMAP,
20762			bumpMap: HAS_BUMPMAP,
20763			normalMap: HAS_NORMALMAP,
20764			displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,
20765			emissiveMap: HAS_EMISSIVEMAP,
20766
20767			normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap,
20768			normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap,
20769
20770			metalnessMap: HAS_METALNESSMAP,
20771			roughnessMap: HAS_ROUGHNESSMAP,
20772
20773			anisotropy: HAS_ANISOTROPY,
20774			anisotropyMap: HAS_ANISOTROPYMAP,
20775
20776			clearcoat: HAS_CLEARCOAT,
20777			clearcoatMap: HAS_CLEARCOATMAP,
20778			clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP,
20779			clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP,
20780
20781			iridescence: HAS_IRIDESCENCE,
20782			iridescenceMap: HAS_IRIDESCENCEMAP,
20783			iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,
20784
20785			sheen: HAS_SHEEN,
20786			sheenColorMap: HAS_SHEEN_COLORMAP,
20787			sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,
20788
20789			specularMap: HAS_SPECULARMAP,
20790			specularColorMap: HAS_SPECULAR_COLORMAP,
20791			specularIntensityMap: HAS_SPECULAR_INTENSITYMAP,
20792
20793			transmission: HAS_TRANSMISSION,
20794			transmissionMap: HAS_TRANSMISSIONMAP,
20795			thicknessMap: HAS_THICKNESSMAP,
20796
20797			gradientMap: HAS_GRADIENTMAP,
20798
20799			opaque: material.transparent === false && material.blending === NormalBlending,
20800
20801			alphaMap: HAS_ALPHAMAP,
20802			alphaTest: HAS_ALPHATEST,
20803			alphaHash: HAS_ALPHAHASH,
20804
20805			combine: material.combine,
20806
20807			//
20808
20809			mapUv: HAS_MAP && getChannel( material.map.channel ),
20810			aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ),
20811			lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ),
20812			bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ),
20813			normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ),
20814			displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ),
20815			emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ),
20816
20817			metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ),
20818			roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ),
20819
20820			anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ),
20821
20822			clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ),
20823			clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ),
20824			clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ),
20825
20826			iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ),
20827			iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ),
20828
20829			sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ),
20830			sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ),
20831
20832			specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ),
20833			specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ),
20834			specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ),
20835
20836			transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ),
20837			thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ),
20838
20839			alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ),
20840
20841			//
20842
20843			vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ),
20844			vertexColors: material.vertexColors,
20845			vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,
20846			vertexUv1s: HAS_ATTRIBUTE_UV1,
20847			vertexUv2s: HAS_ATTRIBUTE_UV2,
20848			vertexUv3s: HAS_ATTRIBUTE_UV3,
20849
20850			pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),
20851
20852			fog: !! fog,
20853			useFog: material.fog === true,
20854			fogExp2: ( fog && fog.isFogExp2 ),
20855
20856			flatShading: material.flatShading === true,
20857
20858			sizeAttenuation: material.sizeAttenuation === true,
20859			logarithmicDepthBuffer: logarithmicDepthBuffer,
20860
20861			skinning: object.isSkinnedMesh === true,
20862
20863			morphTargets: geometry.morphAttributes.position !== undefined,
20864			morphNormals: geometry.morphAttributes.normal !== undefined,
20865			morphColors: geometry.morphAttributes.color !== undefined,
20866			morphTargetsCount: morphTargetsCount,
20867			morphTextureStride: morphTextureStride,
20868
20869			numDirLights: lights.directional.length,
20870			numPointLights: lights.point.length,
20871			numSpotLights: lights.spot.length,
20872			numSpotLightMaps: lights.spotLightMap.length,
20873			numRectAreaLights: lights.rectArea.length,
20874			numHemiLights: lights.hemi.length,
20875
20876			numDirLightShadows: lights.directionalShadowMap.length,
20877			numPointLightShadows: lights.pointShadowMap.length,
20878			numSpotLightShadows: lights.spotShadowMap.length,
20879			numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,
20880
20881			numLightProbes: lights.numLightProbes,
20882
20883			numClippingPlanes: clipping.numPlanes,
20884			numClipIntersection: clipping.numIntersection,
20885
20886			dithering: material.dithering,
20887
20888			shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
20889			shadowMapType: renderer.shadowMap.type,
20890
20891			toneMapping: toneMapping,
20892			useLegacyLights: renderer._useLegacyLights,
20893
20894			decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),
20895
20896			premultipliedAlpha: material.premultipliedAlpha,
20897
20898			doubleSided: material.side === DoubleSide,
20899			flipSided: material.side === BackSide,
20900
20901			useDepthPacking: material.depthPacking >= 0,
20902			depthPacking: material.depthPacking || 0,
20903
20904			index0AttributeName: material.index0AttributeName,
20905
20906			extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true,
20907			extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true,
20908			extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true,
20909			extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true,
20910			extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ),
20911
20912			rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ),
20913			rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ),
20914			rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ),
20915			rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),
20916
20917			customProgramCacheKey: material.customProgramCacheKey()
20918
20919		};
20920
20921		return parameters;
20922
20923	}
20924
20925	function getProgramCacheKey( parameters ) {
20926
20927		const array = [];
20928
20929		if ( parameters.shaderID ) {
20930
20931			array.push( parameters.shaderID );
20932
20933		} else {
20934
20935			array.push( parameters.customVertexShaderID );
20936			array.push( parameters.customFragmentShaderID );
20937
20938		}
20939
20940		if ( parameters.defines !== undefined ) {
20941
20942			for ( const name in parameters.defines ) {
20943
20944				array.push( name );
20945				array.push( parameters.defines[ name ] );
20946
20947			}
20948
20949		}
20950
20951		if ( parameters.isRawShaderMaterial === false ) {
20952
20953			getProgramCacheKeyParameters( array, parameters );
20954			getProgramCacheKeyBooleans( array, parameters );
20955			array.push( renderer.outputColorSpace );
20956
20957		}
20958
20959		array.push( parameters.customProgramCacheKey );
20960
20961		return array.join();
20962
20963	}
20964
20965	function getProgramCacheKeyParameters( array, parameters ) {
20966
20967		array.push( parameters.precision );
20968		array.push( parameters.outputColorSpace );
20969		array.push( parameters.envMapMode );
20970		array.push( parameters.envMapCubeUVHeight );
20971		array.push( parameters.mapUv );
20972		array.push( parameters.alphaMapUv );
20973		array.push( parameters.lightMapUv );
20974		array.push( parameters.aoMapUv );
20975		array.push( parameters.bumpMapUv );
20976		array.push( parameters.normalMapUv );
20977		array.push( parameters.displacementMapUv );
20978		array.push( parameters.emissiveMapUv );
20979		array.push( parameters.metalnessMapUv );
20980		array.push( parameters.roughnessMapUv );
20981		array.push( parameters.anisotropyMapUv );
20982		array.push( parameters.clearcoatMapUv );
20983		array.push( parameters.clearcoatNormalMapUv );
20984		array.push( parameters.clearcoatRoughnessMapUv );
20985		array.push( parameters.iridescenceMapUv );
20986		array.push( parameters.iridescenceThicknessMapUv );
20987		array.push( parameters.sheenColorMapUv );
20988		array.push( parameters.sheenRoughnessMapUv );
20989		array.push( parameters.specularMapUv );
20990		array.push( parameters.specularColorMapUv );
20991		array.push( parameters.specularIntensityMapUv );
20992		array.push( parameters.transmissionMapUv );
20993		array.push( parameters.thicknessMapUv );
20994		array.push( parameters.combine );
20995		array.push( parameters.fogExp2 );
20996		array.push( parameters.sizeAttenuation );
20997		array.push( parameters.morphTargetsCount );
20998		array.push( parameters.morphAttributeCount );
20999		array.push( parameters.numDirLights );
21000		array.push( parameters.numPointLights );
21001		array.push( parameters.numSpotLights );
21002		array.push( parameters.numSpotLightMaps );
21003		array.push( parameters.numHemiLights );
21004		array.push( parameters.numRectAreaLights );
21005		array.push( parameters.numDirLightShadows );
21006		array.push( parameters.numPointLightShadows );
21007		array.push( parameters.numSpotLightShadows );
21008		array.push( parameters.numSpotLightShadowsWithMaps );
21009		array.push( parameters.numLightProbes );
21010		array.push( parameters.shadowMapType );
21011		array.push( parameters.toneMapping );
21012		array.push( parameters.numClippingPlanes );
21013		array.push( parameters.numClipIntersection );
21014		array.push( parameters.depthPacking );
21015
21016	}
21017
21018	function getProgramCacheKeyBooleans( array, parameters ) {
21019
21020		_programLayers.disableAll();
21021
21022		if ( parameters.isWebGL2 )
21023			_programLayers.enable( 0 );
21024		if ( parameters.supportsVertexTextures )
21025			_programLayers.enable( 1 );
21026		if ( parameters.instancing )
21027			_programLayers.enable( 2 );
21028		if ( parameters.instancingColor )
21029			_programLayers.enable( 3 );
21030		if ( parameters.matcap )
21031			_programLayers.enable( 4 );
21032		if ( parameters.envMap )
21033			_programLayers.enable( 5 );
21034		if ( parameters.normalMapObjectSpace )
21035			_programLayers.enable( 6 );
21036		if ( parameters.normalMapTangentSpace )
21037			_programLayers.enable( 7 );
21038		if ( parameters.clearcoat )
21039			_programLayers.enable( 8 );
21040		if ( parameters.iridescence )
21041			_programLayers.enable( 9 );
21042		if ( parameters.alphaTest )
21043			_programLayers.enable( 10 );
21044		if ( parameters.vertexColors )
21045			_programLayers.enable( 11 );
21046		if ( parameters.vertexAlphas )
21047			_programLayers.enable( 12 );
21048		if ( parameters.vertexUv1s )
21049			_programLayers.enable( 13 );
21050		if ( parameters.vertexUv2s )
21051			_programLayers.enable( 14 );
21052		if ( parameters.vertexUv3s )
21053			_programLayers.enable( 15 );
21054		if ( parameters.vertexTangents )
21055			_programLayers.enable( 16 );
21056		if ( parameters.anisotropy )
21057			_programLayers.enable( 17 );
21058		if ( parameters.alphaHash )
21059			_programLayers.enable( 18 );
21060		if ( parameters.batching )
21061			_programLayers.enable( 19 );
21062
21063		array.push( _programLayers.mask );
21064		_programLayers.disableAll();
21065
21066		if ( parameters.fog )
21067			_programLayers.enable( 0 );
21068		if ( parameters.useFog )
21069			_programLayers.enable( 1 );
21070		if ( parameters.flatShading )
21071			_programLayers.enable( 2 );
21072		if ( parameters.logarithmicDepthBuffer )
21073			_programLayers.enable( 3 );
21074		if ( parameters.skinning )
21075			_programLayers.enable( 4 );
21076		if ( parameters.morphTargets )
21077			_programLayers.enable( 5 );
21078		if ( parameters.morphNormals )
21079			_programLayers.enable( 6 );
21080		if ( parameters.morphColors )
21081			_programLayers.enable( 7 );
21082		if ( parameters.premultipliedAlpha )
21083			_programLayers.enable( 8 );
21084		if ( parameters.shadowMapEnabled )
21085			_programLayers.enable( 9 );
21086		if ( parameters.useLegacyLights )
21087			_programLayers.enable( 10 );
21088		if ( parameters.doubleSided )
21089			_programLayers.enable( 11 );
21090		if ( parameters.flipSided )
21091			_programLayers.enable( 12 );
21092		if ( parameters.useDepthPacking )
21093			_programLayers.enable( 13 );
21094		if ( parameters.dithering )
21095			_programLayers.enable( 14 );
21096		if ( parameters.transmission )
21097			_programLayers.enable( 15 );
21098		if ( parameters.sheen )
21099			_programLayers.enable( 16 );
21100		if ( parameters.opaque )
21101			_programLayers.enable( 17 );
21102		if ( parameters.pointsUvs )
21103			_programLayers.enable( 18 );
21104		if ( parameters.decodeVideoTexture )
21105			_programLayers.enable( 19 );
21106
21107		array.push( _programLayers.mask );
21108
21109	}
21110
21111	function getUniforms( material ) {
21112
21113		const shaderID = shaderIDs[ material.type ];
21114		let uniforms;
21115
21116		if ( shaderID ) {
21117
21118			const shader = ShaderLib[ shaderID ];
21119			uniforms = UniformsUtils.clone( shader.uniforms );
21120
21121		} else {
21122
21123			uniforms = material.uniforms;
21124
21125		}
21126
21127		return uniforms;
21128
21129	}
21130
21131	function acquireProgram( parameters, cacheKey ) {
21132
21133		let program;
21134
21135		// Check if code has been already compiled
21136		for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
21137
21138			const preexistingProgram = programs[ p ];
21139
21140			if ( preexistingProgram.cacheKey === cacheKey ) {
21141
21142				program = preexistingProgram;
21143				++ program.usedTimes;
21144
21145				break;
21146
21147			}
21148
21149		}
21150
21151		if ( program === undefined ) {
21152
21153			program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
21154			programs.push( program );
21155
21156		}
21157
21158		return program;
21159
21160	}
21161
21162	function releaseProgram( program ) {
21163
21164		if ( -- program.usedTimes === 0 ) {
21165
21166			// Remove from unordered set
21167			const i = programs.indexOf( program );
21168			programs[ i ] = programs[ programs.length - 1 ];
21169			programs.pop();
21170
21171			// Free WebGL resources
21172			program.destroy();
21173
21174		}
21175
21176	}
21177
21178	function releaseShaderCache( material ) {
21179
21180		_customShaders.remove( material );
21181
21182	}
21183
21184	function dispose() {
21185
21186		_customShaders.dispose();
21187
21188	}
21189
21190	return {
21191		getParameters: getParameters,
21192		getProgramCacheKey: getProgramCacheKey,
21193		getUniforms: getUniforms,
21194		acquireProgram: acquireProgram,
21195		releaseProgram: releaseProgram,
21196		releaseShaderCache: releaseShaderCache,
21197		// Exposed for resource monitoring & error feedback via renderer.info:
21198		programs: programs,
vendor: 4,538 bytes, lines 21199-21480
21199		dispose: dispose
21200	};
21201
21202}
21203
21204function WebGLProperties() {
21205
21206	let properties = new WeakMap();
21207
21208	function get( object ) {
21209
21210		let map = properties.get( object );
21211
21212		if ( map === undefined ) {
21213
21214			map = {};
21215			properties.set( object, map );
21216
21217		}
21218
21219		return map;
21220
21221	}
21222
21223	function remove( object ) {
21224
21225		properties.delete( object );
21226
21227	}
21228
21229	function update( object, key, value ) {
21230
21231		properties.get( object )[ key ] = value;
21232
21233	}
21234
21235	function dispose() {
21236
21237		properties = new WeakMap();
21238
21239	}
21240
21241	return {
21242		get: get,
21243		remove: remove,
21244		update: update,
21245		dispose: dispose
21246	};
21247
21248}
21249
21250function painterSortStable( a, b ) {
21251
21252	if ( a.groupOrder !== b.groupOrder ) {
21253
21254		return a.groupOrder - b.groupOrder;
21255
21256	} else if ( a.renderOrder !== b.renderOrder ) {
21257
21258		return a.renderOrder - b.renderOrder;
21259
21260	} else if ( a.material.id !== b.material.id ) {
21261
21262		return a.material.id - b.material.id;
21263
21264	} else if ( a.z !== b.z ) {
21265
21266		return a.z - b.z;
21267
21268	} else {
21269
21270		return a.id - b.id;
21271
21272	}
21273
21274}
21275
21276function reversePainterSortStable( a, b ) {
21277
21278	if ( a.groupOrder !== b.groupOrder ) {
21279
21280		return a.groupOrder - b.groupOrder;
21281
21282	} else if ( a.renderOrder !== b.renderOrder ) {
21283
21284		return a.renderOrder - b.renderOrder;
21285
21286	} else if ( a.z !== b.z ) {
21287
21288		return b.z - a.z;
21289
21290	} else {
21291
21292		return a.id - b.id;
21293
21294	}
21295
21296}
21297
21298
21299function WebGLRenderList() {
21300
21301	const renderItems = [];
21302	let renderItemsIndex = 0;
21303
21304	const opaque = [];
21305	const transmissive = [];
21306	const transparent = [];
21307
21308	function init() {
21309
21310		renderItemsIndex = 0;
21311
21312		opaque.length = 0;
21313		transmissive.length = 0;
21314		transparent.length = 0;
21315
21316	}
21317
21318	function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
21319
21320		let renderItem = renderItems[ renderItemsIndex ];
21321
21322		if ( renderItem === undefined ) {
21323
21324			renderItem = {
21325				id: object.id,
21326				object: object,
21327				geometry: geometry,
21328				material: material,
21329				groupOrder: groupOrder,
21330				renderOrder: object.renderOrder,
21331				z: z,
21332				group: group
21333			};
21334
21335			renderItems[ renderItemsIndex ] = renderItem;
21336
21337		} else {
21338
21339			renderItem.id = object.id;
21340			renderItem.object = object;
21341			renderItem.geometry = geometry;
21342			renderItem.material = material;
21343			renderItem.groupOrder = groupOrder;
21344			renderItem.renderOrder = object.renderOrder;
21345			renderItem.z = z;
21346			renderItem.group = group;
21347
21348		}
21349
21350		renderItemsIndex ++;
21351
21352		return renderItem;
21353
21354	}
21355
21356	function push( object, geometry, material, groupOrder, z, group ) {
21357
21358		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21359
21360		if ( material.transmission > 0.0 ) {
21361
21362			transmissive.push( renderItem );
21363
21364		} else if ( material.transparent === true ) {
21365
21366			transparent.push( renderItem );
21367
21368		} else {
21369
21370			opaque.push( renderItem );
21371
21372		}
21373
21374	}
21375
21376	function unshift( object, geometry, material, groupOrder, z, group ) {
21377
21378		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21379
21380		if ( material.transmission > 0.0 ) {
21381
21382			transmissive.unshift( renderItem );
21383
21384		} else if ( material.transparent === true ) {
21385
21386			transparent.unshift( renderItem );
21387
21388		} else {
21389
21390			opaque.unshift( renderItem );
21391
21392		}
21393
21394	}
21395
21396	function sort( customOpaqueSort, customTransparentSort ) {
21397
21398		if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
21399		if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
21400		if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
21401
21402	}
21403
21404	function finish() {
21405
21406		// Clear references from inactive renderItems in the list
21407
21408		for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
21409
21410			const renderItem = renderItems[ i ];
21411
21412			if ( renderItem.id === null ) break;
21413
21414			renderItem.id = null;
21415			renderItem.object = null;
21416			renderItem.geometry = null;
21417			renderItem.material = null;
21418			renderItem.group = null;
21419
21420		}
21421
21422	}
21423
21424	return {
21425
21426		opaque: opaque,
21427		transmissive: transmissive,
21428		transparent: transparent,
21429
21430		init: init,
21431		push: push,
21432		unshift: unshift,
21433		finish: finish,
21434
21435		sort: sort
21436	};
21437
21438}
21439
21440function WebGLRenderLists() {
21441
21442	let lists = new WeakMap();
21443
21444	function get( scene, renderCallDepth ) {
21445
21446		const listArray = lists.get( scene );
21447		let list;
21448
21449		if ( listArray === undefined ) {
21450
21451			list = new WebGLRenderList();
21452			lists.set( scene, [ list ] );
21453
21454		} else {
21455
21456			if ( renderCallDepth >= listArray.length ) {
21457
21458				list = new WebGLRenderList();
21459				listArray.push( list );
21460
21461			} else {
21462
21463				list = listArray[ renderCallDepth ];
21464
21465			}
21466
21467		}
21468
21469		return list;
21470
21471	}
21472
21473	function dispose() {
21474
21475		lists = new WeakMap();
21476
21477	}
21478
21479	return {
21480		get: get,
vendor: 2,723 bytes, lines 21481-21654
21481		dispose: dispose
21482	};
21483
21484}
21485
21486function UniformsCache() {
21487
21488	const lights = {};
21489
21490	return {
21491
21492		get: function ( light ) {
21493
21494			if ( lights[ light.id ] !== undefined ) {
21495
21496				return lights[ light.id ];
21497
21498			}
21499
21500			let uniforms;
21501
21502			switch ( light.type ) {
21503
21504				case 'DirectionalLight':
21505					uniforms = {
21506						direction: new Vector3(),
21507						color: new Color()
21508					};
21509					break;
21510
21511				case 'SpotLight':
21512					uniforms = {
21513						position: new Vector3(),
21514						direction: new Vector3(),
21515						color: new Color(),
21516						distance: 0,
21517						coneCos: 0,
21518						penumbraCos: 0,
21519						decay: 0
21520					};
21521					break;
21522
21523				case 'PointLight':
21524					uniforms = {
21525						position: new Vector3(),
21526						color: new Color(),
21527						distance: 0,
21528						decay: 0
21529					};
21530					break;
21531
21532				case 'HemisphereLight':
21533					uniforms = {
21534						direction: new Vector3(),
21535						skyColor: new Color(),
21536						groundColor: new Color()
21537					};
21538					break;
21539
21540				case 'RectAreaLight':
21541					uniforms = {
21542						color: new Color(),
21543						position: new Vector3(),
21544						halfWidth: new Vector3(),
21545						halfHeight: new Vector3()
21546					};
21547					break;
21548
21549			}
21550
21551			lights[ light.id ] = uniforms;
21552
21553			return uniforms;
21554
21555		}
21556
21557	};
21558
21559}
21560
21561function ShadowUniformsCache() {
21562
21563	const lights = {};
21564
21565	return {
21566
21567		get: function ( light ) {
21568
21569			if ( lights[ light.id ] !== undefined ) {
21570
21571				return lights[ light.id ];
21572
21573			}
21574
21575			let uniforms;
21576
21577			switch ( light.type ) {
21578
21579				case 'DirectionalLight':
21580					uniforms = {
21581						shadowBias: 0,
21582						shadowNormalBias: 0,
21583						shadowRadius: 1,
21584						shadowMapSize: new Vector2()
21585					};
21586					break;
21587
21588				case 'SpotLight':
21589					uniforms = {
21590						shadowBias: 0,
21591						shadowNormalBias: 0,
21592						shadowRadius: 1,
21593						shadowMapSize: new Vector2()
21594					};
21595					break;
21596
21597				case 'PointLight':
21598					uniforms = {
21599						shadowBias: 0,
21600						shadowNormalBias: 0,
21601						shadowRadius: 1,
21602						shadowMapSize: new Vector2(),
21603						shadowCameraNear: 1,
21604						shadowCameraFar: 1000
21605					};
21606					break;
21607
21608				// TODO (abelnation): set RectAreaLight shadow uniforms
21609
21610			}
21611
21612			lights[ light.id ] = uniforms;
21613
21614			return uniforms;
21615
21616		}
21617
21618	};
21619
21620}
21621
21622
21623
21624let nextVersion = 0;
21625
21626function shadowCastingAndTexturingLightsFirst( lightA, lightB ) {
21627
21628	return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );
21629
21630}
21631
21632function WebGLLights( extensions, capabilities ) {
21633
21634	const cache = new UniformsCache();
21635
21636	const shadowCache = ShadowUniformsCache();
21637
21638	const state = {
21639
21640		version: 0,
21641
21642		hash: {
21643			directionalLength: - 1,
21644			pointLength: - 1,
21645			spotLength: - 1,
21646			rectAreaLength: - 1,
21647			hemiLength: - 1,
21648
21649			numDirectionalShadows: - 1,
21650			numPointShadows: - 1,
21651			numSpotShadows: - 1,
21652			numSpotMaps: - 1,
21653
21654			numLightProbes: - 
vendor: 16,167 bytes, lines 21654-22305
216541
21655		},
21656
21657		ambient: [ 0, 0, 0 ],
21658		probe: [],
21659		directional: [],
21660		directionalShadow: [],
21661		directionalShadowMap: [],
21662		directionalShadowMatrix: [],
21663		spot: [],
21664		spotLightMap: [],
21665		spotShadow: [],
21666		spotShadowMap: [],
21667		spotLightMatrix: [],
21668		rectArea: [],
21669		rectAreaLTC1: null,
21670		rectAreaLTC2: null,
21671		point: [],
21672		pointShadow: [],
21673		pointShadowMap: [],
21674		pointShadowMatrix: [],
21675		hemi: [],
21676		numSpotLightShadowsWithMaps: 0,
21677		numLightProbes: 0
21678
21679	};
21680
21681	for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
21682
21683	const vector3 = new Vector3();
21684	const matrix4 = new Matrix4();
21685	const matrix42 = new Matrix4();
21686
21687	function setup( lights, useLegacyLights ) {
21688
21689		let r = 0, g = 0, b = 0;
21690
21691		for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
21692
21693		let directionalLength = 0;
21694		let pointLength = 0;
21695		let spotLength = 0;
21696		let rectAreaLength = 0;
21697		let hemiLength = 0;
21698
21699		let numDirectionalShadows = 0;
21700		let numPointShadows = 0;
21701		let numSpotShadows = 0;
21702		let numSpotMaps = 0;
21703		let numSpotShadowsWithMaps = 0;
21704
21705		let numLightProbes = 0;
21706
21707		// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
21708		lights.sort( shadowCastingAndTexturingLightsFirst );
21709
21710		// artist-friendly light intensity scaling factor
21711		const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1;
21712
21713		for ( let i = 0, l = lights.length; i < l; i ++ ) {
21714
21715			const light = lights[ i ];
21716
21717			const color = light.color;
21718			const intensity = light.intensity;
21719			const distance = light.distance;
21720
21721			const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
21722
21723			if ( light.isAmbientLight ) {
21724
21725				r += color.r * intensity * scaleFactor;
21726				g += color.g * intensity * scaleFactor;
21727				b += color.b * intensity * scaleFactor;
21728
21729			} else if ( light.isLightProbe ) {
21730
21731				for ( let j = 0; j < 9; j ++ ) {
21732
21733					state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
21734
21735				}
21736
21737				numLightProbes ++;
21738
21739			} else if ( light.isDirectionalLight ) {
21740
21741				const uniforms = cache.get( light );
21742
21743				uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21744
21745				if ( light.castShadow ) {
21746
21747					const shadow = light.shadow;
21748
21749					const shadowUniforms = shadowCache.get( light );
21750
21751					shadowUniforms.shadowBias = shadow.bias;
21752					shadowUniforms.shadowNormalBias = shadow.normalBias;
21753					shadowUniforms.shadowRadius = shadow.radius;
21754					shadowUniforms.shadowMapSize = shadow.mapSize;
21755
21756					state.directionalShadow[ directionalLength ] = shadowUniforms;
21757					state.directionalShadowMap[ directionalLength ] = shadowMap;
21758					state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
21759
21760					numDirectionalShadows ++;
21761
21762				}
21763
21764				state.directional[ directionalLength ] = uniforms;
21765
21766				directionalLength ++;
21767
21768			} else if ( light.isSpotLight ) {
21769
21770				const uniforms = cache.get( light );
21771
21772				uniforms.position.setFromMatrixPosition( light.matrixWorld );
21773
21774				uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor );
21775				uniforms.distance = distance;
21776
21777				uniforms.coneCos = Math.cos( light.angle );
21778				uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
21779				uniforms.decay = light.decay;
21780
21781				state.spot[ spotLength ] = uniforms;
21782
21783				const shadow = light.shadow;
21784
21785				if ( light.map ) {
21786
21787					state.spotLightMap[ numSpotMaps ] = light.map;
21788					numSpotMaps ++;
21789
21790					// make sure the lightMatrix is up to date
21791					// TODO : do it if required only
21792					shadow.updateMatrices( light );
21793
21794					if ( light.castShadow ) numSpotShadowsWithMaps ++;
21795
21796				}
21797
21798				state.spotLightMatrix[ spotLength ] = shadow.matrix;
21799
21800				if ( light.castShadow ) {
21801
21802					const shadowUniforms = shadowCache.get( light );
21803
21804					shadowUniforms.shadowBias = shadow.bias;
21805					shadowUniforms.shadowNormalBias = shadow.normalBias;
21806					shadowUniforms.shadowRadius = shadow.radius;
21807					shadowUniforms.shadowMapSize = shadow.mapSize;
21808
21809					state.spotShadow[ spotLength ] = shadowUniforms;
21810					state.spotShadowMap[ spotLength ] = shadowMap;
21811
21812					numSpotShadows ++;
21813
21814				}
21815
21816				spotLength ++;
21817
21818			} else if ( light.isRectAreaLight ) {
21819
21820				const uniforms = cache.get( light );
21821
21822				uniforms.color.copy( color ).multiplyScalar( intensity );
21823
21824				uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
21825				uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
21826
21827				state.rectArea[ rectAreaLength ] = uniforms;
21828
21829				rectAreaLength ++;
21830
21831			} else if ( light.isPointLight ) {
21832
21833				const uniforms = cache.get( light );
21834
21835				uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21836				uniforms.distance = light.distance;
21837				uniforms.decay = light.decay;
21838
21839				if ( light.castShadow ) {
21840
21841					const shadow = light.shadow;
21842
21843					const shadowUniforms = shadowCache.get( light );
21844
21845					shadowUniforms.shadowBias = shadow.bias;
21846					shadowUniforms.shadowNormalBias = shadow.normalBias;
21847					shadowUniforms.shadowRadius = shadow.radius;
21848					shadowUniforms.shadowMapSize = shadow.mapSize;
21849					shadowUniforms.shadowCameraNear = shadow.camera.near;
21850					shadowUniforms.shadowCameraFar = shadow.camera.far;
21851
21852					state.pointShadow[ pointLength ] = shadowUniforms;
21853					state.pointShadowMap[ pointLength ] = shadowMap;
21854					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
21855
21856					numPointShadows ++;
21857
21858				}
21859
21860				state.point[ pointLength ] = uniforms;
21861
21862				pointLength ++;
21863
21864			} else if ( light.isHemisphereLight ) {
21865
21866				const uniforms = cache.get( light );
21867
21868				uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor );
21869				uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor );
21870
21871				state.hemi[ hemiLength ] = uniforms;
21872
21873				hemiLength ++;
21874
21875			}
21876
21877		}
21878
21879		if ( rectAreaLength > 0 ) {
21880
21881			if ( capabilities.isWebGL2 ) {
21882
21883				// WebGL 2
21884
21885				if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21886
21887					state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21888					state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21889
21890				} else {
21891
21892					state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21893					state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21894
21895				}
21896
21897			} else {
21898
21899				// WebGL 1
21900
21901				if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21902
21903					state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21904					state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21905
21906				} else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
21907
21908					state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21909					state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21910
21911				} else {
21912
21913					console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
21914
21915				}
21916
21917			}
21918
21919		}
21920
21921		state.ambient[ 0 ] = r;
21922		state.ambient[ 1 ] = g;
21923		state.ambient[ 2 ] = b;
21924
21925		const hash = state.hash;
21926
21927		if ( hash.directionalLength !== directionalLength ||
21928			hash.pointLength !== pointLength ||
21929			hash.spotLength !== spotLength ||
21930			hash.rectAreaLength !== rectAreaLength ||
21931			hash.hemiLength !== hemiLength ||
21932			hash.numDirectionalShadows !== numDirectionalShadows ||
21933			hash.numPointShadows !== numPointShadows ||
21934			hash.numSpotShadows !== numSpotShadows ||
21935			hash.numSpotMaps !== numSpotMaps ||
21936			hash.numLightProbes !== numLightProbes ) {
21937
21938			state.directional.length = directionalLength;
21939			state.spot.length = spotLength;
21940			state.rectArea.length = rectAreaLength;
21941			state.point.length = pointLength;
21942			state.hemi.length = hemiLength;
21943
21944			state.directionalShadow.length = numDirectionalShadows;
21945			state.directionalShadowMap.length = numDirectionalShadows;
21946			state.pointShadow.length = numPointShadows;
21947			state.pointShadowMap.length = numPointShadows;
21948			state.spotShadow.length = numSpotShadows;
21949			state.spotShadowMap.length = numSpotShadows;
21950			state.directionalShadowMatrix.length = numDirectionalShadows;
21951			state.pointShadowMatrix.length = numPointShadows;
21952			state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
21953			state.spotLightMap.length = numSpotMaps;
21954			state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
21955			state.numLightProbes = numLightProbes;
21956
21957			hash.directionalLength = directionalLength;
21958			hash.pointLength = pointLength;
21959			hash.spotLength = spotLength;
21960			hash.rectAreaLength = rectAreaLength;
21961			hash.hemiLength = hemiLength;
21962
21963			hash.numDirectionalShadows = numDirectionalShadows;
21964			hash.numPointShadows = numPointShadows;
21965			hash.numSpotShadows = numSpotShadows;
21966			hash.numSpotMaps = numSpotMaps;
21967
21968			hash.numLightProbes = numLightProbes;
21969
21970			state.version = nextVersion ++;
21971
21972		}
21973
21974	}
21975
21976	function setupView( lights, camera ) {
21977
21978		let directionalLength = 0;
21979		let pointLength = 0;
21980		let spotLength = 0;
21981		let rectAreaLength = 0;
21982		let hemiLength = 0;
21983
21984		const viewMatrix = camera.matrixWorldInverse;
21985
21986		for ( let i = 0, l = lights.length; i < l; i ++ ) {
21987
21988			const light = lights[ i ];
21989
21990			if ( light.isDirectionalLight ) {
21991
21992				const uniforms = state.directional[ directionalLength ];
21993
21994				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
21995				vector3.setFromMatrixPosition( light.target.matrixWorld );
21996				uniforms.direction.sub( vector3 );
21997				uniforms.direction.transformDirection( viewMatrix );
21998
21999				directionalLength ++;
22000
22001			} else if ( light.isSpotLight ) {
22002
22003				const uniforms = state.spot[ spotLength ];
22004
22005				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22006				uniforms.position.applyMatrix4( viewMatrix );
22007
22008				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22009				vector3.setFromMatrixPosition( light.target.matrixWorld );
22010				uniforms.direction.sub( vector3 );
22011				uniforms.direction.transformDirection( viewMatrix );
22012
22013				spotLength ++;
22014
22015			} else if ( light.isRectAreaLight ) {
22016
22017				const uniforms = state.rectArea[ rectAreaLength ];
22018
22019				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22020				uniforms.position.applyMatrix4( viewMatrix );
22021
22022				// extract local rotation of light to derive width/height half vectors
22023				matrix42.identity();
22024				matrix4.copy( light.matrixWorld );
22025				matrix4.premultiply( viewMatrix );
22026				matrix42.extractRotation( matrix4 );
22027
22028				uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22029				uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22030
22031				uniforms.halfWidth.applyMatrix4( matrix42 );
22032				uniforms.halfHeight.applyMatrix4( matrix42 );
22033
22034				rectAreaLength ++;
22035
22036			} else if ( light.isPointLight ) {
22037
22038				const uniforms = state.point[ pointLength ];
22039
22040				uniforms.position.setFromMatrixPosition( light.matrixWorld );
22041				uniforms.position.applyMatrix4( viewMatrix );
22042
22043				pointLength ++;
22044
22045			} else if ( light.isHemisphereLight ) {
22046
22047				const uniforms = state.hemi[ hemiLength ];
22048
22049				uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22050				uniforms.direction.transformDirection( viewMatrix );
22051
22052				hemiLength ++;
22053
22054			}
22055
22056		}
22057
22058	}
22059
22060	return {
22061		setup: setup,
22062		setupView: setupView,
22063		state: state
22064	};
22065
22066}
22067
22068function WebGLRenderState( extensions, capabilities ) {
22069
22070	const lights = new WebGLLights( extensions, capabilities );
22071
22072	const lightsArray = [];
22073	const shadowsArray = [];
22074
22075	function init() {
22076
22077		lightsArray.length = 0;
22078		shadowsArray.length = 0;
22079
22080	}
22081
22082	function pushLight( light ) {
22083
22084		lightsArray.push( light );
22085
22086	}
22087
22088	function pushShadow( shadowLight ) {
22089
22090		shadowsArray.push( shadowLight );
22091
22092	}
22093
22094	function setupLights( useLegacyLights ) {
22095
22096		lights.setup( lightsArray, useLegacyLights );
22097
22098	}
22099
22100	function setupLightsView( camera ) {
22101
22102		lights.setupView( lightsArray, camera );
22103
22104	}
22105
22106	const state = {
22107		lightsArray: lightsArray,
22108		shadowsArray: shadowsArray,
22109
22110		lights: lights
22111	};
22112
22113	return {
22114		init: init,
22115		state: state,
22116		setupLights: setupLights,
22117		setupLightsView: setupLightsView,
22118
22119		pushLight: pushLight,
22120		pushShadow: pushShadow
22121	};
22122
22123}
22124
22125function WebGLRenderStates( extensions, capabilities ) {
22126
22127	let renderStates = new WeakMap();
22128
22129	function get( scene, renderCallDepth = 0 ) {
22130
22131		const renderStateArray = renderStates.get( scene );
22132		let renderState;
22133
22134		if ( renderStateArray === undefined ) {
22135
22136			renderState = new WebGLRenderState( extensions, capabilities );
22137			renderStates.set( scene, [ renderState ] );
22138
22139		} else {
22140
22141			if ( renderCallDepth >= renderStateArray.length ) {
22142
22143				renderState = new WebGLRenderState( extensions, capabilities );
22144				renderStateArray.push( renderState );
22145
22146			} else {
22147
22148				renderState = renderStateArray[ renderCallDepth ];
22149
22150			}
22151
22152		}
22153
22154		return renderState;
22155
22156	}
22157
22158	function dispose() {
22159
22160		renderStates = new WeakMap();
22161
22162	}
22163
22164	return {
22165		get: get,
22166		dispose: dispose
22167	};
22168
22169}
22170
22171class MeshDepthMaterial extends Material {
22172
22173	constructor( parameters ) {
22174
22175		super();
22176
22177		this.isMeshDepthMaterial = true;
22178
22179		this.type = 'MeshDepthMaterial';
22180
22181		this.depthPacking = BasicDepthPacking;
22182
22183		this.map = null;
22184
22185		this.alphaMap = null;
22186
22187		this.displacementMap = null;
22188		this.displacementScale = 1;
22189		this.displacementBias = 0;
22190
22191		this.wireframe = false;
22192		this.wireframeLinewidth = 1;
22193
22194		this.setValues( parameters );
22195
22196	}
22197
22198	copy( source ) {
22199
22200		super.copy( source );
22201
22202		this.depthPacking = source.depthPacking;
22203
22204		this.map = source.map;
22205
22206		this.alphaMap = source.alphaMap;
22207
22208		this.displacementMap = source.displacementMap;
22209		this.displacementScale = source.displacementScale;
22210		this.displacementBias = source.displacementBias;
22211
22212		this.wireframe = source.wireframe;
22213		this.wireframeLinewidth = source.wireframeLinewidth;
22214
22215		return this;
22216
22217	}
22218
22219}
22220
22221class MeshDistanceMaterial extends Material {
22222
22223	constructor( parameters ) {
22224
22225		super();
22226
22227		this.isMeshDistanceMaterial = true;
22228
22229		this.type = 'MeshDistanceMaterial';
22230
22231		this.map = null;
22232
22233		this.alphaMap = null;
22234
22235		this.displacementMap = null;
22236		this.displacementScale = 1;
22237		this.displacementBias = 0;
22238
22239		this.setValues( parameters );
22240
22241	}
22242
22243	copy( source ) {
22244
22245		super.copy( source );
22246
22247		this.map = source.map;
22248
22249		this.alphaMap = source.alphaMap;
22250
22251		this.displacementMap = source.displacementMap;
22252		this.displacementScale = source.displacementScale;
22253		this.displacementBias = source.displacementBias;
22254
22255		return this;
22256
22257	}
22258
22259}
22260
22261const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
22262
22263const 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}";
22264
22265function WebGLShadowMap( _renderer, _objects, _capabilities ) {
22266
22267	let _frustum = new Frustum();
22268
22269	const _shadowMapSize = new Vector2(),
22270		_viewportSize = new Vector2(),
22271
22272		_viewport = new Vector4(),
22273
22274		_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
22275		_distanceMaterial = new MeshDistanceMaterial(),
22276
22277		_materialCache = {},
22278
22279		_maxTextureSize = _capabilities.maxTextureSize;
22280
22281	const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide };
22282
22283	const shadowMaterialVertical = new ShaderMaterial( {
22284		defines: {
22285			VSM_SAMPLES: 8
22286		},
22287		uniforms: {
22288			shadow_pass: { value: null },
22289			resolution: { value: new Vector2() },
22290			radius: { value: 4.0 }
22291		},
22292
22293		vertexShader: vertex,
22294		fragmentShader: fragment
22295
22296	} );
22297
22298	const shadowMaterialHorizontal = shadowMaterialVertical.clone();
22299	shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
22300
22301	const fullScreenTri = new BufferGeometry();
22302	fullScreenTri.setAttribute(
22303		'position',
22304		new BufferAttribute(
22305			new Float32Array( [ -
22305 1, - 1, 0.5, 3, - 1, 0.5, - 
vendor: 10,677 bytes, lines 22305-22728
223051, 3, 0.5 ] ),
22306			3
22307		)
22308	);
22309
22310	const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
22311
22312	const scope = this;
22313
22314	this.enabled = false;
22315
22316	this.autoUpdate = true;
22317	this.needsUpdate = false;
22318
22319	this.type = PCFShadowMap;
22320	let _previousType = this.type;
22321
22322	this.render = function ( lights, scene, camera ) {
22323
22324		if ( scope.enabled === false ) return;
22325		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
22326
22327		if ( lights.length === 0 ) return;
22328
22329		const currentRenderTarget = _renderer.getRenderTarget();
22330		const activeCubeFace = _renderer.getActiveCubeFace();
22331		const activeMipmapLevel = _renderer.getActiveMipmapLevel();
22332
22333		const _state = _renderer.state;
22334
22335		// Set GL state for depth map.
22336		_state.setBlending( NoBlending );
22337		_state.buffers.color.setClear( 1, 1, 1, 1 );
22338		_state.buffers.depth.setTest( true );
22339		_state.setScissorTest( false );
22340
22341		// check for shadow map type changes
22342
22343		const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap );
22344		const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap );
22345
22346		// render depth map
22347
22348		for ( let i = 0, il = lights.length; i < il; i ++ ) {
22349
22350			const light = lights[ i ];
22351			const shadow = light.shadow;
22352
22353			if ( shadow === undefined ) {
22354
22355				console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
22356				continue;
22357
22358			}
22359
22360			if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
22361
22362			_shadowMapSize.copy( shadow.mapSize );
22363
22364			const shadowFrameExtents = shadow.getFrameExtents();
22365
22366			_shadowMapSize.multiply( shadowFrameExtents );
22367
22368			_viewportSize.copy( shadow.mapSize );
22369
22370			if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {
22371
22372				if ( _shadowMapSize.x > _maxTextureSize ) {
22373
22374					_viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );
22375					_shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
22376					shadow.mapSize.x = _viewportSize.x;
22377
22378				}
22379
22380				if ( _shadowMapSize.y > _maxTextureSize ) {
22381
22382					_viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );
22383					_shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
22384					shadow.mapSize.y = _viewportSize.y;
22385
22386				}
22387
22388			}
22389
22390			if ( shadow.map === null || toVSM === true || fromVSM === true ) {
22391
22392				const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {};
22393
22394				if ( shadow.map !== null ) {
22395
22396					shadow.map.dispose();
22397
22398				}
22399
22400				shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
22401				shadow.map.texture.name = light.name + '.shadowMap';
22402
22403				shadow.camera.updateProjectionMatrix();
22404
22405			}
22406
22407			_renderer.setRenderTarget( shadow.map );
22408			_renderer.clear();
22409
22410			const viewportCount = shadow.getViewportCount();
22411
22412			for ( let vp = 0; vp < viewportCount; vp ++ ) {
22413
22414				const viewport = shadow.getViewport( vp );
22415
22416				_viewport.set(
22417					_viewportSize.x * viewport.x,
22418					_viewportSize.y * viewport.y,
22419					_viewportSize.x * viewport.z,
22420					_viewportSize.y * viewport.w
22421				);
22422
22423				_state.viewport( _viewport );
22424
22425				shadow.updateMatrices( light, vp );
22426
22427				_frustum = shadow.getFrustum();
22428
22429				renderObject( scene, camera, shadow.camera, light, this.type );
22430
22431			}
22432
22433			// do blur pass for VSM
22434
22435			if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {
22436
22437				VSMPass( shadow, camera );
22438
22439			}
22440
22441			shadow.needsUpdate = false;
22442
22443		}
22444
22445		_previousType = this.type;
22446
22447		scope.needsUpdate = false;
22448
22449		_renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
22450
22451	};
22452
22453	function VSMPass( shadow, camera ) {
22454
22455		const geometry = _objects.update( fullScreenMesh );
22456
22457		if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {
22458
22459			shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
22460			shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;
22461
22462			shadowMaterialVertical.needsUpdate = true;
22463			shadowMaterialHorizontal.needsUpdate = true;
22464
22465		}
22466
22467		if ( shadow.mapPass === null ) {
22468
22469			shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );
22470
22471		}
22472
22473		// vertical pass
22474
22475		shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
22476		shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
22477		shadowMaterialVertical.uniforms.radius.value = shadow.radius;
22478		_renderer.setRenderTarget( shadow.mapPass );
22479		_renderer.clear();
22480		_renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
22481
22482		// horizontal pass
22483
22484		shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
22485		shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
22486		shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
22487		_renderer.setRenderTarget( shadow.map );
22488		_renderer.clear();
22489		_renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
22490
22491	}
22492
22493	function getDepthMaterial( object, material, light, type ) {
22494
22495		let result = null;
22496
22497		const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;
22498
22499		if ( customMaterial !== undefined ) {
22500
22501			result = customMaterial;
22502
22503		} else {
22504
22505			result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;
22506
22507			if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) ||
22508				( material.displacementMap && material.displacementScale !== 0 ) ||
22509				( material.alphaMap && material.alphaTest > 0 ) ||
22510				( material.map && material.alphaTest > 0 ) ) {
22511
22512				// in this case we need a unique material instance reflecting the
22513				// appropriate state
22514
22515				const keyA = result.uuid, keyB = material.uuid;
22516
22517				let materialsForVariant = _materialCache[ keyA ];
22518
22519				if ( materialsForVariant === undefined ) {
22520
22521					materialsForVariant = {};
22522					_materialCache[ keyA ] = materialsForVariant;
22523
22524				}
22525
22526				let cachedMaterial = materialsForVariant[ keyB ];
22527
22528				if ( cachedMaterial === undefined ) {
22529
22530					cachedMaterial = result.clone();
22531					materialsForVariant[ keyB ] = cachedMaterial;
22532					material.addEventListener( 'dispose', onMaterialDispose );
22533
22534				}
22535
22536				result = cachedMaterial;
22537
22538			}
22539
22540		}
22541
22542		result.visible = material.visible;
22543		result.wireframe = material.wireframe;
22544
22545		if ( type === VSMShadowMap ) {
22546
22547			result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
22548
22549		} else {
22550
22551			result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
22552
22553		}
22554
22555		result.alphaMap = material.alphaMap;
22556		result.alphaTest = material.alphaTest;
22557		result.map = material.map;
22558
22559		result.clipShadows = material.clipShadows;
22560		result.clippingPlanes = material.clippingPlanes;
22561		result.clipIntersection = material.clipIntersection;
22562
22563		result.displacementMap = material.displacementMap;
22564		result.displacementScale = material.displacementScale;
22565		result.displacementBias = material.displacementBias;
22566
22567		result.wireframeLinewidth = material.wireframeLinewidth;
22568		result.linewidth = material.linewidth;
22569
22570		if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
22571
22572			const materialProperties = _renderer.properties.get( result );
22573			materialProperties.light = light;
22574
22575		}
22576
22577		return result;
22578
22579	}
22580
22581	function renderObject( object, camera, shadowCamera, light, type ) {
22582
22583		if ( object.visible === false ) return;
22584
22585		const visible = object.layers.test( camera.layers );
22586
22587		if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
22588
22589			if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
22590
22591				object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
22592
22593				const geometry = _objects.update( object );
22594				const material = object.material;
22595
22596				if ( Array.isArray( material ) ) {
22597
22598					const groups = geometry.groups;
22599
22600					for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
22601
22602						const group = groups[ k ];
22603						const groupMaterial = material[ group.materialIndex ];
22604
22605						if ( groupMaterial && groupMaterial.visible ) {
22606
22607							const depthMaterial = getDepthMaterial( object, groupMaterial, light, type );
22608
22609							object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22610
22611							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
22612
22613							object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22614
22615						}
22616
22617					}
22618
22619				} else if ( material.visible ) {
22620
22621					const depthMaterial = getDepthMaterial( object, material, light, type );
22622
22623					object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22624
22625					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
22626
22627					object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22628
22629				}
22630
22631			}
22632
22633		}
22634
22635		const children = object.children;
22636
22637		for ( let i = 0, l = children.length; i < l; i ++ ) {
22638
22639			renderObject( children[ i ], camera, shadowCamera, light, type );
22640
22641		}
22642
22643	}
22644
22645	function onMaterialDispose( event ) {
22646
22647		const material = event.target;
22648
22649		material.removeEventListener( 'dispose', onMaterialDispose );
22650
22651		// make sure to remove the unique distance/depth materials used for shadow map rendering
22652
22653		for ( const id in _materialCache ) {
22654
22655			const cache = _materialCache[ id ];
22656
22657			const uuid = event.target.uuid;
22658
22659			if ( uuid in cache ) {
22660
22661				const shadowMaterial = cache[ uuid ];
22662				shadowMaterial.dispose();
22663				delete cache[ uuid ];
22664
22665			}
22666
22667		}
22668
22669	}
22670
22671}
22672
22673function WebGLState( gl, extensions, capabilities ) {
22674
22675	const isWebGL2 = capabilities.isWebGL2;
22676
22677	function ColorBuffer() {
22678
22679		let locked = false;
22680
22681		const color = new Vector4();
22682		let currentColorMask = null;
22683		const currentColorClear = new Vector4( 0, 0, 0, 0 );
22684
22685		return {
22686
22687			setMask: function ( colorMask ) {
22688
22689				if ( currentColorMask !== colorMask && ! locked ) {
22690
22691					gl.colorMask( colorMask, colorMask, colorMask, colorMask );
22692					currentColorMask = colorMask;
22693
22694				}
22695
22696			},
22697
22698			setLocked: function ( lock ) {
22699
22700				locked = lock;
22701
22702			},
22703
22704			setClear: function ( r, g, b, a, premultipliedAlpha ) {
22705
22706				if ( premultipliedAlpha === true ) {
22707
22708					r *= a; g *= a; b *= a;
22709
22710				}
22711
22712				color.set( r, g, b, a );
22713
22714				if ( currentColorClear.equals( color ) === false ) {
22715
22716					gl.clearColor( r, g, b, a );
22717					currentColorClear.copy( color );
22718
22719				}
22720
22721			},
22722
22723			reset: function () {
22724
22725				locked = false;
22726
22727				currentColorMask = null;
22728				currentColorClear.set( -
22728 
vendor: 4,959 bytes, lines 22728-23015
227281, 0, 0, 0 ); // set to invalid state
22729
22730			}
22731
22732		};
22733
22734	}
22735
22736	function DepthBuffer() {
22737
22738		let locked = false;
22739
22740		let currentDepthMask = null;
22741		let currentDepthFunc = null;
22742		let currentDepthClear = null;
22743
22744		return {
22745
22746			setTest: function ( depthTest ) {
22747
22748				if ( depthTest ) {
22749
22750					enable( gl.DEPTH_TEST );
22751
22752				} else {
22753
22754					disable( gl.DEPTH_TEST );
22755
22756				}
22757
22758			},
22759
22760			setMask: function ( depthMask ) {
22761
22762				if ( currentDepthMask !== depthMask && ! locked ) {
22763
22764					gl.depthMask( depthMask );
22765					currentDepthMask = depthMask;
22766
22767				}
22768
22769			},
22770
22771			setFunc: function ( depthFunc ) {
22772
22773				if ( currentDepthFunc !== depthFunc ) {
22774
22775					switch ( depthFunc ) {
22776
22777						case NeverDepth:
22778
22779							gl.depthFunc( gl.NEVER );
22780							break;
22781
22782						case AlwaysDepth:
22783
22784							gl.depthFunc( gl.ALWAYS );
22785							break;
22786
22787						case LessDepth:
22788
22789							gl.depthFunc( gl.LESS );
22790							break;
22791
22792						case LessEqualDepth:
22793
22794							gl.depthFunc( gl.LEQUAL );
22795							break;
22796
22797						case EqualDepth:
22798
22799							gl.depthFunc( gl.EQUAL );
22800							break;
22801
22802						case GreaterEqualDepth:
22803
22804							gl.depthFunc( gl.GEQUAL );
22805							break;
22806
22807						case GreaterDepth:
22808
22809							gl.depthFunc( gl.GREATER );
22810							break;
22811
22812						case NotEqualDepth:
22813
22814							gl.depthFunc( gl.NOTEQUAL );
22815							break;
22816
22817						default:
22818
22819							gl.depthFunc( gl.LEQUAL );
22820
22821					}
22822
22823					currentDepthFunc = depthFunc;
22824
22825				}
22826
22827			},
22828
22829			setLocked: function ( lock ) {
22830
22831				locked = lock;
22832
22833			},
22834
22835			setClear: function ( depth ) {
22836
22837				if ( currentDepthClear !== depth ) {
22838
22839					gl.clearDepth( depth );
22840					currentDepthClear = depth;
22841
22842				}
22843
22844			},
22845
22846			reset: function () {
22847
22848				locked = false;
22849
22850				currentDepthMask = null;
22851				currentDepthFunc = null;
22852				currentDepthClear = null;
22853
22854			}
22855
22856		};
22857
22858	}
22859
22860	function StencilBuffer() {
22861
22862		let locked = false;
22863
22864		let currentStencilMask = null;
22865		let currentStencilFunc = null;
22866		let currentStencilRef = null;
22867		let currentStencilFuncMask = null;
22868		let currentStencilFail = null;
22869		let currentStencilZFail = null;
22870		let currentStencilZPass = null;
22871		let currentStencilClear = null;
22872
22873		return {
22874
22875			setTest: function ( stencilTest ) {
22876
22877				if ( ! locked ) {
22878
22879					if ( stencilTest ) {
22880
22881						enable( gl.STENCIL_TEST );
22882
22883					} else {
22884
22885						disable( gl.STENCIL_TEST );
22886
22887					}
22888
22889				}
22890
22891			},
22892
22893			setMask: function ( stencilMask ) {
22894
22895				if ( currentStencilMask !== stencilMask && ! locked ) {
22896
22897					gl.stencilMask( stencilMask );
22898					currentStencilMask = stencilMask;
22899
22900				}
22901
22902			},
22903
22904			setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
22905
22906				if ( currentStencilFunc !== stencilFunc ||
22907				     currentStencilRef !== stencilRef ||
22908				     currentStencilFuncMask !== stencilMask ) {
22909
22910					gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
22911
22912					currentStencilFunc = stencilFunc;
22913					currentStencilRef = stencilRef;
22914					currentStencilFuncMask = stencilMask;
22915
22916				}
22917
22918			},
22919
22920			setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
22921
22922				if ( currentStencilFail !== stencilFail ||
22923				     currentStencilZFail !== stencilZFail ||
22924				     currentStencilZPass !== stencilZPass ) {
22925
22926					gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
22927
22928					currentStencilFail = stencilFail;
22929					currentStencilZFail = stencilZFail;
22930					currentStencilZPass = stencilZPass;
22931
22932				}
22933
22934			},
22935
22936			setLocked: function ( lock ) {
22937
22938				locked = lock;
22939
22940			},
22941
22942			setClear: function ( stencil ) {
22943
22944				if ( currentStencilClear !== stencil ) {
22945
22946					gl.clearStencil( stencil );
22947					currentStencilClear = stencil;
22948
22949				}
22950
22951			},
22952
22953			reset: function () {
22954
22955				locked = false;
22956
22957				currentStencilMask = null;
22958				currentStencilFunc = null;
22959				currentStencilRef = null;
22960				currentStencilFuncMask = null;
22961				currentStencilFail = null;
22962				currentStencilZFail = null;
22963				currentStencilZPass = null;
22964				currentStencilClear = null;
22965
22966			}
22967
22968		};
22969
22970	}
22971
22972	//
22973
22974	const colorBuffer = new ColorBuffer();
22975	const depthBuffer = new DepthBuffer();
22976	const stencilBuffer = new StencilBuffer();
22977
22978	const uboBindings = new WeakMap();
22979	const uboProgramMap = new WeakMap();
22980
22981	let enabledCapabilities = {};
22982
22983	let currentBoundFramebuffers = {};
22984	let currentDrawbuffers = new WeakMap();
22985	let defaultDrawbuffers = [];
22986
22987	let currentProgram = null;
22988
22989	let currentBlendingEnabled = false;
22990	let currentBlending = null;
22991	let currentBlendEquation = null;
22992	let currentBlendSrc = null;
22993	let currentBlendDst = null;
22994	let currentBlendEquationAlpha = null;
22995	let currentBlendSrcAlpha = null;
22996	let currentBlendDstAlpha = null;
22997	let currentBlendColor = new Color( 0, 0, 0 );
22998	let currentBlendAlpha = 0;
22999	let currentPremultipledAlpha = false;
23000
23001	let currentFlipSided = null;
23002	let currentCullFace = null;
23003
23004	let currentLineWidth = null;
23005
23006	let currentPolygonOffsetFactor = null;
23007	let currentPolygonOffsetUnits = null;
23008
23009	const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
23010
23011	let lineWidthAvailable = false;
23012	let version = 0;
23013	const glVersion = gl.getParameter( gl.VERSION );
23014
23015	if ( glVersion.indexOf( 'WebGL' ) !== -
vendor: 4,090 bytes, lines 23015-23214
23015 1 ) {
23016
23017		version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
23018		lineWidthAvailable = ( version >= 1.0 );
23019
23020	} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
23021
23022		version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
23023		lineWidthAvailable = ( version >= 2.0 );
23024
23025	}
23026
23027	let currentTextureSlot = null;
23028	let currentBoundTextures = {};
23029
23030	const scissorParam = gl.getParameter( gl.SCISSOR_BOX );
23031	const viewportParam = gl.getParameter( gl.VIEWPORT );
23032
23033	const currentScissor = new Vector4().fromArray( scissorParam );
23034	const currentViewport = new Vector4().fromArray( viewportParam );
23035
23036	function createTexture( type, target, count, dimensions ) {
23037
23038		const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
23039		const texture = gl.createTexture();
23040
23041		gl.bindTexture( type, texture );
23042		gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
23043		gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
23044
23045		for ( let i = 0; i < count; i ++ ) {
23046
23047			if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) {
23048
23049				gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23050
23051			} else {
23052
23053				gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23054
23055			}
23056
23057		}
23058
23059		return texture;
23060
23061	}
23062
23063	const emptyTextures = {};
23064	emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
23065	emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
23066
23067	if ( isWebGL2 ) {
23068
23069		emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );
23070		emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );
23071
23072	}
23073
23074	// init
23075
23076	colorBuffer.setClear( 0, 0, 0, 1 );
23077	depthBuffer.setClear( 1 );
23078	stencilBuffer.setClear( 0 );
23079
23080	enable( gl.DEPTH_TEST );
23081	depthBuffer.setFunc( LessEqualDepth );
23082
23083	setFlipSided( false );
23084	setCullFace( CullFaceBack );
23085	enable( gl.CULL_FACE );
23086
23087	setBlending( NoBlending );
23088
23089	//
23090
23091	function enable( id ) {
23092
23093		if ( enabledCapabilities[ id ] !== true ) {
23094
23095			gl.enable( id );
23096			enabledCapabilities[ id ] = true;
23097
23098		}
23099
23100	}
23101
23102	function disable( id ) {
23103
23104		if ( enabledCapabilities[ id ] !== false ) {
23105
23106			gl.disable( id );
23107			enabledCapabilities[ id ] = false;
23108
23109		}
23110
23111	}
23112
23113	function bindFramebuffer( target, framebuffer ) {
23114
23115		if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
23116
23117			gl.bindFramebuffer( target, framebuffer );
23118
23119			currentBoundFramebuffers[ target ] = framebuffer;
23120
23121			if ( isWebGL2 ) {
23122
23123				// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
23124
23125				if ( target === gl.DRAW_FRAMEBUFFER ) {
23126
23127					currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;
23128
23129				}
23130
23131				if ( target === gl.FRAMEBUFFER ) {
23132
23133					currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;
23134
23135				}
23136
23137			}
23138
23139			return true;
23140
23141		}
23142
23143		return false;
23144
23145	}
23146
23147	function drawBuffers( renderTarget, framebuffer ) {
23148
23149		let drawBuffers = defaultDrawbuffers;
23150
23151		let needsUpdate = false;
23152
23153		if ( renderTarget ) {
23154
23155			drawBuffers = currentDrawbuffers.get( framebuffer );
23156
23157			if ( drawBuffers === undefined ) {
23158
23159				drawBuffers = [];
23160				currentDrawbuffers.set( framebuffer, drawBuffers );
23161
23162			}
23163
23164			if ( renderTarget.isWebGLMultipleRenderTargets ) {
23165
23166				const textures = renderTarget.texture;
23167
23168				if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23169
23170					for ( let i = 0, il = textures.length; i < il; i ++ ) {
23171
23172						drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
23173
23174					}
23175
23176					drawBuffers.length = textures.length;
23177
23178					needsUpdate = true;
23179
23180				}
23181
23182			} else {
23183
23184				if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23185
23186					drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0;
23187
23188					needsUpdate = true;
23189
23190				}
23191
23192			}
23193
23194		} else {
23195
23196			if ( drawBuffers[ 0 ] !== gl.BACK ) {
23197
23198				drawBuffers[ 0 ] = gl.BACK;
23199
23200				needsUpdate = true;
23201
23202			}
23203
23204		}
23205
23206		if ( needsUpdate ) {
23207
23208			if ( capabilities.isWebGL2 ) {
23209
23210				gl.drawBuffers( drawBuffers );
23211
23212			} else {
23213
23214				extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers
vendor: 15,740 bytes, lines 23214-24002
23214 );
23215
23216			}
23217
23218		}
23219
23220
23221	}
23222
23223	function useProgram( program ) {
23224
23225		if ( currentProgram !== program ) {
23226
23227			gl.useProgram( program );
23228
23229			currentProgram = program;
23230
23231			return true;
23232
23233		}
23234
23235		return false;
23236
23237	}
23238
23239	const equationToGL = {
23240		[ AddEquation ]: gl.FUNC_ADD,
23241		[ SubtractEquation ]: gl.FUNC_SUBTRACT,
23242		[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
23243	};
23244
23245	if ( isWebGL2 ) {
23246
23247		equationToGL[ MinEquation ] = gl.MIN;
23248		equationToGL[ MaxEquation ] = gl.MAX;
23249
23250	} else {
23251
23252		const extension = extensions.get( 'EXT_blend_minmax' );
23253
23254		if ( extension !== null ) {
23255
23256			equationToGL[ MinEquation ] = extension.MIN_EXT;
23257			equationToGL[ MaxEquation ] = extension.MAX_EXT;
23258
23259		}
23260
23261	}
23262
23263	const factorToGL = {
23264		[ ZeroFactor ]: gl.ZERO,
23265		[ OneFactor ]: gl.ONE,
23266		[ SrcColorFactor ]: gl.SRC_COLOR,
23267		[ SrcAlphaFactor ]: gl.SRC_ALPHA,
23268		[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
23269		[ DstColorFactor ]: gl.DST_COLOR,
23270		[ DstAlphaFactor ]: gl.DST_ALPHA,
23271		[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
23272		[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
23273		[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
23274		[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
23275		[ ConstantColorFactor ]: gl.CONSTANT_COLOR,
23276		[ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
23277		[ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
23278		[ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
23279	};
23280
23281	function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {
23282
23283		if ( blending === NoBlending ) {
23284
23285			if ( currentBlendingEnabled === true ) {
23286
23287				disable( gl.BLEND );
23288				currentBlendingEnabled = false;
23289
23290			}
23291
23292			return;
23293
23294		}
23295
23296		if ( currentBlendingEnabled === false ) {
23297
23298			enable( gl.BLEND );
23299			currentBlendingEnabled = true;
23300
23301		}
23302
23303		if ( blending !== CustomBlending ) {
23304
23305			if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
23306
23307				if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
23308
23309					gl.blendEquation( gl.FUNC_ADD );
23310
23311					currentBlendEquation = AddEquation;
23312					currentBlendEquationAlpha = AddEquation;
23313
23314				}
23315
23316				if ( premultipliedAlpha ) {
23317
23318					switch ( blending ) {
23319
23320						case NormalBlending:
23321							gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23322							break;
23323
23324						case AdditiveBlending:
23325							gl.blendFunc( gl.ONE, gl.ONE );
23326							break;
23327
23328						case SubtractiveBlending:
23329							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23330							break;
23331
23332						case MultiplyBlending:
23333							gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
23334							break;
23335
23336						default:
23337							console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23338							break;
23339
23340					}
23341
23342				} else {
23343
23344					switch ( blending ) {
23345
23346						case NormalBlending:
23347							gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23348							break;
23349
23350						case AdditiveBlending:
23351							gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
23352							break;
23353
23354						case SubtractiveBlending:
23355							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23356							break;
23357
23358						case MultiplyBlending:
23359							gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
23360							break;
23361
23362						default:
23363							console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23364							break;
23365
23366					}
23367
23368				}
23369
23370				currentBlendSrc = null;
23371				currentBlendDst = null;
23372				currentBlendSrcAlpha = null;
23373				currentBlendDstAlpha = null;
23374				currentBlendColor.set( 0, 0, 0 );
23375				currentBlendAlpha = 0;
23376
23377				currentBlending = blending;
23378				currentPremultipledAlpha = premultipliedAlpha;
23379
23380			}
23381
23382			return;
23383
23384		}
23385
23386		// custom blending
23387
23388		blendEquationAlpha = blendEquationAlpha || blendEquation;
23389		blendSrcAlpha = blendSrcAlpha || blendSrc;
23390		blendDstAlpha = blendDstAlpha || blendDst;
23391
23392		if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
23393
23394			gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
23395
23396			currentBlendEquation = blendEquation;
23397			currentBlendEquationAlpha = blendEquationAlpha;
23398
23399		}
23400
23401		if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
23402
23403			gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
23404
23405			currentBlendSrc = blendSrc;
23406			currentBlendDst = blendDst;
23407			currentBlendSrcAlpha = blendSrcAlpha;
23408			currentBlendDstAlpha = blendDstAlpha;
23409
23410		}
23411
23412		if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {
23413
23414			gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );
23415
23416			currentBlendColor.copy( blendColor );
23417			currentBlendAlpha = blendAlpha;
23418
23419		}
23420
23421		currentBlending = blending;
23422		currentPremultipledAlpha = false;
23423
23424	}
23425
23426	function setMaterial( material, frontFaceCW ) {
23427
23428		material.side === DoubleSide
23429			? disable( gl.CULL_FACE )
23430			: enable( gl.CULL_FACE );
23431
23432		let flipSided = ( material.side === BackSide );
23433		if ( frontFaceCW ) flipSided = ! flipSided;
23434
23435		setFlipSided( flipSided );
23436
23437		( material.blending === NormalBlending && material.transparent === false )
23438			? setBlending( NoBlending )
23439			: setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
23440
23441		depthBuffer.setFunc( material.depthFunc );
23442		depthBuffer.setTest( material.depthTest );
23443		depthBuffer.setMask( material.depthWrite );
23444		colorBuffer.setMask( material.colorWrite );
23445
23446		const stencilWrite = material.stencilWrite;
23447		stencilBuffer.setTest( stencilWrite );
23448		if ( stencilWrite ) {
23449
23450			stencilBuffer.setMask( material.stencilWriteMask );
23451			stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
23452			stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
23453
23454		}
23455
23456		setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
23457
23458		material.alphaToCoverage === true
23459			? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
23460			: disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
23461
23462	}
23463
23464	//
23465
23466	function setFlipSided( flipSided ) {
23467
23468		if ( currentFlipSided !== flipSided ) {
23469
23470			if ( flipSided ) {
23471
23472				gl.frontFace( gl.CW );
23473
23474			} else {
23475
23476				gl.frontFace( gl.CCW );
23477
23478			}
23479
23480			currentFlipSided = flipSided;
23481
23482		}
23483
23484	}
23485
23486	function setCullFace( cullFace ) {
23487
23488		if ( cullFace !== CullFaceNone ) {
23489
23490			enable( gl.CULL_FACE );
23491
23492			if ( cullFace !== currentCullFace ) {
23493
23494				if ( cullFace === CullFaceBack ) {
23495
23496					gl.cullFace( gl.BACK );
23497
23498				} else if ( cullFace === CullFaceFront ) {
23499
23500					gl.cullFace( gl.FRONT );
23501
23502				} else {
23503
23504					gl.cullFace( gl.FRONT_AND_BACK );
23505
23506				}
23507
23508			}
23509
23510		} else {
23511
23512			disable( gl.CULL_FACE );
23513
23514		}
23515
23516		currentCullFace = cullFace;
23517
23518	}
23519
23520	function setLineWidth( width ) {
23521
23522		if ( width !== currentLineWidth ) {
23523
23524			if ( lineWidthAvailable ) gl.lineWidth( width );
23525
23526			currentLineWidth = width;
23527
23528		}
23529
23530	}
23531
23532	function setPolygonOffset( polygonOffset, factor, units ) {
23533
23534		if ( polygonOffset ) {
23535
23536			enable( gl.POLYGON_OFFSET_FILL );
23537
23538			if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
23539
23540				gl.polygonOffset( factor, units );
23541
23542				currentPolygonOffsetFactor = factor;
23543				currentPolygonOffsetUnits = units;
23544
23545			}
23546
23547		} else {
23548
23549			disable( gl.POLYGON_OFFSET_FILL );
23550
23551		}
23552
23553	}
23554
23555	function setScissorTest( scissorTest ) {
23556
23557		if ( scissorTest ) {
23558
23559			enable( gl.SCISSOR_TEST );
23560
23561		} else {
23562
23563			disable( gl.SCISSOR_TEST );
23564
23565		}
23566
23567	}
23568
23569	// texture
23570
23571	function activeTexture( webglSlot ) {
23572
23573		if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
23574
23575		if ( currentTextureSlot !== webglSlot ) {
23576
23577			gl.activeTexture( webglSlot );
23578			currentTextureSlot = webglSlot;
23579
23580		}
23581
23582	}
23583
23584	function bindTexture( webglType, webglTexture, webglSlot ) {
23585
23586		if ( webglSlot === undefined ) {
23587
23588			if ( currentTextureSlot === null ) {
23589
23590				webglSlot = gl.TEXTURE0 + maxTextures - 1;
23591
23592			} else {
23593
23594				webglSlot = currentTextureSlot;
23595
23596			}
23597
23598		}
23599
23600		let boundTexture = currentBoundTextures[ webglSlot ];
23601
23602		if ( boundTexture === undefined ) {
23603
23604			boundTexture = { type: undefined, texture: undefined };
23605			currentBoundTextures[ webglSlot ] = boundTexture;
23606
23607		}
23608
23609		if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
23610
23611			if ( currentTextureSlot !== webglSlot ) {
23612
23613				gl.activeTexture( webglSlot );
23614				currentTextureSlot = webglSlot;
23615
23616			}
23617
23618			gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
23619
23620			boundTexture.type = webglType;
23621			boundTexture.texture = webglTexture;
23622
23623		}
23624
23625	}
23626
23627	function unbindTexture() {
23628
23629		const boundTexture = currentBoundTextures[ currentTextureSlot ];
23630
23631		if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
23632
23633			gl.bindTexture( boundTexture.type, null );
23634
23635			boundTexture.type = undefined;
23636			boundTexture.texture = undefined;
23637
23638		}
23639
23640	}
23641
23642	function compressedTexImage2D() {
23643
23644		try {
23645
23646			gl.compressedTexImage2D.apply( gl, arguments );
23647
23648		} catch ( error ) {
23649
23650			console.error( 'THREE.WebGLState:', error );
23651
23652		}
23653
23654	}
23655
23656	function compressedTexImage3D() {
23657
23658		try {
23659
23660			gl.compressedTexImage3D.apply( gl, arguments );
23661
23662		} catch ( error ) {
23663
23664			console.error( 'THREE.WebGLState:', error );
23665
23666		}
23667
23668	}
23669
23670	function texSubImage2D() {
23671
23672		try {
23673
23674			gl.texSubImage2D.apply( gl, arguments );
23675
23676		} catch ( error ) {
23677
23678			console.error( 'THREE.WebGLState:', error );
23679
23680		}
23681
23682	}
23683
23684	function texSubImage3D() {
23685
23686		try {
23687
23688			gl.texSubImage3D.apply( gl, arguments );
23689
23690		} catch ( error ) {
23691
23692			console.error( 'THREE.WebGLState:', error );
23693
23694		}
23695
23696	}
23697
23698	function compressedTexSubImage2D() {
23699
23700		try {
23701
23702			gl.compressedTexSubImage2D.apply( gl, arguments );
23703
23704		} catch ( error ) {
23705
23706			console.error( 'THREE.WebGLState:', error );
23707
23708		}
23709
23710	}
23711
23712	function compressedTexSubImage3D() {
23713
23714		try {
23715
23716			gl.compressedTexSubImage3D.apply( gl, arguments );
23717
23718		} catch ( error ) {
23719
23720			console.error( 'THREE.WebGLState:', error );
23721
23722		}
23723
23724	}
23725
23726	function texStorage2D() {
23727
23728		try {
23729
23730			gl.texStorage2D.apply( gl, arguments );
23731
23732		} catch ( error ) {
23733
23734			console.error( 'THREE.WebGLState:', error );
23735
23736		}
23737
23738	}
23739
23740	function texStorage3D() {
23741
23742		try {
23743
23744			gl.texStorage3D.apply( gl, arguments );
23745
23746		} catch ( error ) {
23747
23748			console.error( 'THREE.WebGLState:', error );
23749
23750		}
23751
23752	}
23753
23754	function texImage2D() {
23755
23756		try {
23757
23758			gl.texImage2D.apply( gl, arguments );
23759
23760		} catch ( error ) {
23761
23762			console.error( 'THREE.WebGLState:', error );
23763
23764		}
23765
23766	}
23767
23768	function texImage3D() {
23769
23770		try {
23771
23772			gl.texImage3D.apply( gl, arguments );
23773
23774		} catch ( error ) {
23775
23776			console.error( 'THREE.WebGLState:', error );
23777
23778		}
23779
23780	}
23781
23782	//
23783
23784	function scissor( scissor ) {
23785
23786		if ( currentScissor.equals( scissor ) === false ) {
23787
23788			gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
23789			currentScissor.copy( scissor );
23790
23791		}
23792
23793	}
23794
23795	function viewport( viewport ) {
23796
23797		if ( currentViewport.equals( viewport ) === false ) {
23798
23799			gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
23800			currentViewport.copy( viewport );
23801
23802		}
23803
23804	}
23805
23806	function updateUBOMapping( uniformsGroup, program ) {
23807
23808		let mapping = uboProgramMap.get( program );
23809
23810		if ( mapping === undefined ) {
23811
23812			mapping = new WeakMap();
23813
23814			uboProgramMap.set( program, mapping );
23815
23816		}
23817
23818		let blockIndex = mapping.get( uniformsGroup );
23819
23820		if ( blockIndex === undefined ) {
23821
23822			blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );
23823
23824			mapping.set( uniformsGroup, blockIndex );
23825
23826		}
23827
23828	}
23829
23830	function uniformBlockBinding( uniformsGroup, program ) {
23831
23832		const mapping = uboProgramMap.get( program );
23833		const blockIndex = mapping.get( uniformsGroup );
23834
23835		if ( uboBindings.get( program ) !== blockIndex ) {
23836
23837			// bind shader specific block index to global block point
23838			gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );
23839
23840			uboBindings.set( program, blockIndex );
23841
23842		}
23843
23844	}
23845
23846	//
23847
23848	function reset() {
23849
23850		// reset state
23851
23852		gl.disable( gl.BLEND );
23853		gl.disable( gl.CULL_FACE );
23854		gl.disable( gl.DEPTH_TEST );
23855		gl.disable( gl.POLYGON_OFFSET_FILL );
23856		gl.disable( gl.SCISSOR_TEST );
23857		gl.disable( gl.STENCIL_TEST );
23858		gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
23859
23860		gl.blendEquation( gl.FUNC_ADD );
23861		gl.blendFunc( gl.ONE, gl.ZERO );
23862		gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
23863		gl.blendColor( 0, 0, 0, 0 );
23864
23865		gl.colorMask( true, true, true, true );
23866		gl.clearColor( 0, 0, 0, 0 );
23867
23868		gl.depthMask( true );
23869		gl.depthFunc( gl.LESS );
23870		gl.clearDepth( 1 );
23871
23872		gl.stencilMask( 0xffffffff );
23873		gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
23874		gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
23875		gl.clearStencil( 0 );
23876
23877		gl.cullFace( gl.BACK );
23878		gl.frontFace( gl.CCW );
23879
23880		gl.polygonOffset( 0, 0 );
23881
23882		gl.activeTexture( gl.TEXTURE0 );
23883
23884		gl.bindFramebuffer( gl.FRAMEBUFFER, null );
23885
23886		if ( isWebGL2 === true ) {
23887
23888			gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
23889			gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
23890
23891		}
23892
23893		gl.useProgram( null );
23894
23895		gl.lineWidth( 1 );
23896
23897		gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
23898		gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
23899
23900		// reset internals
23901
23902		enabledCapabilities = {};
23903
23904		currentTextureSlot = null;
23905		currentBoundTextures = {};
23906
23907		currentBoundFramebuffers = {};
23908		currentDrawbuffers = new WeakMap();
23909		defaultDrawbuffers = [];
23910
23911		currentProgram = null;
23912
23913		currentBlendingEnabled = false;
23914		currentBlending = null;
23915		currentBlendEquation = null;
23916		currentBlendSrc = null;
23917		currentBlendDst = null;
23918		currentBlendEquationAlpha = null;
23919		currentBlendSrcAlpha = null;
23920		currentBlendDstAlpha = null;
23921		currentBlendColor = new Color( 0, 0, 0 );
23922		currentBlendAlpha = 0;
23923		currentPremultipledAlpha = false;
23924
23925		currentFlipSided = null;
23926		currentCullFace = null;
23927
23928		currentLineWidth = null;
23929
23930		currentPolygonOffsetFactor = null;
23931		currentPolygonOffsetUnits = null;
23932
23933		currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
23934		currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );
23935
23936		colorBuffer.reset();
23937		depthBuffer.reset();
23938		stencilBuffer.reset();
23939
23940	}
23941
23942	return {
23943
23944		buffers: {
23945			color: colorBuffer,
23946			depth: depthBuffer,
23947			stencil: stencilBuffer
23948		},
23949
23950		enable: enable,
23951		disable: disable,
23952
23953		bindFramebuffer: bindFramebuffer,
23954		drawBuffers: drawBuffers,
23955
23956		useProgram: useProgram,
23957
23958		setBlending: setBlending,
23959		setMaterial: setMaterial,
23960
23961		setFlipSided: setFlipSided,
23962		setCullFace: setCullFace,
23963
23964		setLineWidth: setLineWidth,
23965		setPolygonOffset: setPolygonOffset,
23966
23967		setScissorTest: setScissorTest,
23968
23969		activeTexture: activeTexture,
23970		bindTexture: bindTexture,
23971		unbindTexture: unbindTexture,
23972		compressedTexImage2D: compressedTexImage2D,
23973		compressedTexImage3D: compressedTexImage3D,
23974		texImage2D: texImage2D,
23975		texImage3D: texImage3D,
23976
23977		updateUBOMapping: updateUBOMapping,
23978		uniformBlockBinding: uniformBlockBinding,
23979
23980		texStorage2D: texStorage2D,
23981		texStorage3D: texStorage3D,
23982		texSubImage2D: texSubImage2D,
23983		texSubImage3D: texSubImage3D,
23984		compressedTexSubImage2D: compressedTexSubImage2D,
23985		compressedTexSubImage3D: compressedTexSubImage3D,
23986
23987		scissor: scissor,
23988		viewport: viewport,
23989
23990		reset: reset
23991
23992	};
23993
23994}
23995
23996function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
23997
23998	const isWebGL2 = capabilities.isWebGL2;
23999	const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;
24000	const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent );
24001
24002	const _
vendor: 58,712 bytes, lines 24002-26075
24002videoTextures = new WeakMap();
24003	let _canvas;
24004
24005	const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source
24006
24007	// cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
24008	// also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
24009	// Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
24010
24011	let useOffscreenCanvas = false;
24012
24013	try {
24014
24015		useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
24016			// eslint-disable-next-line compat/compat
24017			&& ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
24018
24019	} catch ( err ) {
24020
24021		// Ignore any errors
24022
24023	}
24024
24025	function createCanvas( width, height ) {
24026
24027		// Use OffscreenCanvas when available. Specially needed in web workers
24028
24029		return useOffscreenCanvas ?
24030			// eslint-disable-next-line compat/compat
24031			new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );
24032
24033	}
24034
24035	function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
24036
24037		let scale = 1;
24038
24039		// handle case if texture exceeds max size
24040
24041		if ( image.width > maxSize || image.height > maxSize ) {
24042
24043			scale = maxSize / Math.max( image.width, image.height );
24044
24045		}
24046
24047		// only perform resize if necessary
24048
24049		if ( scale < 1 || needsPowerOfTwo === true ) {
24050
24051			// only perform resize for certain image types
24052
24053			if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
24054				( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
24055				( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
24056
24057				const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor;
24058
24059				const width = floor( scale * image.width );
24060				const height = floor( scale * image.height );
24061
24062				if ( _canvas === undefined ) _canvas = createCanvas( width, height );
24063
24064				// cube textures can't reuse the same canvas
24065
24066				const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
24067
24068				canvas.width = width;
24069				canvas.height = height;
24070
24071				const context = canvas.getContext( '2d' );
24072				context.drawImage( image, 0, 0, width, height );
24073
24074				console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
24075
24076				return canvas;
24077
24078			} else {
24079
24080				if ( 'data' in image ) {
24081
24082					console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
24083
24084				}
24085
24086				return image;
24087
24088			}
24089
24090		}
24091
24092		return image;
24093
24094	}
24095
24096	function isPowerOfTwo$1( image ) {
24097
24098		return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height );
24099
24100	}
24101
24102	function textureNeedsPowerOfTwo( texture ) {
24103
24104		if ( isWebGL2 ) return false;
24105
24106		return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
24107			( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
24108
24109	}
24110
24111	function textureNeedsGenerateMipmaps( texture, supportsMips ) {
24112
24113		return texture.generateMipmaps && supportsMips &&
24114			texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
24115
24116	}
24117
24118	function generateMipmap( target ) {
24119
24120		_gl.generateMipmap( target );
24121
24122	}
24123
24124	function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {
24125
24126		if ( isWebGL2 === false ) return glFormat;
24127
24128		if ( internalFormatName !== null ) {
24129
24130			if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
24131
24132			console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
24133
24134		}
24135
24136		let internalFormat = glFormat;
24137
24138		if ( glFormat === _gl.RED ) {
24139
24140			if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
24141			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
24142			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
24143
24144		}
24145
24146		if ( glFormat === _gl.RED_INTEGER ) {
24147
24148			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI;
24149			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI;
24150			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI;
24151			if ( glType === _gl.BYTE ) internalFormat = _gl.R8I;
24152			if ( glType === _gl.SHORT ) internalFormat = _gl.R16I;
24153			if ( glType === _gl.INT ) internalFormat = _gl.R32I;
24154
24155		}
24156
24157		if ( glFormat === _gl.RG ) {
24158
24159			if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;
24160			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;
24161			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;
24162
24163		}
24164
24165		if ( glFormat === _gl.RGBA ) {
24166
24167			const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace );
24168
24169			if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
24170			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
24171			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
24172			if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;
24173			if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;
24174
24175		}
24176
24177		if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||
24178			internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
24179			internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {
24180
24181			extensions.get( 'EXT_color_buffer_float' );
24182
24183		}
24184
24185		return internalFormat;
24186
24187	}
24188
24189	function getMipLevels( texture, image, supportsMips ) {
24190
24191		if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {
24192
24193			return Math.log2( Math.max( image.width, image.height ) ) + 1;
24194
24195		} else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {
24196
24197			// user-defined mipmaps
24198
24199			return texture.mipmaps.length;
24200
24201		} else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {
24202
24203			return image.mipmaps.length;
24204
24205		} else {
24206
24207			// texture without mipmaps (only base level)
24208
24209			return 1;
24210
24211		}
24212
24213	}
24214
24215	// Fallback filters for non-power-of-2 textures
24216
24217	function filterFallback( f ) {
24218
24219		if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
24220
24221			return _gl.NEAREST;
24222
24223		}
24224
24225		return _gl.LINEAR;
24226
24227	}
24228
24229	//
24230
24231	function onTextureDispose( event ) {
24232
24233		const texture = event.target;
24234
24235		texture.removeEventListener( 'dispose', onTextureDispose );
24236
24237		deallocateTexture( texture );
24238
24239		if ( texture.isVideoTexture ) {
24240
24241			_videoTextures.delete( texture );
24242
24243		}
24244
24245	}
24246
24247	function onRenderTargetDispose( event ) {
24248
24249		const renderTarget = event.target;
24250
24251		renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
24252
24253		deallocateRenderTarget( renderTarget );
24254
24255	}
24256
24257	//
24258
24259	function deallocateTexture( texture ) {
24260
24261		const textureProperties = properties.get( texture );
24262
24263		if ( textureProperties.__webglInit === undefined ) return;
24264
24265		// check if it's necessary to remove the WebGLTexture object
24266
24267		const source = texture.source;
24268		const webglTextures = _sources.get( source );
24269
24270		if ( webglTextures ) {
24271
24272			const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24273			webglTexture.usedTimes --;
24274
24275			// the WebGLTexture object is not used anymore, remove it
24276
24277			if ( webglTexture.usedTimes === 0 ) {
24278
24279				deleteTexture( texture );
24280
24281			}
24282
24283			// remove the weak map entry if no WebGLTexture uses the source anymore
24284
24285			if ( Object.keys( webglTextures ).length === 0 ) {
24286
24287				_sources.delete( source );
24288
24289			}
24290
24291		}
24292
24293		properties.remove( texture );
24294
24295	}
24296
24297	function deleteTexture( texture ) {
24298
24299		const textureProperties = properties.get( texture );
24300		_gl.deleteTexture( textureProperties.__webglTexture );
24301
24302		const source = texture.source;
24303		const webglTextures = _sources.get( source );
24304		delete webglTextures[ textureProperties.__cacheKey ];
24305
24306		info.memory.textures --;
24307
24308	}
24309
24310	function deallocateRenderTarget( renderTarget ) {
24311
24312		const texture = renderTarget.texture;
24313
24314		const renderTargetProperties = properties.get( renderTarget );
24315		const textureProperties = properties.get( texture );
24316
24317		if ( textureProperties.__webglTexture !== undefined ) {
24318
24319			_gl.deleteTexture( textureProperties.__webglTexture );
24320
24321			info.memory.textures --;
24322
24323		}
24324
24325		if ( renderTarget.depthTexture ) {
24326
24327			renderTarget.depthTexture.dispose();
24328
24329		}
24330
24331		if ( renderTarget.isWebGLCubeRenderTarget ) {
24332
24333			for ( let i = 0; i < 6; i ++ ) {
24334
24335				if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {
24336
24337					for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] );
24338
24339				} else {
24340
24341					_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
24342
24343				}
24344
24345				if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
24346
24347			}
24348
24349		} else {
24350
24351			if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) {
24352
24353				for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] );
24354
24355			} else {
24356
24357				_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
24358
24359			}
24360
24361			if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
24362			if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
24363
24364			if ( renderTargetProperties.__webglColorRenderbuffer ) {
24365
24366				for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {
24367
24368					if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );
24369
24370				}
24371
24372			}
24373
24374			if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
24375
24376		}
24377
24378		if ( renderTarget.isWebGLMultipleRenderTargets ) {
24379
24380			for ( let i = 0, il = texture.length; i < il; i ++ ) {
24381
24382				const attachmentProperties = properties.get( texture[ i ] );
24383
24384				if ( attachmentProperties.__webglTexture ) {
24385
24386					_gl.deleteTexture( attachmentProperties.__webglTexture );
24387
24388					info.memory.textures --;
24389
24390				}
24391
24392				properties.remove( texture[ i ] );
24393
24394			}
24395
24396		}
24397
24398		properties.remove( texture );
24399		properties.remove( renderTarget );
24400
24401	}
24402
24403	//
24404
24405	let textureUnits = 0;
24406
24407	function resetTextureUnits() {
24408
24409		textureUnits = 0;
24410
24411	}
24412
24413	function allocateTextureUnit() {
24414
24415		const textureUnit = textureUnits;
24416
24417		if ( textureUnit >= capabilities.maxTextures ) {
24418
24419			console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
24420
24421		}
24422
24423		textureUnits += 1;
24424
24425		return textureUnit;
24426
24427	}
24428
24429	function getTextureCacheKey( texture ) {
24430
24431		const array = [];
24432
24433		array.push( texture.wrapS );
24434		array.push( texture.wrapT );
24435		array.push( texture.wrapR || 0 );
24436		array.push( texture.magFilter );
24437		array.push( texture.minFilter );
24438		array.push( texture.anisotropy );
24439		array.push( texture.internalFormat );
24440		array.push( texture.format );
24441		array.push( texture.type );
24442		array.push( texture.generateMipmaps );
24443		array.push( texture.premultiplyAlpha );
24444		array.push( texture.flipY );
24445		array.push( texture.unpackAlignment );
24446		array.push( texture.colorSpace );
24447
24448		return array.join();
24449
24450	}
24451
24452	//
24453
24454	function setTexture2D( texture, slot ) {
24455
24456		const textureProperties = properties.get( texture );
24457
24458		if ( texture.isVideoTexture ) updateVideoTexture( texture );
24459
24460		if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {
24461
24462			const image = texture.image;
24463
24464			if ( image === null ) {
24465
24466				console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );
24467
24468			} else if ( image.complete === false ) {
24469
24470				console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
24471
24472			} else {
24473
24474				uploadTexture( textureProperties, texture, slot );
24475				return;
24476
24477			}
24478
24479		}
24480
24481		state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24482
24483	}
24484
24485	function setTexture2DArray( texture, slot ) {
24486
24487		const textureProperties = properties.get( texture );
24488
24489		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24490
24491			uploadTexture( textureProperties, texture, slot );
24492			return;
24493
24494		}
24495
24496		state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24497
24498	}
24499
24500	function setTexture3D( texture, slot ) {
24501
24502		const textureProperties = properties.get( texture );
24503
24504		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24505
24506			uploadTexture( textureProperties, texture, slot );
24507			return;
24508
24509		}
24510
24511		state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24512
24513	}
24514
24515	function setTextureCube( texture, slot ) {
24516
24517		const textureProperties = properties.get( texture );
24518
24519		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24520
24521			uploadCubeTexture( textureProperties, texture, slot );
24522			return;
24523
24524		}
24525
24526		state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24527
24528	}
24529
24530	const wrappingToGL = {
24531		[ RepeatWrapping ]: _gl.REPEAT,
24532		[ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
24533		[ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
24534	};
24535
24536	const filterToGL = {
24537		[ NearestFilter ]: _gl.NEAREST,
24538		[ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
24539		[ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,
24540
24541		[ LinearFilter ]: _gl.LINEAR,
24542		[ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
24543		[ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
24544	};
24545
24546	const compareToGL = {
24547		[ NeverCompare ]: _gl.NEVER,
24548		[ AlwaysCompare ]: _gl.ALWAYS,
24549		[ LessCompare ]: _gl.LESS,
24550		[ LessEqualCompare ]: _gl.LEQUAL,
24551		[ EqualCompare ]: _gl.EQUAL,
24552		[ GreaterEqualCompare ]: _gl.GEQUAL,
24553		[ GreaterCompare ]: _gl.GREATER,
24554		[ NotEqualCompare ]: _gl.NOTEQUAL
24555	};
24556
24557	function setTextureParameters( textureType, texture, supportsMips ) {
24558
24559		if ( supportsMips ) {
24560
24561			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
24562			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );
24563
24564			if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24565
24566				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );
24567
24568			}
24569
24570			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
24571			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );
24572
24573		} else {
24574
24575			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
24576			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
24577
24578			if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24579
24580				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE );
24581
24582			}
24583
24584			if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
24585
24586				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
24587
24588			}
24589
24590			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
24591			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
24592
24593			if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
24594
24595				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
24596
24597			}
24598
24599		}
24600
24601		if ( texture.compareFunction ) {
24602
24603			_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE );
24604			_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );
24605
24606		}
24607
24608		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
24609
24610			const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
24611
24612			if ( texture.magFilter === NearestFilter ) return;
24613			if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;
24614			if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
24615			if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only
24616
24617			if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
24618
24619				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
24620				properties.get( texture ).__currentAnisotropy = texture.anisotropy;
24621
24622			}
24623
24624		}
24625
24626	}
24627
24628	function initTexture( textureProperties, texture ) {
24629
24630		let forceUpload = false;
24631
24632		if ( textureProperties.__webglInit === undefined ) {
24633
24634			textureProperties.__webglInit = true;
24635
24636			texture.addEventListener( 'dispose', onTextureDispose );
24637
24638		}
24639
24640		// create Source <-> WebGLTextures mapping if necessary
24641
24642		const source = texture.source;
24643		let webglTextures = _sources.get( source );
24644
24645		if ( webglTextures === undefined ) {
24646
24647			webglTextures = {};
24648			_sources.set( source, webglTextures );
24649
24650		}
24651
24652		// check if there is already a WebGLTexture object for the given texture parameters
24653
24654		const textureCacheKey = getTextureCacheKey( texture );
24655
24656		if ( textureCacheKey !== textureProperties.__cacheKey ) {
24657
24658			// if not, create a new instance of WebGLTexture
24659
24660			if ( webglTextures[ textureCacheKey ] === undefined ) {
24661
24662				// create new entry
24663
24664				webglTextures[ textureCacheKey ] = {
24665					texture: _gl.createTexture(),
24666					usedTimes: 0
24667				};
24668
24669				info.memory.textures ++;
24670
24671				// when a new instance of WebGLTexture was created, a texture upload is required
24672				// even if the image contents are identical
24673
24674				forceUpload = true;
24675
24676			}
24677
24678			webglTextures[ textureCacheKey ].usedTimes ++;
24679
24680			// every time the texture cache key changes, it's necessary to check if an instance of
24681			// WebGLTexture can be deleted in order to avoid a memory leak.
24682
24683			const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24684
24685			if ( webglTexture !== undefined ) {
24686
24687				webglTextures[ textureProperties.__cacheKey ].usedTimes --;
24688
24689				if ( webglTexture.usedTimes === 0 ) {
24690
24691					deleteTexture( texture );
24692
24693				}
24694
24695			}
24696
24697			// store references to cache key and WebGLTexture object
24698
24699			textureProperties.__cacheKey = textureCacheKey;
24700			textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;
24701
24702		}
24703
24704		return forceUpload;
24705
24706	}
24707
24708	function uploadTexture( textureProperties, texture, slot ) {
24709
24710		let textureType = _gl.TEXTURE_2D;
24711
24712		if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY;
24713		if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;
24714
24715		const forceUpload = initTexture( textureProperties, texture );
24716		const source = texture.source;
24717
24718		state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24719
24720		const sourceProperties = properties.get( source );
24721
24722		if ( source.version !== sourceProperties.__version || forceUpload === true ) {
24723
24724			state.activeTexture( _gl.TEXTURE0 + slot );
24725
24726			const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
24727			const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
24728			const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
24729
24730			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
24731			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
24732			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
24733			_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
24734
24735			const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false;
24736			let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize );
24737			image = verifyColorSpace( texture, image );
24738
24739			const supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
24740				glFormat = utils.convert( texture.format, texture.colorSpace );
24741
24742			let glType = utils.convert( texture.type ),
24743				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
24744
24745			setTextureParameters( textureType, texture, supportsMips );
24746
24747			let mipmap;
24748			const mipmaps = texture.mipmaps;
24749
24750			const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format );
24751			const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
24752			const levels = getMipLevels( texture, image, supportsMips );
24753
24754			if ( texture.isDepthTexture ) {
24755
24756				// populate depth texture with dummy data
24757
24758				glInternalFormat = _gl.DEPTH_COMPONENT;
24759
24760				if ( isWebGL2 ) {
24761
24762					if ( texture.type === FloatType ) {
24763
24764						glInternalFormat = _gl.DEPTH_COMPONENT32F;
24765
24766					} else if ( texture.type === UnsignedIntType ) {
24767
24768						glInternalFormat = _gl.DEPTH_COMPONENT24;
24769
24770					} else if ( texture.type === UnsignedInt248Type ) {
24771
24772						glInternalFormat = _gl.DEPTH24_STENCIL8;
24773
24774					} else {
24775
24776						glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D
24777
24778					}
24779
24780				} else {
24781
24782					if ( texture.type === FloatType ) {
24783
24784						console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
24785
24786					}
24787
24788				}
24789
24790				// validation checks for WebGL 1
24791
24792				if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24793
24794					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24795					// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
24796					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24797					if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
24798
24799						console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
24800
24801						texture.type = UnsignedIntType;
24802						glType = utils.convert( texture.type );
24803
24804					}
24805
24806				}
24807
24808				if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24809
24810					// Depth stencil textures need the DEPTH_STENCIL internal format
24811					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24812					glInternalFormat = _gl.DEPTH_STENCIL;
24813
24814					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24815					// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
24816					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24817					if ( texture.type !== UnsignedInt248Type ) {
24818
24819						console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
24820
24821						texture.type = UnsignedInt248Type;
24822						glType = utils.convert( texture.type );
24823
24824					}
24825
24826				}
24827
24828				//
24829
24830				if ( allocateMemory ) {
24831
24832					if ( useTexStorage ) {
24833
24834						state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );
24835
24836					} else {
24837
24838						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
24839
24840					}
24841
24842				}
24843
24844			} else if ( texture.isDataTexture ) {
24845
24846				// use manually created mipmaps if available
24847				// if there are no manual mipmaps
24848				// set 0 level mipmap and then use GL to generate other mipmap levels
24849
24850				if ( mipmaps.length > 0 && supportsMips ) {
24851
24852					if ( useTexStorage && allocateMemory ) {
24853
24854						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24855
24856					}
24857
24858					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24859
24860						mipmap = mipmaps[ i ];
24861
24862						if ( useTexStorage ) {
24863
24864							state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24865
24866						} else {
24867
24868							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24869
24870						}
24871
24872					}
24873
24874					texture.generateMipmaps = false;
24875
24876				} else {
24877
24878					if ( useTexStorage ) {
24879
24880						if ( allocateMemory ) {
24881
24882							state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
24883
24884						}
24885
24886						state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
24887
24888					} else {
24889
24890						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
24891
24892					}
24893
24894				}
24895
24896			} else if ( texture.isCompressedTexture ) {
24897
24898				if ( texture.isCompressedArrayTexture ) {
24899
24900					if ( useTexStorage && allocateMemory ) {
24901
24902						state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );
24903
24904					}
24905
24906					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24907
24908						mipmap = mipmaps[ i ];
24909
24910						if ( texture.format !== RGBAFormat ) {
24911
24912							if ( glFormat !== null ) {
24913
24914								if ( useTexStorage ) {
24915
24916									state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
24917
24918								} else {
24919
24920									state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );
24921
24922								}
24923
24924							} else {
24925
24926								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24927
24928							}
24929
24930						} else {
24931
24932							if ( useTexStorage ) {
24933
24934								state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );
24935
24936							} else {
24937
24938								state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );
24939
24940							}
24941
24942						}
24943
24944					}
24945
24946				} else {
24947
24948					if ( useTexStorage && allocateMemory ) {
24949
24950						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24951
24952					}
24953
24954					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24955
24956						mipmap = mipmaps[ i ];
24957
24958						if ( texture.format !== RGBAFormat ) {
24959
24960							if ( glFormat !== null ) {
24961
24962								if ( useTexStorage ) {
24963
24964									state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
24965
24966								} else {
24967
24968									state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24969
24970								}
24971
24972							} else {
24973
24974								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24975
24976							}
24977
24978						} else {
24979
24980							if ( useTexStorage ) {
24981
24982								state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24983
24984							} else {
24985
24986								state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24987
24988							}
24989
24990						}
24991
24992					}
24993
24994				}
24995
24996			} else if ( texture.isDataArrayTexture ) {
24997
24998				if ( useTexStorage ) {
24999
25000					if ( allocateMemory ) {
25001
25002						state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );
25003
25004					}
25005
25006					state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25007
25008				} else {
25009
25010					state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25011
25012				}
25013
25014			} else if ( texture.isData3DTexture ) {
25015
25016				if ( useTexStorage ) {
25017
25018					if ( allocateMemory ) {
25019
25020						state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );
25021
25022					}
25023
25024					state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25025
25026				} else {
25027
25028					state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25029
25030				}
25031
25032			} else if ( texture.isFramebufferTexture ) {
25033
25034				if ( allocateMemory ) {
25035
25036					if ( useTexStorage ) {
25037
25038						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25039
25040					} else {
25041
25042						let width = image.width, height = image.height;
25043
25044						for ( let i = 0; i < levels; i ++ ) {
25045
25046							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );
25047
25048							width >>= 1;
25049							height >>= 1;
25050
25051						}
25052
25053					}
25054
25055				}
25056
25057			} else {
25058
25059				// regular Texture (image, video, canvas)
25060
25061				// use manually created mipmaps if available
25062				// if there are no manual mipmaps
25063				// set 0 level mipmap and then use GL to generate other mipmap levels
25064
25065				if ( mipmaps.length > 0 && supportsMips ) {
25066
25067					if ( useTexStorage && allocateMemory ) {
25068
25069						state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
25070
25071					}
25072
25073					for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25074
25075						mipmap = mipmaps[ i ];
25076
25077						if ( useTexStorage ) {
25078
25079							state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );
25080
25081						} else {
25082
25083							state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
25084
25085						}
25086
25087					}
25088
25089					texture.generateMipmaps = false;
25090
25091				} else {
25092
25093					if ( useTexStorage ) {
25094
25095						if ( allocateMemory ) {
25096
25097							state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25098
25099						}
25100
25101						state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );
25102
25103					} else {
25104
25105						state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
25106
25107					}
25108
25109				}
25110
25111			}
25112
25113			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25114
25115				generateMipmap( textureType );
25116
25117			}
25118
25119			sourceProperties.__version = source.version;
25120
25121			if ( texture.onUpdate ) texture.onUpdate( texture );
25122
25123		}
25124
25125		textureProperties.__version = texture.version;
25126
25127	}
25128
25129	function uploadCubeTexture( textureProperties, texture, slot ) {
25130
25131		if ( texture.image.length !== 6 ) return;
25132
25133		const forceUpload = initTexture( textureProperties, texture );
25134		const source = texture.source;
25135
25136		state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
25137
25138		const sourceProperties = properties.get( source );
25139
25140		if ( source.version !== sourceProperties.__version || forceUpload === true ) {
25141
25142			state.activeTexture( _gl.TEXTURE0 + slot );
25143
25144			const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
25145			const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
25146			const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
25147
25148			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
25149			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
25150			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
25151			_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
25152
25153			const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );
25154			const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
25155
25156			const cubeImage = [];
25157
25158			for ( let i = 0; i < 6; i ++ ) {
25159
25160				if ( ! isCompressed && ! isDataTexture ) {
25161
25162					cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize );
25163
25164				} else {
25165
25166					cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
25167
25168				}
25169
25170				cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );
25171
25172			}
25173
25174			const image = cubeImage[ 0 ],
25175				supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
25176				glFormat = utils.convert( texture.format, texture.colorSpace ),
25177				glType = utils.convert( texture.type ),
25178				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25179
25180			const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true );
25181			const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
25182			let levels = getMipLevels( texture, image, supportsMips );
25183
25184			setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25185
25186			let mipmaps;
25187
25188			if ( isCompressed ) {
25189
25190				if ( useTexStorage && allocateMemory ) {
25191
25192					state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );
25193
25194				}
25195
25196				for ( let i = 0; i < 6; i ++ ) {
25197
25198					mipmaps = cubeImage[ i ].mipmaps;
25199
25200					for ( let j = 0; j < mipmaps.length; j ++ ) {
25201
25202						const mipmap = mipmaps[ j ];
25203
25204						if ( texture.format !== RGBAFormat ) {
25205
25206							if ( glFormat !== null ) {
25207
25208								if ( useTexStorage ) {
25209
25210									state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
25211
25212								} else {
25213
25214									state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
25215
25216								}
25217
25218							} else {
25219
25220								console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
25221
25222							}
25223
25224						} else {
25225
25226							if ( useTexStorage ) {
25227
25228								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
25229
25230							} else {
25231
25232								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25233
25234							}
25235
25236						}
25237
25238					}
25239
25240				}
25241
25242			} else {
25243
25244				mipmaps = texture.mipmaps;
25245
25246				if ( useTexStorage && allocateMemory ) {
25247
25248					// TODO: Uniformly handle mipmap definitions
25249					// Normal textures and compressed cube textures define base level + mips with their mipmap array
25250					// Uncompressed cube textures use their mipmap array only for mips (no base level)
25251
25252					if ( mipmaps.length > 0 ) levels ++;
25253
25254					state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height );
25255
25256				}
25257
25258				for ( let i = 0; i < 6; i ++ ) {
25259
25260					if ( isDataTexture ) {
25261
25262						if ( useTexStorage ) {
25263
25264							state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );
25265
25266						} else {
25267
25268							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
25269
25270						}
25271
25272						for ( let j = 0; j < mipmaps.length; j ++ ) {
25273
25274							const mipmap = mipmaps[ j ];
25275							const mipmapImage = mipmap.image[ i ].image;
25276
25277							if ( useTexStorage ) {
25278
25279								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );
25280
25281							} else {
25282
25283								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
25284
25285							}
25286
25287						}
25288
25289					} else {
25290
25291						if ( useTexStorage ) {
25292
25293							state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );
25294
25295						} else {
25296
25297							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
25298
25299						}
25300
25301						for ( let j = 0; j < mipmaps.length; j ++ ) {
25302
25303							const mipmap = mipmaps[ j ];
25304
25305							if ( useTexStorage ) {
25306
25307								state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );
25308
25309							} else {
25310
25311								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
25312
25313							}
25314
25315						}
25316
25317					}
25318
25319				}
25320
25321			}
25322
25323			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25324
25325				// We assume images for cube map have the same size.
25326				generateMipmap( _gl.TEXTURE_CUBE_MAP );
25327
25328			}
25329
25330			sourceProperties.__version = source.version;
25331
25332			if ( texture.onUpdate ) texture.onUpdate( texture );
25333
25334		}
25335
25336		textureProperties.__version = texture.version;
25337
25338	}
25339
25340	// Render targets
25341
25342	// Setup storage for target texture and bind it to correct framebuffer
25343	function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {
25344
25345		const glFormat = utils.convert( texture.format, texture.colorSpace );
25346		const glType = utils.convert( texture.type );
25347		const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25348		const renderTargetProperties = properties.get( renderTarget );
25349
25350		if ( ! renderTargetProperties.__hasExternalTextures ) {
25351
25352			const width = Math.max( 1, renderTarget.width >> level );
25353			const height = Math.max( 1, renderTarget.height >> level );
25354
25355			if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
25356
25357				state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null );
25358
25359			} else {
25360
25361				state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null );
25362
25363			}
25364
25365		}
25366
25367		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25368
25369		if ( useMultisampledRTT( renderTarget ) ) {
25370
25371			multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
25372
25373		} else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753
25374
25375			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );
25376
25377		}
25378
25379		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25380
25381	}
25382
25383
25384	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
25385	function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
25386
25387		_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
25388
25389		if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
25390
25391			let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16;
25392
25393			if ( isMultisample || useMultisampledRTT( renderTarget ) ) {
25394
25395				const depthTexture = renderTarget.depthTexture;
25396
25397				if ( depthTexture && depthTexture.isDepthTexture ) {
25398
25399					if ( depthTexture.type === FloatType ) {
25400
25401						glInternalFormat = _gl.DEPTH_COMPONENT32F;
25402
25403					} else if ( depthTexture.type === UnsignedIntType ) {
25404
25405						glInternalFormat = _gl.DEPTH_COMPONENT24;
25406
25407					}
25408
25409				}
25410
25411				const samples = getRenderTargetSamples( renderTarget );
25412
25413				if ( useMultisampledRTT( renderTarget ) ) {
25414
25415					multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25416
25417				} else {
25418
25419					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25420
25421				}
25422
25423			} else {
25424
25425				_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25426
25427			}
25428
25429			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25430
25431		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
25432
25433			const samples = getRenderTargetSamples( renderTarget );
25434
25435			if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25436
25437				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25438
25439			} else if ( useMultisampledRTT( renderTarget ) ) {
25440
25441				multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25442
25443			} else {
25444
25445				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
25446
25447			}
25448
25449
25450			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25451
25452		} else {
25453
25454			const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25455
25456			for ( let i = 0; i < textures.length; i ++ ) {
25457
25458				const texture = textures[ i ];
25459
25460				const glFormat = utils.convert( texture.format, texture.colorSpace );
25461				const glType = utils.convert( texture.type );
25462				const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25463				const samples = getRenderTargetSamples( renderTarget );
25464
25465				if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25466
25467					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25468
25469				} else if ( useMultisampledRTT( renderTarget ) ) {
25470
25471					multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25472
25473				} else {
25474
25475					_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25476
25477				}
25478
25479			}
25480
25481		}
25482
25483		_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25484
25485	}
25486
25487	// Setup resources for a Depth Texture for a FBO (needs an extension)
25488	function setupDepthTexture( framebuffer, renderTarget ) {
25489
25490		const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
25491		if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
25492
25493		state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25494
25495		if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
25496
25497			throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
25498
25499		}
25500
25501		// upload an empty depth texture with framebuffer size
25502		if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
25503				renderTarget.depthTexture.image.width !== renderTarget.width ||
25504				renderTarget.depthTexture.image.height !== renderTarget.height ) {
25505
25506			renderTarget.depthTexture.image.width = renderTarget.width;
25507			renderTarget.depthTexture.image.height = renderTarget.height;
25508			renderTarget.depthTexture.needsUpdate = true;
25509
25510		}
25511
25512		setTexture2D( renderTarget.depthTexture, 0 );
25513
25514		const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
25515		const samples = getRenderTargetSamples( renderTarget );
25516
25517		if ( renderTarget.depthTexture.format === DepthFormat ) {
25518
25519			if ( useMultisampledRTT( renderTarget ) ) {
25520
25521				multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25522
25523			} else {
25524
25525				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25526
25527			}
25528
25529		} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
25530
25531			if ( useMultisampledRTT( renderTarget ) ) {
25532
25533				multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25534
25535			} else {
25536
25537				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25538
25539			}
25540
25541		} else {
25542
25543			throw new Error( 'Unknown depthTexture format' );
25544
25545		}
25546
25547	}
25548
25549	// Setup GL resources for a non-texture depth buffer
25550	function setupDepthRenderbuffer( renderTarget ) {
25551
25552		const renderTargetProperties = properties.get( renderTarget );
25553		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25554
25555		if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {
25556
25557			if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
25558
25559			setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
25560
25561		} else {
25562
25563			if ( isCube ) {
25564
25565				renderTargetProperties.__webglDepthbuffer = [];
25566
25567				for ( let i = 0; i < 6; i ++ ) {
25568
25569					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
25570					renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
25571					setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
25572
25573				}
25574
25575			} else {
25576
25577				state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25578				renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
25579				setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
25580
25581			}
25582
25583		}
25584
25585		state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25586
25587	}
25588
25589	// rebind framebuffer with external textures
25590	function rebindTextures( renderTarget, colorTexture, depthTexture ) {
25591
25592		const renderTargetProperties = properties.get( renderTarget );
25593
25594		if ( colorTexture !== undefined ) {
25595
25596			setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );
25597
25598		}
25599
25600		if ( depthTexture !== undefined ) {
25601
25602			setupDepthRenderbuffer( renderTarget );
25603
25604		}
25605
25606	}
25607
25608	// Set up GL resources for the render target
25609	function setupRenderTarget( renderTarget ) {
25610
25611		const texture = renderTarget.texture;
25612
25613		const renderTargetProperties = properties.get( renderTarget );
25614		const textureProperties = properties.get( texture );
25615
25616		renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
25617
25618		if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
25619
25620			if ( textureProperties.__webglTexture === undefined ) {
25621
25622				textureProperties.__webglTexture = _gl.createTexture();
25623
25624			}
25625
25626			textureProperties.__version = texture.version;
25627			info.memory.textures ++;
25628
25629		}
25630
25631		const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25632		const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25633		const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25634
25635		// Setup framebuffer
25636
25637		if ( isCube ) {
25638
25639			renderTargetProperties.__webglFramebuffer = [];
25640
25641			for ( let i = 0; i < 6; i ++ ) {
25642
25643				if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25644
25645					renderTargetProperties.__webglFramebuffer[ i ] = [];
25646
25647					for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25648
25649						renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer();
25650
25651					}
25652
25653				} else {
25654
25655					renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
25656
25657				}
25658
25659			}
25660
25661		} else {
25662
25663			if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25664
25665				renderTargetProperties.__webglFramebuffer = [];
25666
25667				for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25668
25669					renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer();
25670
25671				}
25672
25673			} else {
25674
25675				renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
25676
25677			}
25678
25679			if ( isMultipleRenderTargets ) {
25680
25681				if ( capabilities.drawBuffers ) {
25682
25683					const textures = renderTarget.texture;
25684
25685					for ( let i = 0, il = textures.length; i < il; i ++ ) {
25686
25687						const attachmentProperties = properties.get( textures[ i ] );
25688
25689						if ( attachmentProperties.__webglTexture === undefined ) {
25690
25691							attachmentProperties.__webglTexture = _gl.createTexture();
25692
25693							info.memory.textures ++;
25694
25695						}
25696
25697					}
25698
25699				} else {
25700
25701					console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' );
25702
25703				}
25704
25705			}
25706
25707			if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25708
25709				const textures = isMultipleRenderTargets ? texture : [ texture ];
25710
25711				renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
25712				renderTargetProperties.__webglColorRenderbuffer = [];
25713
25714				state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25715
25716				for ( let i = 0; i < textures.length; i ++ ) {
25717
25718					const texture = textures[ i ];
25719					renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer();
25720
25721					_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25722
25723					const glFormat = utils.convert( texture.format, texture.colorSpace );
25724					const glType = utils.convert( texture.type );
25725					const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
25726					const samples = getRenderTargetSamples( renderTarget );
25727					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25728
25729					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25730
25731				}
25732
25733				_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25734
25735				if ( renderTarget.depthBuffer ) {
25736
25737					renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
25738					setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
25739
25740				}
25741
25742				state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25743
25744			}
25745
25746		}
25747
25748		// Setup color buffer
25749
25750		if ( isCube ) {
25751
25752			state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
25753			setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25754
25755			for ( let i = 0; i < 6; i ++ ) {
25756
25757				if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25758
25759					for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25760
25761						setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );
25762
25763					}
25764
25765				} else {
25766
25767					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 );
25768
25769				}
25770
25771			}
25772
25773			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25774
25775				generateMipmap( _gl.TEXTURE_CUBE_MAP );
25776
25777			}
25778
25779			state.unbindTexture();
25780
25781		} else if ( isMultipleRenderTargets ) {
25782
25783			const textures = renderTarget.texture;
25784
25785			for ( let i = 0, il = textures.length; i < il; i ++ ) {
25786
25787				const attachment = textures[ i ];
25788				const attachmentProperties = properties.get( attachment );
25789
25790				state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );
25791				setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips );
25792				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );
25793
25794				if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) {
25795
25796					generateMipmap( _gl.TEXTURE_2D );
25797
25798				}
25799
25800			}
25801
25802			state.unbindTexture();
25803
25804		} else {
25805
25806			let glTextureType = _gl.TEXTURE_2D;
25807
25808			if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {
25809
25810				if ( isWebGL2 ) {
25811
25812					glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;
25813
25814				} else {
25815
25816					console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' );
25817
25818				}
25819
25820			}
25821
25822			state.bindTexture( glTextureType, textureProperties.__webglTexture );
25823			setTextureParameters( glTextureType, texture, supportsMips );
25824
25825			if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25826
25827				for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25828
25829					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level );
25830
25831				}
25832
25833			} else {
25834
25835				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );
25836
25837			}
25838
25839			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25840
25841				generateMipmap( glTextureType );
25842
25843			}
25844
25845			state.unbindTexture();
25846
25847		}
25848
25849		// Setup depth and stencil buffers
25850
25851		if ( renderTarget.depthBuffer ) {
25852
25853			setupDepthRenderbuffer( renderTarget );
25854
25855		}
25856
25857	}
25858
25859	function updateRenderTargetMipmap( renderTarget ) {
25860
25861		const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25862
25863		const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25864
25865		for ( let i = 0, il = textures.length; i < il; i ++ ) {
25866
25867			const texture = textures[ i ];
25868
25869			if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25870
25871				const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
25872				const webglTexture = properties.get( texture ).__webglTexture;
25873
25874				state.bindTexture( target, webglTexture );
25875				generateMipmap( target );
25876				state.unbindTexture();
25877
25878			}
25879
25880		}
25881
25882	}
25883
25884	function updateMultisampleRenderTarget( renderTarget ) {
25885
25886		if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25887
25888			const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ];
25889			const width = renderTarget.width;
25890			const height = renderTarget.height;
25891			let mask = _gl.COLOR_BUFFER_BIT;
25892			const invalidationArray = [];
25893			const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
25894			const renderTargetProperties = properties.get( renderTarget );
25895			const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25896
25897			// If MRT we need to remove FBO attachments
25898			if ( isMultipleRenderTargets ) {
25899
25900				for ( let i = 0; i < textures.length; i ++ ) {
25901
25902					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25903					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );
25904
25905					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25906					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );
25907
25908				}
25909
25910			}
25911
25912			state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25913			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25914
25915			for ( let i = 0; i < textures.length; i ++ ) {
25916
25917				invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i );
25918
25919				if ( renderTarget.depthBuffer ) {
25920
25921					invalidationArray.push( depthStyle );
25922
25923				}
25924
25925				const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false;
25926
25927				if ( ignoreDepthValues === false ) {
25928
25929					if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
25930					if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
25931
25932				}
25933
25934				if ( isMultipleRenderTargets ) {
25935
25936					_gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25937
25938				}
25939
25940				if ( ignoreDepthValues === true ) {
25941
25942					_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] );
25943					_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
25944
25945				}
25946
25947				if ( isMultipleRenderTargets ) {
25948
25949					const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25950					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );
25951
25952				}
25953
25954				_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
25955
25956				if ( supportsInvalidateFramebuffer ) {
25957
25958					_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray );
25959
25960				}
25961
25962
25963			}
25964
25965			state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
25966			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );
25967
25968			// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments
25969			if ( isMultipleRenderTargets ) {
25970
25971				for ( let i = 0; i < textures.length; i ++ ) {
25972
25973					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25974					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25975
25976					const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25977
25978					state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25979					_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );
25980
25981				}
25982
25983			}
25984
25985			state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25986
25987		}
25988
25989	}
25990
25991	function getRenderTargetSamples( renderTarget ) {
25992
25993		return Math.min( capabilities.maxSamples, renderTarget.samples );
25994
25995	}
25996
25997	function useMultisampledRTT( renderTarget ) {
25998
25999		const renderTargetProperties = properties.get( renderTarget );
26000
26001		return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;
26002
26003	}
26004
26005	function updateVideoTexture( texture ) {
26006
26007		const frame = info.render.frame;
26008
26009		// Check the last frame we updated the VideoTexture
26010
26011		if ( _videoTextures.get( texture ) !== frame ) {
26012
26013			_videoTextures.set( texture, frame );
26014			texture.update();
26015
26016		}
26017
26018	}
26019
26020	function verifyColorSpace( texture, image ) {
26021
26022		const colorSpace = texture.colorSpace;
26023		const format = texture.format;
26024		const type = texture.type;
26025
26026		if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
26027
26028		if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {
26029
26030			// sRGB
26031
26032			if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {
26033
26034				if ( isWebGL2 === false ) {
26035
26036					// in WebGL 1, try to use EXT_sRGB extension and unsized formats
26037
26038					if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) {
26039
26040						texture.format = _SRGBAFormat;
26041
26042						// it's not possible to generate mips in WebGL 1 with this extension
26043
26044						texture.minFilter = LinearFilter;
26045						texture.generateMipmaps = false;
26046
26047					} else {
26048
26049						// slow fallback (CPU decode)
26050
26051						image = ImageUtils.sRGBToLinear( image );
26052
26053					}
26054
26055				} else {
26056
26057					// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
26058
26059					if ( format !== RGBAFormat || type !== UnsignedByteType ) {
26060
26061						console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );
26062
26063					}
26064
26065				}
26066
26067			} else {
26068
26069				console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );
26070
26071			}
26072
26073		}
26074
26075		return image
vendor: 16,386 bytes, lines 26075-26742
26075;
26076
26077	}
26078
26079	//
26080
26081	this.allocateTextureUnit = allocateTextureUnit;
26082	this.resetTextureUnits = resetTextureUnits;
26083
26084	this.setTexture2D = setTexture2D;
26085	this.setTexture2DArray = setTexture2DArray;
26086	this.setTexture3D = setTexture3D;
26087	this.setTextureCube = setTextureCube;
26088	this.rebindTextures = rebindTextures;
26089	this.setupRenderTarget = setupRenderTarget;
26090	this.updateRenderTargetMipmap = updateRenderTargetMipmap;
26091	this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
26092	this.setupDepthRenderbuffer = setupDepthRenderbuffer;
26093	this.setupFrameBufferTexture = setupFrameBufferTexture;
26094	this.useMultisampledRTT = useMultisampledRTT;
26095
26096}
26097
26098function WebGLUtils( gl, extensions, capabilities ) {
26099
26100	const isWebGL2 = capabilities.isWebGL2;
26101
26102	function convert( p, colorSpace = NoColorSpace ) {
26103
26104		let extension;
26105
26106		const transfer = ColorManagement.getTransfer( colorSpace );
26107
26108		if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
26109		if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
26110		if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
26111
26112		if ( p === ByteType ) return gl.BYTE;
26113		if ( p === ShortType ) return gl.SHORT;
26114		if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
26115		if ( p === IntType ) return gl.INT;
26116		if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
26117		if ( p === FloatType ) return gl.FLOAT;
26118
26119		if ( p === HalfFloatType ) {
26120
26121			if ( isWebGL2 ) return gl.HALF_FLOAT;
26122
26123			extension = extensions.get( 'OES_texture_half_float' );
26124
26125			if ( extension !== null ) {
26126
26127				return extension.HALF_FLOAT_OES;
26128
26129			} else {
26130
26131				return null;
26132
26133			}
26134
26135		}
26136
26137		if ( p === AlphaFormat ) return gl.ALPHA;
26138		if ( p === RGBAFormat ) return gl.RGBA;
26139		if ( p === LuminanceFormat ) return gl.LUMINANCE;
26140		if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
26141		if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
26142		if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
26143
26144		// WebGL 1 sRGB fallback
26145
26146		if ( p === _SRGBAFormat ) {
26147
26148			extension = extensions.get( 'EXT_sRGB' );
26149
26150			if ( extension !== null ) {
26151
26152				return extension.SRGB_ALPHA_EXT;
26153
26154			} else {
26155
26156				return null;
26157
26158			}
26159
26160		}
26161
26162		// WebGL2 formats.
26163
26164		if ( p === RedFormat ) return gl.RED;
26165		if ( p === RedIntegerFormat ) return gl.RED_INTEGER;
26166		if ( p === RGFormat ) return gl.RG;
26167		if ( p === RGIntegerFormat ) return gl.RG_INTEGER;
26168		if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;
26169
26170		// S3TC
26171
26172		if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
26173
26174			if ( transfer === SRGBTransfer ) {
26175
26176				extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
26177
26178				if ( extension !== null ) {
26179
26180					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
26181					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
26182					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
26183					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
26184
26185				} else {
26186
26187					return null;
26188
26189				}
26190
26191			} else {
26192
26193				extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
26194
26195				if ( extension !== null ) {
26196
26197					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
26198					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
26199					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
26200					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
26201
26202				} else {
26203
26204					return null;
26205
26206				}
26207
26208			}
26209
26210		}
26211
26212		// PVRTC
26213
26214		if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
26215
26216			extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
26217
26218			if ( extension !== null ) {
26219
26220				if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
26221				if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
26222				if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
26223				if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
26224
26225			} else {
26226
26227				return null;
26228
26229			}
26230
26231		}
26232
26233		// ETC1
26234
26235		if ( p === RGB_ETC1_Format ) {
26236
26237			extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
26238
26239			if ( extension !== null ) {
26240
26241				return extension.COMPRESSED_RGB_ETC1_WEBGL;
26242
26243			} else {
26244
26245				return null;
26246
26247			}
26248
26249		}
26250
26251		// ETC2
26252
26253		if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
26254
26255			extension = extensions.get( 'WEBGL_compressed_texture_etc' );
26256
26257			if ( extension !== null ) {
26258
26259				if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
26260				if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
26261
26262			} else {
26263
26264				return null;
26265
26266			}
26267
26268		}
26269
26270		// ASTC
26271
26272		if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
26273			p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
26274			p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
26275			p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
26276			p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {
26277
26278			extension = extensions.get( 'WEBGL_compressed_texture_astc' );
26279
26280			if ( extension !== null ) {
26281
26282				if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
26283				if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
26284				if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
26285				if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
26286				if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
26287				if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
26288				if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
26289				if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
26290				if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
26291				if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
26292				if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
26293				if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
26294				if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
26295				if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
26296
26297			} else {
26298
26299				return null;
26300
26301			}
26302
26303		}
26304
26305		// BPTC
26306
26307		if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {
26308
26309			extension = extensions.get( 'EXT_texture_compression_bptc' );
26310
26311			if ( extension !== null ) {
26312
26313				if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
26314				if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
26315				if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
26316
26317			} else {
26318
26319				return null;
26320
26321			}
26322
26323		}
26324
26325		// RGTC
26326
26327		if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) {
26328
26329			extension = extensions.get( 'EXT_texture_compression_rgtc' );
26330
26331			if ( extension !== null ) {
26332
26333				if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;
26334				if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;
26335				if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;
26336				if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
26337
26338			} else {
26339
26340				return null;
26341
26342			}
26343
26344		}
26345
26346		//
26347
26348		if ( p === UnsignedInt248Type ) {
26349
26350			if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8;
26351
26352			extension = extensions.get( 'WEBGL_depth_texture' );
26353
26354			if ( extension !== null ) {
26355
26356				return extension.UNSIGNED_INT_24_8_WEBGL;
26357
26358			} else {
26359
26360				return null;
26361
26362			}
26363
26364		}
26365
26366		// if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)
26367
26368		return ( gl[ p ] !== undefined ) ? gl[ p ] : null;
26369
26370	}
26371
26372	return { convert: convert };
26373
26374}
26375
26376class ArrayCamera extends PerspectiveCamera {
26377
26378	constructor( array = [] ) {
26379
26380		super();
26381
26382		this.isArrayCamera = true;
26383
26384		this.cameras = array;
26385
26386	}
26387
26388}
26389
26390class Group extends Object3D {
26391
26392	constructor() {
26393
26394		super();
26395
26396		this.isGroup = true;
26397
26398		this.type = 'Group';
26399
26400	}
26401
26402}
26403
26404const _moveEvent = { type: 'move' };
26405
26406class WebXRController {
26407
26408	constructor() {
26409
26410		this._targetRay = null;
26411		this._grip = null;
26412		this._hand = null;
26413
26414	}
26415
26416	getHandSpace() {
26417
26418		if ( this._hand === null ) {
26419
26420			this._hand = new Group();
26421			this._hand.matrixAutoUpdate = false;
26422			this._hand.visible = false;
26423
26424			this._hand.joints = {};
26425			this._hand.inputState = { pinching: false };
26426
26427		}
26428
26429		return this._hand;
26430
26431	}
26432
26433	getTargetRaySpace() {
26434
26435		if ( this._targetRay === null ) {
26436
26437			this._targetRay = new Group();
26438			this._targetRay.matrixAutoUpdate = false;
26439			this._targetRay.visible = false;
26440			this._targetRay.hasLinearVelocity = false;
26441			this._targetRay.linearVelocity = new Vector3();
26442			this._targetRay.hasAngularVelocity = false;
26443			this._targetRay.angularVelocity = new Vector3();
26444
26445		}
26446
26447		return this._targetRay;
26448
26449	}
26450
26451	getGripSpace() {
26452
26453		if ( this._grip === null ) {
26454
26455			this._grip = new Group();
26456			this._grip.matrixAutoUpdate = false;
26457			this._grip.visible = false;
26458			this._grip.hasLinearVelocity = false;
26459			this._grip.linearVelocity = new Vector3();
26460			this._grip.hasAngularVelocity = false;
26461			this._grip.angularVelocity = new Vector3();
26462
26463		}
26464
26465		return this._grip;
26466
26467	}
26468
26469	dispatchEvent( event ) {
26470
26471		if ( this._targetRay !== null ) {
26472
26473			this._targetRay.dispatchEvent( event );
26474
26475		}
26476
26477		if ( this._grip !== null ) {
26478
26479			this._grip.dispatchEvent( event );
26480
26481		}
26482
26483		if ( this._hand !== null ) {
26484
26485			this._hand.dispatchEvent( event );
26486
26487		}
26488
26489		return this;
26490
26491	}
26492
26493	connect( inputSource ) {
26494
26495		if ( inputSource && inputSource.hand ) {
26496
26497			const hand = this._hand;
26498
26499			if ( hand ) {
26500
26501				for ( const inputjoint of inputSource.hand.values() ) {
26502
26503					// Initialize hand with joints when connected
26504					this._getHandJoint( hand, inputjoint );
26505
26506				}
26507
26508			}
26509
26510		}
26511
26512		this.dispatchEvent( { type: 'connected', data: inputSource } );
26513
26514		return this;
26515
26516	}
26517
26518	disconnect( inputSource ) {
26519
26520		this.dispatchEvent( { type: 'disconnected', data: inputSource } );
26521
26522		if ( this._targetRay !== null ) {
26523
26524			this._targetRay.visible = false;
26525
26526		}
26527
26528		if ( this._grip !== null ) {
26529
26530			this._grip.visible = false;
26531
26532		}
26533
26534		if ( this._hand !== null ) {
26535
26536			this._hand.visible = false;
26537
26538		}
26539
26540		return this;
26541
26542	}
26543
26544	update( inputSource, frame, referenceSpace ) {
26545
26546		let inputPose = null;
26547		let gripPose = null;
26548		let handPose = null;
26549
26550		const targetRay = this._targetRay;
26551		const grip = this._grip;
26552		const hand = this._hand;
26553
26554		if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
26555
26556			if ( hand && inputSource.hand ) {
26557
26558				handPose = true;
26559
26560				for ( const inputjoint of inputSource.hand.values() ) {
26561
26562					// Update the joints groups with the XRJoint poses
26563					const jointPose = frame.getJointPose( inputjoint, referenceSpace );
26564
26565					// The transform of this joint will be updated with the joint pose on each frame
26566					const joint = this._getHandJoint( hand, inputjoint );
26567
26568					if ( jointPose !== null ) {
26569
26570						joint.matrix.fromArray( jointPose.transform.matrix );
26571						joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
26572						joint.matrixWorldNeedsUpdate = true;
26573						joint.jointRadius = jointPose.radius;
26574
26575					}
26576
26577					joint.visible = jointPose !== null;
26578
26579				}
26580
26581				// Custom events
26582
26583				// Check pinchz
26584				const indexTip = hand.joints[ 'index-finger-tip' ];
26585				const thumbTip = hand.joints[ 'thumb-tip' ];
26586				const distance = indexTip.position.distanceTo( thumbTip.position );
26587
26588				const distanceToPinch = 0.02;
26589				const threshold = 0.005;
26590
26591				if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
26592
26593					hand.inputState.pinching = false;
26594					this.dispatchEvent( {
26595						type: 'pinchend',
26596						handedness: inputSource.handedness,
26597						target: this
26598					} );
26599
26600				} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
26601
26602					hand.inputState.pinching = true;
26603					this.dispatchEvent( {
26604						type: 'pinchstart',
26605						handedness: inputSource.handedness,
26606						target: this
26607					} );
26608
26609				}
26610
26611			} else {
26612
26613				if ( grip !== null && inputSource.gripSpace ) {
26614
26615					gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
26616
26617					if ( gripPose !== null ) {
26618
26619						grip.matrix.fromArray( gripPose.transform.matrix );
26620						grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
26621						grip.matrixWorldNeedsUpdate = true;
26622
26623						if ( gripPose.linearVelocity ) {
26624
26625							grip.hasLinearVelocity = true;
26626							grip.linearVelocity.copy( gripPose.linearVelocity );
26627
26628						} else {
26629
26630							grip.hasLinearVelocity = false;
26631
26632						}
26633
26634						if ( gripPose.angularVelocity ) {
26635
26636							grip.hasAngularVelocity = true;
26637							grip.angularVelocity.copy( gripPose.angularVelocity );
26638
26639						} else {
26640
26641							grip.hasAngularVelocity = false;
26642
26643						}
26644
26645					}
26646
26647				}
26648
26649			}
26650
26651			if ( targetRay !== null ) {
26652
26653				inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
26654
26655				// Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it
26656				if ( inputPose === null && gripPose !== null ) {
26657
26658					inputPose = gripPose;
26659
26660				}
26661
26662				if ( inputPose !== null ) {
26663
26664					targetRay.matrix.fromArray( inputPose.transform.matrix );
26665					targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
26666					targetRay.matrixWorldNeedsUpdate = true;
26667
26668					if ( inputPose.linearVelocity ) {
26669
26670						targetRay.hasLinearVelocity = true;
26671						targetRay.linearVelocity.copy( inputPose.linearVelocity );
26672
26673					} else {
26674
26675						targetRay.hasLinearVelocity = false;
26676
26677					}
26678
26679					if ( inputPose.angularVelocity ) {
26680
26681						targetRay.hasAngularVelocity = true;
26682						targetRay.angularVelocity.copy( inputPose.angularVelocity );
26683
26684					} else {
26685
26686						targetRay.hasAngularVelocity = false;
26687
26688					}
26689
26690					this.dispatchEvent( _moveEvent );
26691
26692				}
26693
26694			}
26695
26696
26697		}
26698
26699		if ( targetRay !== null ) {
26700
26701			targetRay.visible = ( inputPose !== null );
26702
26703		}
26704
26705		if ( grip !== null ) {
26706
26707			grip.visible = ( gripPose !== null );
26708
26709		}
26710
26711		if ( hand !== null ) {
26712
26713			hand.visible = ( handPose !== null );
26714
26715		}
26716
26717		return this;
26718
26719	}
26720
26721	// private method
26722
26723	_getHandJoint( hand, inputjoint ) {
26724
26725		if ( hand.joints[ inputjoint.jointName ] === undefined ) {
26726
26727			const joint = new Group();
26728			joint.matrixAutoUpdate = false;
26729			joint.visible = false;
26730			hand.joints[ inputjoint.jointName ] = joint;
26731
26732			hand.add( joint );
26733
26734		}
26735
26736		return hand.joints[ inputjoint.jointName ];
26737
26738	}
26739
26740}
26741
26742c
vendor: 41,656 bytes, lines 26742-28561
26742lass WebXRManager extends EventDispatcher {
26743
26744	constructor( renderer, gl ) {
26745
26746		super();
26747
26748		const scope = this;
26749
26750		let session = null;
26751
26752		let framebufferScaleFactor = 1.0;
26753
26754		let referenceSpace = null;
26755		let referenceSpaceType = 'local-floor';
26756		// Set default foveation to maximum.
26757		let foveation = 1.0;
26758		let customReferenceSpace = null;
26759
26760		let pose = null;
26761		let glBinding = null;
26762		let glProjLayer = null;
26763		let glBaseLayer = null;
26764		let xrFrame = null;
26765		const attributes = gl.getContextAttributes();
26766		let initialRenderTarget = null;
26767		let newRenderTarget = null;
26768
26769		const controllers = [];
26770		const controllerInputSources = [];
26771
26772		const currentSize = new Vector2();
26773		let currentPixelRatio = null;
26774
26775		//
26776
26777		const cameraL = new PerspectiveCamera();
26778		cameraL.layers.enable( 1 );
26779		cameraL.viewport = new Vector4();
26780
26781		const cameraR = new PerspectiveCamera();
26782		cameraR.layers.enable( 2 );
26783		cameraR.viewport = new Vector4();
26784
26785		const cameras = [ cameraL, cameraR ];
26786
26787		const cameraXR = new ArrayCamera();
26788		cameraXR.layers.enable( 1 );
26789		cameraXR.layers.enable( 2 );
26790
26791		let _currentDepthNear = null;
26792		let _currentDepthFar = null;
26793
26794		//
26795
26796		this.cameraAutoUpdate = true;
26797		this.enabled = false;
26798
26799		this.isPresenting = false;
26800
26801		this.getController = function ( index ) {
26802
26803			let controller = controllers[ index ];
26804
26805			if ( controller === undefined ) {
26806
26807				controller = new WebXRController();
26808				controllers[ index ] = controller;
26809
26810			}
26811
26812			return controller.getTargetRaySpace();
26813
26814		};
26815
26816		this.getControllerGrip = function ( index ) {
26817
26818			let controller = controllers[ index ];
26819
26820			if ( controller === undefined ) {
26821
26822				controller = new WebXRController();
26823				controllers[ index ] = controller;
26824
26825			}
26826
26827			return controller.getGripSpace();
26828
26829		};
26830
26831		this.getHand = function ( index ) {
26832
26833			let controller = controllers[ index ];
26834
26835			if ( controller === undefined ) {
26836
26837				controller = new WebXRController();
26838				controllers[ index ] = controller;
26839
26840			}
26841
26842			return controller.getHandSpace();
26843
26844		};
26845
26846		//
26847
26848		function onSessionEvent( event ) {
26849
26850			const controllerIndex = controllerInputSources.indexOf( event.inputSource );
26851
26852			if ( controllerIndex === - 1 ) {
26853
26854				return;
26855
26856			}
26857
26858			const controller = controllers[ controllerIndex ];
26859
26860			if ( controller !== undefined ) {
26861
26862				controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );
26863				controller.dispatchEvent( { type: event.type, data: event.inputSource } );
26864
26865			}
26866
26867		}
26868
26869		function onSessionEnd() {
26870
26871			session.removeEventListener( 'select', onSessionEvent );
26872			session.removeEventListener( 'selectstart', onSessionEvent );
26873			session.removeEventListener( 'selectend', onSessionEvent );
26874			session.removeEventListener( 'squeeze', onSessionEvent );
26875			session.removeEventListener( 'squeezestart', onSessionEvent );
26876			session.removeEventListener( 'squeezeend', onSessionEvent );
26877			session.removeEventListener( 'end', onSessionEnd );
26878			session.removeEventListener( 'inputsourceschange', onInputSourcesChange );
26879
26880			for ( let i = 0; i < controllers.length; i ++ ) {
26881
26882				const inputSource = controllerInputSources[ i ];
26883
26884				if ( inputSource === null ) continue;
26885
26886				controllerInputSources[ i ] = null;
26887
26888				controllers[ i ].disconnect( inputSource );
26889
26890			}
26891
26892			_currentDepthNear = null;
26893			_currentDepthFar = null;
26894
26895			// restore framebuffer/rendering state
26896
26897			renderer.setRenderTarget( initialRenderTarget );
26898
26899			glBaseLayer = null;
26900			glProjLayer = null;
26901			glBinding = null;
26902			session = null;
26903			newRenderTarget = null;
26904
26905			//
26906
26907			animation.stop();
26908
26909			scope.isPresenting = false;
26910
26911			renderer.setPixelRatio( currentPixelRatio );
26912			renderer.setSize( currentSize.width, currentSize.height, false );
26913
26914			scope.dispatchEvent( { type: 'sessionend' } );
26915
26916		}
26917
26918		this.setFramebufferScaleFactor = function ( value ) {
26919
26920			framebufferScaleFactor = value;
26921
26922			if ( scope.isPresenting === true ) {
26923
26924				console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
26925
26926			}
26927
26928		};
26929
26930		this.setReferenceSpaceType = function ( value ) {
26931
26932			referenceSpaceType = value;
26933
26934			if ( scope.isPresenting === true ) {
26935
26936				console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
26937
26938			}
26939
26940		};
26941
26942		this.getReferenceSpace = function () {
26943
26944			return customReferenceSpace || referenceSpace;
26945
26946		};
26947
26948		this.setReferenceSpace = function ( space ) {
26949
26950			customReferenceSpace = space;
26951
26952		};
26953
26954		this.getBaseLayer = function () {
26955
26956			return glProjLayer !== null ? glProjLayer : glBaseLayer;
26957
26958		};
26959
26960		this.getBinding = function () {
26961
26962			return glBinding;
26963
26964		};
26965
26966		this.getFrame = function () {
26967
26968			return xrFrame;
26969
26970		};
26971
26972		this.getSession = function () {
26973
26974			return session;
26975
26976		};
26977
26978		this.setSession = async function ( value ) {
26979
26980			session = value;
26981
26982			if ( session !== null ) {
26983
26984				initialRenderTarget = renderer.getRenderTarget();
26985
26986				session.addEventListener( 'select', onSessionEvent );
26987				session.addEventListener( 'selectstart', onSessionEvent );
26988				session.addEventListener( 'selectend', onSessionEvent );
26989				session.addEventListener( 'squeeze', onSessionEvent );
26990				session.addEventListener( 'squeezestart', onSessionEvent );
26991				session.addEventListener( 'squeezeend', onSessionEvent );
26992				session.addEventListener( 'end', onSessionEnd );
26993				session.addEventListener( 'inputsourceschange', onInputSourcesChange );
26994
26995				if ( attributes.xrCompatible !== true ) {
26996
26997					await gl.makeXRCompatible();
26998
26999				}
27000
27001				currentPixelRatio = renderer.getPixelRatio();
27002				renderer.getSize( currentSize );
27003
27004				if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) {
27005
27006					const layerInit = {
27007						antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true,
27008						alpha: true,
27009						depth: attributes.depth,
27010						stencil: attributes.stencil,
27011						framebufferScaleFactor: framebufferScaleFactor
27012					};
27013
27014					glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
27015
27016					session.updateRenderState( { baseLayer: glBaseLayer } );
27017
27018					renderer.setPixelRatio( 1 );
27019					renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );
27020
27021					newRenderTarget = new WebGLRenderTarget(
27022						glBaseLayer.framebufferWidth,
27023						glBaseLayer.framebufferHeight,
27024						{
27025							format: RGBAFormat,
27026							type: UnsignedByteType,
27027							colorSpace: renderer.outputColorSpace,
27028							stencilBuffer: attributes.stencil
27029						}
27030					);
27031
27032				} else {
27033
27034					let depthFormat = null;
27035					let depthType = null;
27036					let glDepthFormat = null;
27037
27038					if ( attributes.depth ) {
27039
27040						glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
27041						depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;
27042						depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType;
27043
27044					}
27045
27046					const projectionlayerInit = {
27047						colorFormat: gl.RGBA8,
27048						depthFormat: glDepthFormat,
27049						scaleFactor: framebufferScaleFactor
27050					};
27051
27052					glBinding = new XRWebGLBinding( session, gl );
27053
27054					glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
27055
27056					session.updateRenderState( { layers: [ glProjLayer ] } );
27057
27058					renderer.setPixelRatio( 1 );
27059					renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );
27060
27061					newRenderTarget = new WebGLRenderTarget(
27062						glProjLayer.textureWidth,
27063						glProjLayer.textureHeight,
27064						{
27065							format: RGBAFormat,
27066							type: UnsignedByteType,
27067							depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
27068							stencilBuffer: attributes.stencil,
27069							colorSpace: renderer.outputColorSpace,
27070							samples: attributes.antialias ? 4 : 0
27071						} );
27072
27073					const renderTargetProperties = renderer.properties.get( newRenderTarget );
27074					renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues;
27075
27076				}
27077
27078				newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278
27079
27080				this.setFoveation( foveation );
27081
27082				customReferenceSpace = null;
27083				referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
27084
27085				animation.setContext( session );
27086				animation.start();
27087
27088				scope.isPresenting = true;
27089
27090				scope.dispatchEvent( { type: 'sessionstart' } );
27091
27092			}
27093
27094		};
27095
27096		this.getEnvironmentBlendMode = function () {
27097
27098			if ( session !== null ) {
27099
27100				return session.environmentBlendMode;
27101
27102			}
27103
27104		};
27105
27106		function onInputSourcesChange( event ) {
27107
27108			// Notify disconnected
27109
27110			for ( let i = 0; i < event.removed.length; i ++ ) {
27111
27112				const inputSource = event.removed[ i ];
27113				const index = controllerInputSources.indexOf( inputSource );
27114
27115				if ( index >= 0 ) {
27116
27117					controllerInputSources[ index ] = null;
27118					controllers[ index ].disconnect( inputSource );
27119
27120				}
27121
27122			}
27123
27124			// Notify connected
27125
27126			for ( let i = 0; i < event.added.length; i ++ ) {
27127
27128				const inputSource = event.added[ i ];
27129
27130				let controllerIndex = controllerInputSources.indexOf( inputSource );
27131
27132				if ( controllerIndex === - 1 ) {
27133
27134					// Assign input source a controller that currently has no input source
27135
27136					for ( let i = 0; i < controllers.length; i ++ ) {
27137
27138						if ( i >= controllerInputSources.length ) {
27139
27140							controllerInputSources.push( inputSource );
27141							controllerIndex = i;
27142							break;
27143
27144						} else if ( controllerInputSources[ i ] === null ) {
27145
27146							controllerInputSources[ i ] = inputSource;
27147							controllerIndex = i;
27148							break;
27149
27150						}
27151
27152					}
27153
27154					// If all controllers do currently receive input we ignore new ones
27155
27156					if ( controllerIndex === - 1 ) break;
27157
27158				}
27159
27160				const controller = controllers[ controllerIndex ];
27161
27162				if ( controller ) {
27163
27164					controller.connect( inputSource );
27165
27166				}
27167
27168			}
27169
27170		}
27171
27172		//
27173
27174		const cameraLPos = new Vector3();
27175		const cameraRPos = new Vector3();
27176
27177		/**
27178		 * Assumes 2 cameras that are parallel and share an X-axis, and that
27179		 * the cameras' projection and world matrices have already been set.
27180		 * And that near and far planes are identical for both cameras.
27181		 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
27182		 */
27183		function setProjectionFromUnion( camera, cameraL, cameraR ) {
27184
27185			cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
27186			cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
27187
27188			const ipd = cameraLPos.distanceTo( cameraRPos );
27189
27190			const projL = cameraL.projectionMatrix.elements;
27191			const projR = cameraR.projectionMatrix.elements;
27192
27193			// VR systems will have identical far and near planes, and
27194			// most likely identical top and bottom frustum extents.
27195			// Use the left camera for these values.
27196			const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
27197			const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
27198			const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
27199			const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
27200
27201			const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
27202			const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
27203			const left = near * leftFov;
27204			const right = near * rightFov;
27205
27206			// Calculate the new camera's position offset from the
27207			// left camera. xOffset should be roughly half `ipd`.
27208			const zOffset = ipd / ( - leftFov + rightFov );
27209			const xOffset = zOffset * - leftFov;
27210
27211			// TODO: Better way to apply this offset?
27212			cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
27213			camera.translateX( xOffset );
27214			camera.translateZ( zOffset );
27215			camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
27216			camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27217
27218			// Find the union of the frustum values of the cameras and scale
27219			// the values so that the near plane's position does not change in world space,
27220			// although must now be relative to the new union camera.
27221			const near2 = near + zOffset;
27222			const far2 = far + zOffset;
27223			const left2 = left - xOffset;
27224			const right2 = right + ( ipd - xOffset );
27225			const top2 = topFov * far / far2 * near2;
27226			const bottom2 = bottomFov * far / far2 * near2;
27227
27228			camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
27229			camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27230
27231		}
27232
27233		function updateCamera( camera, parent ) {
27234
27235			if ( parent === null ) {
27236
27237				camera.matrixWorld.copy( camera.matrix );
27238
27239			} else {
27240
27241				camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
27242
27243			}
27244
27245			camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27246
27247		}
27248
27249		this.updateCamera = function ( camera ) {
27250
27251			if ( session === null ) return;
27252
27253			cameraXR.near = cameraR.near = cameraL.near = camera.near;
27254			cameraXR.far = cameraR.far = cameraL.far = camera.far;
27255
27256			if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {
27257
27258				// Note that the new renderState won't apply until the next frame. See #18320
27259
27260				session.updateRenderState( {
27261					depthNear: cameraXR.near,
27262					depthFar: cameraXR.far
27263				} );
27264
27265				_currentDepthNear = cameraXR.near;
27266				_currentDepthFar = cameraXR.far;
27267
27268			}
27269
27270			const parent = camera.parent;
27271			const cameras = cameraXR.cameras;
27272
27273			updateCamera( cameraXR, parent );
27274
27275			for ( let i = 0; i < cameras.length; i ++ ) {
27276
27277				updateCamera( cameras[ i ], parent );
27278
27279			}
27280
27281			// update projection matrix for proper view frustum culling
27282
27283			if ( cameras.length === 2 ) {
27284
27285				setProjectionFromUnion( cameraXR, cameraL, cameraR );
27286
27287			} else {
27288
27289				// assume single camera setup (AR)
27290
27291				cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );
27292
27293			}
27294
27295			// update user camera and its children
27296
27297			updateUserCamera( camera, cameraXR, parent );
27298
27299		};
27300
27301		function updateUserCamera( camera, cameraXR, parent ) {
27302
27303			if ( parent === null ) {
27304
27305				camera.matrix.copy( cameraXR.matrixWorld );
27306
27307			} else {
27308
27309				camera.matrix.copy( parent.matrixWorld );
27310				camera.matrix.invert();
27311				camera.matrix.multiply( cameraXR.matrixWorld );
27312
27313			}
27314
27315			camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27316			camera.updateMatrixWorld( true );
27317
27318			camera.projectionMatrix.copy( cameraXR.projectionMatrix );
27319			camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
27320
27321			if ( camera.isPerspectiveCamera ) {
27322
27323				camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
27324				camera.zoom = 1;
27325
27326			}
27327
27328		}
27329
27330		this.getCamera = function () {
27331
27332			return cameraXR;
27333
27334		};
27335
27336		this.getFoveation = function () {
27337
27338			if ( glProjLayer === null && glBaseLayer === null ) {
27339
27340				return undefined;
27341
27342			}
27343
27344			return foveation;
27345
27346		};
27347
27348		this.setFoveation = function ( value ) {
27349
27350			// 0 = no foveation = full resolution
27351			// 1 = maximum foveation = the edges render at lower resolution
27352
27353			foveation = value;
27354
27355			if ( glProjLayer !== null ) {
27356
27357				glProjLayer.fixedFoveation = value;
27358
27359			}
27360
27361			if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {
27362
27363				glBaseLayer.fixedFoveation = value;
27364
27365			}
27366
27367		};
27368
27369		// Animation Loop
27370
27371		let onAnimationFrameCallback = null;
27372
27373		function onAnimationFrame( time, frame ) {
27374
27375			pose = frame.getViewerPose( customReferenceSpace || referenceSpace );
27376			xrFrame = frame;
27377
27378			if ( pose !== null ) {
27379
27380				const views = pose.views;
27381
27382				if ( glBaseLayer !== null ) {
27383
27384					renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
27385					renderer.setRenderTarget( newRenderTarget );
27386
27387				}
27388
27389				let cameraXRNeedsUpdate = false;
27390
27391				// check if it's necessary to rebuild cameraXR's camera list
27392
27393				if ( views.length !== cameraXR.cameras.length ) {
27394
27395					cameraXR.cameras.length = 0;
27396					cameraXRNeedsUpdate = true;
27397
27398				}
27399
27400				for ( let i = 0; i < views.length; i ++ ) {
27401
27402					const view = views[ i ];
27403
27404					let viewport = null;
27405
27406					if ( glBaseLayer !== null ) {
27407
27408						viewport = glBaseLayer.getViewport( view );
27409
27410					} else {
27411
27412						const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
27413						viewport = glSubImage.viewport;
27414
27415						// For side-by-side projection, we only produce a single texture for both eyes.
27416						if ( i === 0 ) {
27417
27418							renderer.setRenderTargetTextures(
27419								newRenderTarget,
27420								glSubImage.colorTexture,
27421								glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );
27422
27423							renderer.setRenderTarget( newRenderTarget );
27424
27425						}
27426
27427					}
27428
27429					let camera = cameras[ i ];
27430
27431					if ( camera === undefined ) {
27432
27433						camera = new PerspectiveCamera();
27434						camera.layers.enable( i );
27435						camera.viewport = new Vector4();
27436						cameras[ i ] = camera;
27437
27438					}
27439
27440					camera.matrix.fromArray( view.transform.matrix );
27441					camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27442					camera.projectionMatrix.fromArray( view.projectionMatrix );
27443					camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27444					camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
27445
27446					if ( i === 0 ) {
27447
27448						cameraXR.matrix.copy( camera.matrix );
27449						cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );
27450
27451					}
27452
27453					if ( cameraXRNeedsUpdate === true ) {
27454
27455						cameraXR.cameras.push( camera );
27456
27457					}
27458
27459				}
27460
27461			}
27462
27463			//
27464
27465			for ( let i = 0; i < controllers.length; i ++ ) {
27466
27467				const inputSource = controllerInputSources[ i ];
27468				const controller = controllers[ i ];
27469
27470				if ( inputSource !== null && controller !== undefined ) {
27471
27472					controller.update( inputSource, frame, customReferenceSpace || referenceSpace );
27473
27474				}
27475
27476			}
27477
27478			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
27479
27480			if ( frame.detectedPlanes ) {
27481
27482				scope.dispatchEvent( { type: 'planesdetected', data: frame } );
27483
27484			}
27485
27486			xrFrame = null;
27487
27488		}
27489
27490		const animation = new WebGLAnimation();
27491
27492		animation.setAnimationLoop( onAnimationFrame );
27493
27494		this.setAnimationLoop = function ( callback ) {
27495
27496			onAnimationFrameCallback = callback;
27497
27498		};
27499
27500		this.dispose = function () {};
27501
27502	}
27503
27504}
27505
27506function WebGLMaterials( renderer, properties ) {
27507
27508	function refreshTransformUniform( map, uniform ) {
27509
27510		if ( map.matrixAutoUpdate === true ) {
27511
27512			map.updateMatrix();
27513
27514		}
27515
27516		uniform.value.copy( map.matrix );
27517
27518	}
27519
27520	function refreshFogUniforms( uniforms, fog ) {
27521
27522		fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );
27523
27524		if ( fog.isFog ) {
27525
27526			uniforms.fogNear.value = fog.near;
27527			uniforms.fogFar.value = fog.far;
27528
27529		} else if ( fog.isFogExp2 ) {
27530
27531			uniforms.fogDensity.value = fog.density;
27532
27533		}
27534
27535	}
27536
27537	function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {
27538
27539		if ( material.isMeshBasicMaterial ) {
27540
27541			refreshUniformsCommon( uniforms, material );
27542
27543		} else if ( material.isMeshLambertMaterial ) {
27544
27545			refreshUniformsCommon( uniforms, material );
27546
27547		} else if ( material.isMeshToonMaterial ) {
27548
27549			refreshUniformsCommon( uniforms, material );
27550			refreshUniformsToon( uniforms, material );
27551
27552		} else if ( material.isMeshPhongMaterial ) {
27553
27554			refreshUniformsCommon( uniforms, material );
27555			refreshUniformsPhong( uniforms, material );
27556
27557		} else if ( material.isMeshStandardMaterial ) {
27558
27559			refreshUniformsCommon( uniforms, material );
27560			refreshUniformsStandard( uniforms, material );
27561
27562			if ( material.isMeshPhysicalMaterial ) {
27563
27564				refreshUniformsPhysical( uniforms, material, transmissionRenderTarget );
27565
27566			}
27567
27568		} else if ( material.isMeshMatcapMaterial ) {
27569
27570			refreshUniformsCommon( uniforms, material );
27571			refreshUniformsMatcap( uniforms, material );
27572
27573		} else if ( material.isMeshDepthMaterial ) {
27574
27575			refreshUniformsCommon( uniforms, material );
27576
27577		} else if ( material.isMeshDistanceMaterial ) {
27578
27579			refreshUniformsCommon( uniforms, material );
27580			refreshUniformsDistance( uniforms, material );
27581
27582		} else if ( material.isMeshNormalMaterial ) {
27583
27584			refreshUniformsCommon( uniforms, material );
27585
27586		} else if ( material.isLineBasicMaterial ) {
27587
27588			refreshUniformsLine( uniforms, material );
27589
27590			if ( material.isLineDashedMaterial ) {
27591
27592				refreshUniformsDash( uniforms, material );
27593
27594			}
27595
27596		} else if ( material.isPointsMaterial ) {
27597
27598			refreshUniformsPoints( uniforms, material, pixelRatio, height );
27599
27600		} else if ( material.isSpriteMaterial ) {
27601
27602			refreshUniformsSprites( uniforms, material );
27603
27604		} else if ( material.isShadowMaterial ) {
27605
27606			uniforms.color.value.copy( material.color );
27607			uniforms.opacity.value = material.opacity;
27608
27609		} else if ( material.isShaderMaterial ) {
27610
27611			material.uniformsNeedUpdate = false; // #15581
27612
27613		}
27614
27615	}
27616
27617	function refreshUniformsCommon( uniforms, material ) {
27618
27619		uniforms.opacity.value = material.opacity;
27620
27621		if ( material.color ) {
27622
27623			uniforms.diffuse.value.copy( material.color );
27624
27625		}
27626
27627		if ( material.emissive ) {
27628
27629			uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
27630
27631		}
27632
27633		if ( material.map ) {
27634
27635			uniforms.map.value = material.map;
27636
27637			refreshTransformUniform( material.map, uniforms.mapTransform );
27638
27639		}
27640
27641		if ( material.alphaMap ) {
27642
27643			uniforms.alphaMap.value = material.alphaMap;
27644
27645			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27646
27647		}
27648
27649		if ( material.bumpMap ) {
27650
27651			uniforms.bumpMap.value = material.bumpMap;
27652
27653			refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform );
27654
27655			uniforms.bumpScale.value = material.bumpScale;
27656
27657			if ( material.side === BackSide ) {
27658
27659				uniforms.bumpScale.value *= - 1;
27660
27661			}
27662
27663		}
27664
27665		if ( material.normalMap ) {
27666
27667			uniforms.normalMap.value = material.normalMap;
27668
27669			refreshTransformUniform( material.normalMap, uniforms.normalMapTransform );
27670
27671			uniforms.normalScale.value.copy( material.normalScale );
27672
27673			if ( material.side === BackSide ) {
27674
27675				uniforms.normalScale.value.negate();
27676
27677			}
27678
27679		}
27680
27681		if ( material.displacementMap ) {
27682
27683			uniforms.displacementMap.value = material.displacementMap;
27684
27685			refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform );
27686
27687			uniforms.displacementScale.value = material.displacementScale;
27688			uniforms.displacementBias.value = material.displacementBias;
27689
27690		}
27691
27692		if ( material.emissiveMap ) {
27693
27694			uniforms.emissiveMap.value = material.emissiveMap;
27695
27696			refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );
27697
27698		}
27699
27700		if ( material.specularMap ) {
27701
27702			uniforms.specularMap.value = material.specularMap;
27703
27704			refreshTransformUniform( material.specularMap, uniforms.specularMapTransform );
27705
27706		}
27707
27708		if ( material.alphaTest > 0 ) {
27709
27710			uniforms.alphaTest.value = material.alphaTest;
27711
27712		}
27713
27714		const envMap = properties.get( material ).envMap;
27715
27716		if ( envMap ) {
27717
27718			uniforms.envMap.value = envMap;
27719
27720			uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
27721
27722			uniforms.reflectivity.value = material.reflectivity;
27723			uniforms.ior.value = material.ior;
27724			uniforms.refractionRatio.value = material.refractionRatio;
27725
27726		}
27727
27728		if ( material.lightMap ) {
27729
27730			uniforms.lightMap.value = material.lightMap;
27731
27732			// artist-friendly light intensity scaling factor
27733			const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1;
27734
27735			uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor;
27736
27737			refreshTransformUniform( material.lightMap, uniforms.lightMapTransform );
27738
27739		}
27740
27741		if ( material.aoMap ) {
27742
27743			uniforms.aoMap.value = material.aoMap;
27744			uniforms.aoMapIntensity.value = material.aoMapIntensity;
27745
27746			refreshTransformUniform( material.aoMap, uniforms.aoMapTransform );
27747
27748		}
27749
27750	}
27751
27752	function refreshUniformsLine( uniforms, material ) {
27753
27754		uniforms.diffuse.value.copy( material.color );
27755		uniforms.opacity.value = material.opacity;
27756
27757		if ( material.map ) {
27758
27759			uniforms.map.value = material.map;
27760
27761			refreshTransformUniform( material.map, uniforms.mapTransform );
27762
27763		}
27764
27765	}
27766
27767	function refreshUniformsDash( uniforms, material ) {
27768
27769		uniforms.dashSize.value = material.dashSize;
27770		uniforms.totalSize.value = material.dashSize + material.gapSize;
27771		uniforms.scale.value = material.scale;
27772
27773	}
27774
27775	function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
27776
27777		uniforms.diffuse.value.copy( material.color );
27778		uniforms.opacity.value = material.opacity;
27779		uniforms.size.value = material.size * pixelRatio;
27780		uniforms.scale.value = height * 0.5;
27781
27782		if ( material.map ) {
27783
27784			uniforms.map.value = material.map;
27785
27786			refreshTransformUniform( material.map, uniforms.uvTransform );
27787
27788		}
27789
27790		if ( material.alphaMap ) {
27791
27792			uniforms.alphaMap.value = material.alphaMap;
27793
27794			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27795
27796		}
27797
27798		if ( material.alphaTest > 0 ) {
27799
27800			uniforms.alphaTest.value = material.alphaTest;
27801
27802		}
27803
27804	}
27805
27806	function refreshUniformsSprites( uniforms, material ) {
27807
27808		uniforms.diffuse.value.copy( material.color );
27809		uniforms.opacity.value = material.opacity;
27810		uniforms.rotation.value = material.rotation;
27811
27812		if ( material.map ) {
27813
27814			uniforms.map.value = material.map;
27815
27816			refreshTransformUniform( material.map, uniforms.mapTransform );
27817
27818		}
27819
27820		if ( material.alphaMap ) {
27821
27822			uniforms.alphaMap.value = material.alphaMap;
27823
27824			refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27825
27826		}
27827
27828		if ( material.alphaTest > 0 ) {
27829
27830			uniforms.alphaTest.value = material.alphaTest;
27831
27832		}
27833
27834	}
27835
27836	function refreshUniformsPhong( uniforms, material ) {
27837
27838		uniforms.specular.value.copy( material.specular );
27839		uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
27840
27841	}
27842
27843	function refreshUniformsToon( uniforms, material ) {
27844
27845		if ( material.gradientMap ) {
27846
27847			uniforms.gradientMap.value = material.gradientMap;
27848
27849		}
27850
27851	}
27852
27853	function refreshUniformsStandard( uniforms, material ) {
27854
27855		uniforms.metalness.value = material.metalness;
27856
27857		if ( material.metalnessMap ) {
27858
27859			uniforms.metalnessMap.value = material.metalnessMap;
27860
27861			refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );
27862
27863		}
27864
27865		uniforms.roughness.value = material.roughness;
27866
27867		if ( material.roughnessMap ) {
27868
27869			uniforms.roughnessMap.value = material.roughnessMap;
27870
27871			refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );
27872
27873		}
27874
27875		const envMap = properties.get( material ).envMap;
27876
27877		if ( envMap ) {
27878
27879			//uniforms.envMap.value = material.envMap; // part of uniforms common
27880			uniforms.envMapIntensity.value = material.envMapIntensity;
27881
27882		}
27883
27884	}
27885
27886	function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {
27887
27888		uniforms.ior.value = material.ior; // also part of uniforms common
27889
27890		if ( material.sheen > 0 ) {
27891
27892			uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );
27893
27894			uniforms.sheenRoughness.value = material.sheenRoughness;
27895
27896			if ( material.sheenColorMap ) {
27897
27898				uniforms.sheenColorMap.value = material.sheenColorMap;
27899
27900				refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );
27901
27902			}
27903
27904			if ( material.sheenRoughnessMap ) {
27905
27906				uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;
27907
27908				refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );
27909
27910			}
27911
27912		}
27913
27914		if ( material.clearcoat > 0 ) {
27915
27916			uniforms.clearcoat.value = material.clearcoat;
27917			uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
27918
27919			if ( material.clearcoatMap ) {
27920
27921				uniforms.clearcoatMap.value = material.clearcoatMap;
27922
27923				refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );
27924
27925			}
27926
27927			if ( material.clearcoatRoughnessMap ) {
27928
27929				uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
27930
27931				refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );
27932
27933			}
27934
27935			if ( material.clearcoatNormalMap ) {
27936
27937				uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
27938
27939				refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );
27940
27941				uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
27942
27943				if ( material.side === BackSide ) {
27944
27945					uniforms.clearcoatNormalScale.value.negate();
27946
27947				}
27948
27949			}
27950
27951		}
27952
27953		if ( material.iridescence > 0 ) {
27954
27955			uniforms.iridescence.value = material.iridescence;
27956			uniforms.iridescenceIOR.value = material.iridescenceIOR;
27957			uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];
27958			uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];
27959
27960			if ( material.iridescenceMap ) {
27961
27962				uniforms.iridescenceMap.value = material.iridescenceMap;
27963
27964				refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );
27965
27966			}
27967
27968			if ( material.iridescenceThicknessMap ) {
27969
27970				uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;
27971
27972				refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );
27973
27974			}
27975
27976		}
27977
27978		if ( material.transmission > 0 ) {
27979
27980			uniforms.transmission.value = material.transmission;
27981			uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
27982			uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );
27983
27984			if ( material.transmissionMap ) {
27985
27986				uniforms.transmissionMap.value = material.transmissionMap;
27987
27988				refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );
27989
27990			}
27991
27992			uniforms.thickness.value = material.thickness;
27993
27994			if ( material.thicknessMap ) {
27995
27996				uniforms.thicknessMap.value = material.thicknessMap;
27997
27998				refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );
27999
28000			}
28001
28002			uniforms.attenuationDistance.value = material.attenuationDistance;
28003			uniforms.attenuationColor.value.copy( material.attenuationColor );
28004
28005		}
28006
28007		if ( material.anisotropy > 0 ) {
28008
28009			uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );
28010
28011			if ( material.anisotropyMap ) {
28012
28013				uniforms.anisotropyMap.value = material.anisotropyMap;
28014
28015				refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );
28016
28017			}
28018
28019		}
28020
28021		uniforms.specularIntensity.value = material.specularIntensity;
28022		uniforms.specularColor.value.copy( material.specularColor );
28023
28024		if ( material.specularColorMap ) {
28025
28026			uniforms.specularColorMap.value = material.specularColorMap;
28027
28028			refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );
28029
28030		}
28031
28032		if ( material.specularIntensityMap ) {
28033
28034			uniforms.specularIntensityMap.value = material.specularIntensityMap;
28035
28036			refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );
28037
28038		}
28039
28040	}
28041
28042	function refreshUniformsMatcap( uniforms, material ) {
28043
28044		if ( material.matcap ) {
28045
28046			uniforms.matcap.value = material.matcap;
28047
28048		}
28049
28050	}
28051
28052	function refreshUniformsDistance( uniforms, material ) {
28053
28054		const light = properties.get( material ).light;
28055
28056		uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );
28057		uniforms.nearDistance.value = light.shadow.camera.near;
28058		uniforms.farDistance.value = light.shadow.camera.far;
28059
28060	}
28061
28062	return {
28063		refreshFogUniforms: refreshFogUniforms,
28064		refreshMaterialUniforms: refreshMaterialUniforms
28065	};
28066
28067}
28068
28069function WebGLUniformsGroups( gl, info, capabilities, state ) {
28070
28071	let buffers = {};
28072	let updateList = {};
28073	let allocatedBindingPoints = [];
28074
28075	const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program
28076
28077	function bind( uniformsGroup, program ) {
28078
28079		const webglProgram = program.program;
28080		state.uniformBlockBinding( uniformsGroup, webglProgram );
28081
28082	}
28083
28084	function update( uniformsGroup, program ) {
28085
28086		let buffer = buffers[ uniformsGroup.id ];
28087
28088		if ( buffer === undefined ) {
28089
28090			prepareUniformsGroup( uniformsGroup );
28091
28092			buffer = createBuffer( uniformsGroup );
28093			buffers[ uniformsGroup.id ] = buffer;
28094
28095			uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );
28096
28097		}
28098
28099		// ensure to update the binding points/block indices mapping for this program
28100
28101		const webglProgram = program.program;
28102		state.updateUBOMapping( uniformsGroup, webglProgram );
28103
28104		// update UBO once per frame
28105
28106		const frame = info.render.frame;
28107
28108		if ( updateList[ uniformsGroup.id ] !== frame ) {
28109
28110			updateBufferData( uniformsGroup );
28111
28112			updateList[ uniformsGroup.id ] = frame;
28113
28114		}
28115
28116	}
28117
28118	function createBuffer( uniformsGroup ) {
28119
28120		// the setup of an UBO is independent of a particular shader program but global
28121
28122		const bindingPointIndex = allocateBindingPointIndex();
28123		uniformsGroup.__bindingPointIndex = bindingPointIndex;
28124
28125		const buffer = gl.createBuffer();
28126		const size = uniformsGroup.__size;
28127		const usage = uniformsGroup.usage;
28128
28129		gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28130		gl.bufferData( gl.UNIFORM_BUFFER, size, usage );
28131		gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28132		gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer );
28133
28134		return buffer;
28135
28136	}
28137
28138	function allocateBindingPointIndex() {
28139
28140		for ( let i = 0; i < maxBindingPoints; i ++ ) {
28141
28142			if ( allocatedBindingPoints.indexOf( i ) === - 1 ) {
28143
28144				allocatedBindingPoints.push( i );
28145				return i;
28146
28147			}
28148
28149		}
28150
28151		console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );
28152
28153		return 0;
28154
28155	}
28156
28157	function updateBufferData( uniformsGroup ) {
28158
28159		const buffer = buffers[ uniformsGroup.id ];
28160		const uniforms = uniformsGroup.uniforms;
28161		const cache = uniformsGroup.__cache;
28162
28163		gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28164
28165		for ( let i = 0, il = uniforms.length; i < il; i ++ ) {
28166
28167			const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28168
28169			for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28170
28171				const uniform = uniformArray[ j ];
28172
28173				if ( hasUniformChanged( uniform, i, j, cache ) === true ) {
28174
28175					const offset = uniform.__offset;
28176
28177					const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28178
28179					let arrayOffset = 0;
28180
28181					for ( let k = 0; k < values.length; k ++ ) {
28182
28183						const value = values[ k ];
28184
28185						const info = getUniformSize( value );
28186
28187						// TODO add integer and struct support
28188						if ( typeof value === 'number' || typeof value === 'boolean' ) {
28189
28190							uniform.__data[ 0 ] = value;
28191							gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );
28192
28193						} else if ( value.isMatrix3 ) {
28194
28195							// manually converting 3x3 to 3x4
28196
28197							uniform.__data[ 0 ] = value.elements[ 0 ];
28198							uniform.__data[ 1 ] = value.elements[ 1 ];
28199							uniform.__data[ 2 ] = value.elements[ 2 ];
28200							uniform.__data[ 3 ] = 0;
28201							uniform.__data[ 4 ] = value.elements[ 3 ];
28202							uniform.__data[ 5 ] = value.elements[ 4 ];
28203							uniform.__data[ 6 ] = value.elements[ 5 ];
28204							uniform.__data[ 7 ] = 0;
28205							uniform.__data[ 8 ] = value.elements[ 6 ];
28206							uniform.__data[ 9 ] = value.elements[ 7 ];
28207							uniform.__data[ 10 ] = value.elements[ 8 ];
28208							uniform.__data[ 11 ] = 0;
28209
28210						} else {
28211
28212							value.toArray( uniform.__data, arrayOffset );
28213
28214							arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;
28215
28216						}
28217
28218					}
28219
28220					gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
28221
28222				}
28223
28224			}
28225
28226		}
28227
28228		gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28229
28230	}
28231
28232	function hasUniformChanged( uniform, index, indexArray, cache ) {
28233
28234		const value = uniform.value;
28235		const indexString = index + '_' + indexArray;
28236
28237		if ( cache[ indexString ] === undefined ) {
28238
28239			// cache entry does not exist so far
28240
28241			if ( typeof value === 'number' || typeof value === 'boolean' ) {
28242
28243				cache[ indexString ] = value;
28244
28245			} else {
28246
28247				cache[ indexString ] = value.clone();
28248
28249			}
28250
28251			return true;
28252
28253		} else {
28254
28255			const cachedObject = cache[ indexString ];
28256
28257			// compare current value with cached entry
28258
28259			if ( typeof value === 'number' || typeof value === 'boolean' ) {
28260
28261				if ( cachedObject !== value ) {
28262
28263					cache[ indexString ] = value;
28264					return true;
28265
28266				}
28267
28268			} else {
28269
28270				if ( cachedObject.equals( value ) === false ) {
28271
28272					cachedObject.copy( value );
28273					return true;
28274
28275				}
28276
28277			}
28278
28279		}
28280
28281		return false;
28282
28283	}
28284
28285	function prepareUniformsGroup( uniformsGroup ) {
28286
28287		// determine total buffer size according to the STD140 layout
28288		// Hint: STD140 is the only supported layout in WebGL 2
28289
28290		const uniforms = uniformsGroup.uniforms;
28291
28292		let offset = 0; // global buffer offset in bytes
28293		const chunkSize = 16; // size of a chunk in bytes
28294
28295		for ( let i = 0, l = uniforms.length; i < l; i ++ ) {
28296
28297			const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28298
28299			for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28300
28301				const uniform = uniformArray[ j ];
28302
28303				const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28304
28305				for ( let k = 0, kl = values.length; k < kl; k ++ ) {
28306
28307					const value = values[ k ];
28308
28309					const info = getUniformSize( value );
28310
28311					// Calculate the chunk offset
28312					const chunkOffsetUniform = offset % chunkSize;
28313
28314					// Check for chunk overflow
28315					if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) {
28316
28317						// Add padding and adjust offset
28318						offset += ( chunkSize - chunkOffsetUniform );
28319
28320					}
28321
28322					// the following two properties will be used for partial buffer updates
28323
28324					uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
28325					uniform.__offset = offset;
28326
28327
28328					// Update the global offset
28329					offset += info.storage;
28330
28331
28332				}
28333
28334			}
28335
28336		}
28337
28338		// ensure correct final padding
28339
28340		const chunkOffset = offset % chunkSize;
28341
28342		if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );
28343
28344		//
28345
28346		uniformsGroup.__size = offset;
28347		uniformsGroup.__cache = {};
28348
28349		return this;
28350
28351	}
28352
28353	function getUniformSize( value ) {
28354
28355		const info = {
28356			boundary: 0, // bytes
28357			storage: 0 // bytes
28358		};
28359
28360		// determine sizes according to STD140
28361
28362		if ( typeof value === 'number' || typeof value === 'boolean' ) {
28363
28364			// float/int/bool
28365
28366			info.boundary = 4;
28367			info.storage = 4;
28368
28369		} else if ( value.isVector2 ) {
28370
28371			// vec2
28372
28373			info.boundary = 8;
28374			info.storage = 8;
28375
28376		} else if ( value.isVector3 || value.isColor ) {
28377
28378			// vec3
28379
28380			info.boundary = 16;
28381			info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes
28382
28383		} else if ( value.isVector4 ) {
28384
28385			// vec4
28386
28387			info.boundary = 16;
28388			info.storage = 16;
28389
28390		} else if ( value.isMatrix3 ) {
28391
28392			// mat3 (in STD140 a 3x3 matrix is represented as 3x4)
28393
28394			info.boundary = 48;
28395			info.storage = 48;
28396
28397		} else if ( value.isMatrix4 ) {
28398
28399			// mat4
28400
28401			info.boundary = 64;
28402			info.storage = 64;
28403
28404		} else if ( value.isTexture ) {
28405
28406			console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' );
28407
28408		} else {
28409
28410			console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value );
28411
28412		}
28413
28414		return info;
28415
28416	}
28417
28418	function onUniformsGroupsDispose( event ) {
28419
28420		const uniformsGroup = event.target;
28421
28422		uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose );
28423
28424		const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );
28425		allocatedBindingPoints.splice( index, 1 );
28426
28427		gl.deleteBuffer( buffers[ uniformsGroup.id ] );
28428
28429		delete buffers[ uniformsGroup.id ];
28430		delete updateList[ uniformsGroup.id ];
28431
28432	}
28433
28434	function dispose() {
28435
28436		for ( const id in buffers ) {
28437
28438			gl.deleteBuffer( buffers[ id ] );
28439
28440		}
28441
28442		allocatedBindingPoints = [];
28443		buffers = {};
28444		updateList = {};
28445
28446	}
28447
28448	return {
28449
28450		bind: bind,
28451		update: update,
28452
28453		dispose: dispose
28454
28455	};
28456
28457}
28458
28459class WebGLRenderer {
28460
28461	constructor( parameters = {} ) {
28462
28463		const {
28464			canvas = createCanvasElement(),
28465			context = null,
28466			depth = true,
28467			stencil = true,
28468			alpha = false,
28469			antialias = false,
28470			premultipliedAlpha = true,
28471			preserveDrawingBuffer = false,
28472			powerPreference = 'default',
28473			failIfMajorPerformanceCaveat = false,
28474		} = parameters;
28475
28476		this.isWebGLRenderer = true;
28477
28478		let _alpha;
28479
28480		if ( context !== null ) {
28481
28482			_alpha = context.getContextAttributes().alpha;
28483
28484		} else {
28485
28486			_alpha = alpha;
28487
28488		}
28489
28490		const uintClearColor = new Uint32Array( 4 );
28491		const intClearColor = new Int32Array( 4 );
28492
28493		let currentRenderList = null;
28494		let currentRenderState = null;
28495
28496		// render() can be called from within a callback triggered by another render.
28497		// We track this so that the nested render call gets its list and state isolated from the parent render call.
28498
28499		const renderListStack = [];
28500		const renderStateStack = [];
28501
28502		// public properties
28503
28504		this.domElement = canvas;
28505
28506		// Debug configuration container
28507		this.debug = {
28508
28509			/**
28510			 * Enables error checking and reporting when shader programs are being compiled
28511			 * @type {boolean}
28512			 */
28513			checkShaderErrors: true,
28514			/**
28515			 * Callback for custom error reporting.
28516			 * @type {?Function}
28517			 */
28518			onShaderError: null
28519		};
28520
28521		// clearing
28522
28523		this.autoClear = true;
28524		this.autoClearColor = true;
28525		this.autoClearDepth = true;
28526		this.autoClearStencil = true;
28527
28528		// scene graph
28529
28530		this.sortObjects = true;
28531
28532		// user-defined clipping
28533
28534		this.clippingPlanes = [];
28535		this.localClippingEnabled = false;
28536
28537		// physically based shading
28538
28539		this._outputColorSpace = SRGBColorSpace;
28540
28541		// physical lights
28542
28543		this._useLegacyLights = false;
28544
28545		// tone mapping
28546
28547		this.toneMapping = NoToneMapping;
28548		this.toneMappingExposure = 1.0;
28549
28550		// internal properties
28551
28552		const _this = this;
28553
28554		let _isContextLost = false;
28555
28556		// internal state cache
28557
28558		let _currentActiveCubeFace = 0;
28559		let _currentActiveMipmapLevel = 0;
28560		let _currentRenderTarget = null;
28561		let _currentMaterialId = - 
vendor: 7,816 bytes, lines 28561-28887
285611;
28562
28563		let _currentCamera = null;
28564
28565		const _currentViewport = new Vector4();
28566		const _currentScissor = new Vector4();
28567		let _currentScissorTest = null;
28568
28569		const _currentClearColor = new Color( 0x000000 );
28570		let _currentClearAlpha = 0;
28571
28572		//
28573
28574		let _width = canvas.width;
28575		let _height = canvas.height;
28576
28577		let _pixelRatio = 1;
28578		let _opaqueSort = null;
28579		let _transparentSort = null;
28580
28581		const _viewport = new Vector4( 0, 0, _width, _height );
28582		const _scissor = new Vector4( 0, 0, _width, _height );
28583		let _scissorTest = false;
28584
28585		// frustum
28586
28587		const _frustum = new Frustum();
28588
28589		// clipping
28590
28591		let _clippingEnabled = false;
28592		let _localClippingEnabled = false;
28593
28594		// transmission
28595
28596		let _transmissionRenderTarget = null;
28597
28598		// camera matrices cache
28599
28600		const _projScreenMatrix = new Matrix4();
28601
28602		const _vector2 = new Vector2();
28603		const _vector3 = new Vector3();
28604
28605		const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
28606
28607		function getTargetPixelRatio() {
28608
28609			return _currentRenderTarget === null ? _pixelRatio : 1;
28610
28611		}
28612
28613		// initialize
28614
28615		let _gl = context;
28616
28617		function getContext( contextNames, contextAttributes ) {
28618
28619			for ( let i = 0; i < contextNames.length; i ++ ) {
28620
28621				const contextName = contextNames[ i ];
28622				const context = canvas.getContext( contextName, contextAttributes );
28623				if ( context !== null ) return context;
28624
28625			}
28626
28627			return null;
28628
28629		}
28630
28631		try {
28632
28633			const contextAttributes = {
28634				alpha: true,
28635				depth,
28636				stencil,
28637				antialias,
28638				premultipliedAlpha,
28639				preserveDrawingBuffer,
28640				powerPreference,
28641				failIfMajorPerformanceCaveat,
28642			};
28643
28644			// OffscreenCanvas does not have setAttribute, see #22811
28645			if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );
28646
28647			// event listeners must be registered before WebGL context is created, see #12753
28648			canvas.addEventListener( 'webglcontextlost', onContextLost, false );
28649			canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
28650			canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );
28651
28652			if ( _gl === null ) {
28653
28654				const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
28655
28656				if ( _this.isWebGL1Renderer === true ) {
28657
28658					contextNames.shift();
28659
28660				}
28661
28662				_gl = getContext( contextNames, contextAttributes );
28663
28664				if ( _gl === null ) {
28665
28666					if ( getContext( contextNames ) ) {
28667
28668						throw new Error( 'Error creating WebGL context with your selected attributes.' );
28669
28670					} else {
28671
28672						throw new Error( 'Error creating WebGL context.' );
28673
28674					}
28675
28676				}
28677
28678			}
28679
28680			if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153
28681
28682				console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' );
28683
28684			}
28685
28686			// Some experimental-webgl implementations do not have getShaderPrecisionFormat
28687
28688			if ( _gl.getShaderPrecisionFormat === undefined ) {
28689
28690				_gl.getShaderPrecisionFormat = function () {
28691
28692					return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
28693
28694				};
28695
28696			}
28697
28698		} catch ( error ) {
28699
28700			console.error( 'THREE.WebGLRenderer: ' + error.message );
28701			throw error;
28702
28703		}
28704
28705		let extensions, capabilities, state, info;
28706		let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
28707		let programCache, materials, renderLists, renderStates, clipping, shadowMap;
28708
28709		let background, morphtargets, bufferRenderer, indexedBufferRenderer;
28710
28711		let utils, bindingStates, uniformsGroups;
28712
28713		function initGLContext() {
28714
28715			extensions = new WebGLExtensions( _gl );
28716
28717			capabilities = new WebGLCapabilities( _gl, extensions, parameters );
28718
28719			extensions.init( capabilities );
28720
28721			utils = new WebGLUtils( _gl, extensions, capabilities );
28722
28723			state = new WebGLState( _gl, extensions, capabilities );
28724
28725			info = new WebGLInfo( _gl );
28726			properties = new WebGLProperties();
28727			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
28728			cubemaps = new WebGLCubeMaps( _this );
28729			cubeuvmaps = new WebGLCubeUVMaps( _this );
28730			attributes = new WebGLAttributes( _gl, capabilities );
28731			bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
28732			geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
28733			objects = new WebGLObjects( _gl, geometries, attributes, info );
28734			morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
28735			clipping = new WebGLClipping( properties );
28736			programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );
28737			materials = new WebGLMaterials( _this, properties );
28738			renderLists = new WebGLRenderLists();
28739			renderStates = new WebGLRenderStates( extensions, capabilities );
28740			background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
28741			shadowMap = new WebGLShadowMap( _this, objects, capabilities );
28742			uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
28743
28744			bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
28745			indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
28746
28747			info.programs = programCache.programs;
28748
28749			_this.capabilities = capabilities;
28750			_this.extensions = extensions;
28751			_this.properties = properties;
28752			_this.renderLists = renderLists;
28753			_this.shadowMap = shadowMap;
28754			_this.state = state;
28755			_this.info = info;
28756
28757		}
28758
28759		initGLContext();
28760
28761		// xr
28762
28763		const xr = new WebXRManager( _this, _gl );
28764
28765		this.xr = xr;
28766
28767		// API
28768
28769		this.getContext = function () {
28770
28771			return _gl;
28772
28773		};
28774
28775		this.getContextAttributes = function () {
28776
28777			return _gl.getContextAttributes();
28778
28779		};
28780
28781		this.forceContextLoss = function () {
28782
28783			const extension = extensions.get( 'WEBGL_lose_context' );
28784			if ( extension ) extension.loseContext();
28785
28786		};
28787
28788		this.forceContextRestore = function () {
28789
28790			const extension = extensions.get( 'WEBGL_lose_context' );
28791			if ( extension ) extension.restoreContext();
28792
28793		};
28794
28795		this.getPixelRatio = function () {
28796
28797			return _pixelRatio;
28798
28799		};
28800
28801		this.setPixelRatio = function ( value ) {
28802
28803			if ( value === undefined ) return;
28804
28805			_pixelRatio = value;
28806
28807			this.setSize( _width, _height, false );
28808
28809		};
28810
28811		this.getSize = function ( target ) {
28812
28813			return target.set( _width, _height );
28814
28815		};
28816
28817		this.setSize = function ( width, height, updateStyle = true ) {
28818
28819			if ( xr.isPresenting ) {
28820
28821				console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
28822				return;
28823
28824			}
28825
28826			_width = width;
28827			_height = height;
28828
28829			canvas.width = Math.floor( width * _pixelRatio );
28830			canvas.height = Math.floor( height * _pixelRatio );
28831
28832			if ( updateStyle === true ) {
28833
28834				canvas.style.width = width + 'px';
28835				canvas.style.height = height + 'px';
28836
28837			}
28838
28839			this.setViewport( 0, 0, width, height );
28840
28841		};
28842
28843		this.getDrawingBufferSize = function ( target ) {
28844
28845			return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
28846
28847		};
28848
28849		this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
28850
28851			_width = width;
28852			_height = height;
28853
28854			_pixelRatio = pixelRatio;
28855
28856			canvas.width = Math.floor( width * pixelRatio );
28857			canvas.height = Math.floor( height * pixelRatio );
28858
28859			this.setViewport( 0, 0, width, height );
28860
28861		};
28862
28863		this.getCurrentViewport = function ( target ) {
28864
28865			return target.copy( _currentViewport );
28866
28867		};
28868
28869		this.getViewport = function ( target ) {
28870
28871			return target.copy( _viewport );
28872
28873		};
28874
28875		this.setViewport = function ( x, y, width, height ) {
28876
28877			if ( x.isVector4 ) {
28878
28879				_viewport.set( x.x, x.y, x.z, x.w );
28880
28881			} else {
28882
28883				_viewport.set( x, y, width, height );
28884
28885			}
28886
28887			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).
28887floor() );
28888
28889		};
28890
28891		this.getScissor = function ( target ) {
28892
28893			return target.copy( _scissor );
28894
28895		};
28896
28897		this.setScissor = function ( x, y, width, height ) {
28898
28899			if ( x.isVector4 ) {
28900
28901				_scissor.set( x.x, x.y, x.z, x.w );
28902
28903			} else {
28904
28905				_scissor.set( x, y, width, height );
28906
28907			}
28908
28909			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor
vendor: 14,801 bytes, lines 28909-29605
28909() );
28910
28911		};
28912
28913		this.getScissorTest = function () {
28914
28915			return _scissorTest;
28916
28917		};
28918
28919		this.setScissorTest = function ( boolean ) {
28920
28921			state.setScissorTest( _scissorTest = boolean );
28922
28923		};
28924
28925		this.setOpaqueSort = function ( method ) {
28926
28927			_opaqueSort = method;
28928
28929		};
28930
28931		this.setTransparentSort = function ( method ) {
28932
28933			_transparentSort = method;
28934
28935		};
28936
28937		// Clearing
28938
28939		this.getClearColor = function ( target ) {
28940
28941			return target.copy( background.getClearColor() );
28942
28943		};
28944
28945		this.setClearColor = function () {
28946
28947			background.setClearColor.apply( background, arguments );
28948
28949		};
28950
28951		this.getClearAlpha = function () {
28952
28953			return background.getClearAlpha();
28954
28955		};
28956
28957		this.setClearAlpha = function () {
28958
28959			background.setClearAlpha.apply( background, arguments );
28960
28961		};
28962
28963		this.clear = function ( color = true, depth = true, stencil = true ) {
28964
28965			let bits = 0;
28966
28967			if ( color ) {
28968
28969				// check if we're trying to clear an integer target
28970				let isIntegerFormat = false;
28971				if ( _currentRenderTarget !== null ) {
28972
28973					const targetFormat = _currentRenderTarget.texture.format;
28974					isIntegerFormat = targetFormat === RGBAIntegerFormat ||
28975						targetFormat === RGIntegerFormat ||
28976						targetFormat === RedIntegerFormat;
28977
28978				}
28979
28980				// use the appropriate clear functions to clear the target if it's a signed
28981				// or unsigned integer target
28982				if ( isIntegerFormat ) {
28983
28984					const targetType = _currentRenderTarget.texture.type;
28985					const isUnsignedType = targetType === UnsignedByteType ||
28986						targetType === UnsignedIntType ||
28987						targetType === UnsignedShortType ||
28988						targetType === UnsignedInt248Type ||
28989						targetType === UnsignedShort4444Type ||
28990						targetType === UnsignedShort5551Type;
28991
28992					const clearColor = background.getClearColor();
28993					const a = background.getClearAlpha();
28994					const r = clearColor.r;
28995					const g = clearColor.g;
28996					const b = clearColor.b;
28997
28998					if ( isUnsignedType ) {
28999
29000						uintClearColor[ 0 ] = r;
29001						uintClearColor[ 1 ] = g;
29002						uintClearColor[ 2 ] = b;
29003						uintClearColor[ 3 ] = a;
29004						_gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );
29005
29006					} else {
29007
29008						intClearColor[ 0 ] = r;
29009						intClearColor[ 1 ] = g;
29010						intClearColor[ 2 ] = b;
29011						intClearColor[ 3 ] = a;
29012						_gl.clearBufferiv( _gl.COLOR, 0, intClearColor );
29013
29014					}
29015
29016				} else {
29017
29018					bits |= _gl.COLOR_BUFFER_BIT;
29019
29020				}
29021
29022			}
29023
29024			if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
29025			if ( stencil ) {
29026
29027				bits |= _gl.STENCIL_BUFFER_BIT;
29028				this.state.buffers.stencil.setMask( 0xffffffff );
29029
29030			}
29031
29032			_gl.clear( bits );
29033
29034		};
29035
29036		this.clearColor = function () {
29037
29038			this.clear( true, false, false );
29039
29040		};
29041
29042		this.clearDepth = function () {
29043
29044			this.clear( false, true, false );
29045
29046		};
29047
29048		this.clearStencil = function () {
29049
29050			this.clear( false, false, true );
29051
29052		};
29053
29054		//
29055
29056		this.dispose = function () {
29057
29058			canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
29059			canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
29060			canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );
29061
29062			renderLists.dispose();
29063			renderStates.dispose();
29064			properties.dispose();
29065			cubemaps.dispose();
29066			cubeuvmaps.dispose();
29067			objects.dispose();
29068			bindingStates.dispose();
29069			uniformsGroups.dispose();
29070			programCache.dispose();
29071
29072			xr.dispose();
29073
29074			xr.removeEventListener( 'sessionstart', onXRSessionStart );
29075			xr.removeEventListener( 'sessionend', onXRSessionEnd );
29076
29077			if ( _transmissionRenderTarget ) {
29078
29079				_transmissionRenderTarget.dispose();
29080				_transmissionRenderTarget = null;
29081
29082			}
29083
29084			animation.stop();
29085
29086		};
29087
29088		// Events
29089
29090		function onContextLost( event ) {
29091
29092			event.preventDefault();
29093
29094			console.log( 'THREE.WebGLRenderer: Context Lost.' );
29095
29096			_isContextLost = true;
29097
29098		}
29099
29100		function onContextRestore( /* event */ ) {
29101
29102			console.log( 'THREE.WebGLRenderer: Context Restored.' );
29103
29104			_isContextLost = false;
29105
29106			const infoAutoReset = info.autoReset;
29107			const shadowMapEnabled = shadowMap.enabled;
29108			const shadowMapAutoUpdate = shadowMap.autoUpdate;
29109			const shadowMapNeedsUpdate = shadowMap.needsUpdate;
29110			const shadowMapType = shadowMap.type;
29111
29112			initGLContext();
29113
29114			info.autoReset = infoAutoReset;
29115			shadowMap.enabled = shadowMapEnabled;
29116			shadowMap.autoUpdate = shadowMapAutoUpdate;
29117			shadowMap.needsUpdate = shadowMapNeedsUpdate;
29118			shadowMap.type = shadowMapType;
29119
29120		}
29121
29122		function onContextCreationError( event ) {
29123
29124			console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );
29125
29126		}
29127
29128		function onMaterialDispose( event ) {
29129
29130			const material = event.target;
29131
29132			material.removeEventListener( 'dispose', onMaterialDispose );
29133
29134			deallocateMaterial( material );
29135
29136		}
29137
29138		// Buffer deallocation
29139
29140		function deallocateMaterial( material ) {
29141
29142			releaseMaterialProgramReferences( material );
29143
29144			properties.remove( material );
29145
29146		}
29147
29148
29149		function releaseMaterialProgramReferences( material ) {
29150
29151			const programs = properties.get( material ).programs;
29152
29153			if ( programs !== undefined ) {
29154
29155				programs.forEach( function ( program ) {
29156
29157					programCache.releaseProgram( program );
29158
29159				} );
29160
29161				if ( material.isShaderMaterial ) {
29162
29163					programCache.releaseShaderCache( material );
29164
29165				}
29166
29167			}
29168
29169		}
29170
29171		// Buffer rendering
29172
29173		this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
29174
29175			if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
29176
29177			const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
29178
29179			const program = setProgram( camera, scene, geometry, material, object );
29180
29181			state.setMaterial( material, frontFaceCW );
29182
29183			//
29184
29185			let index = geometry.index;
29186			let rangeFactor = 1;
29187
29188			if ( material.wireframe === true ) {
29189
29190				index = geometries.getWireframeAttribute( geometry );
29191
29192				if ( index === undefined ) return;
29193
29194				rangeFactor = 2;
29195
29196			}
29197
29198			//
29199
29200			const drawRange = geometry.drawRange;
29201			const position = geometry.attributes.position;
29202
29203			let drawStart = drawRange.start * rangeFactor;
29204			let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;
29205
29206			if ( group !== null ) {
29207
29208				drawStart = Math.max( drawStart, group.start * rangeFactor );
29209				drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );
29210
29211			}
29212
29213			if ( index !== null ) {
29214
29215				drawStart = Math.max( drawStart, 0 );
29216				drawEnd = Math.min( drawEnd, index.count );
29217
29218			} else if ( position !== undefined && position !== null ) {
29219
29220				drawStart = Math.max( drawStart, 0 );
29221				drawEnd = Math.min( drawEnd, position.count );
29222
29223			}
29224
29225			const drawCount = drawEnd - drawStart;
29226
29227			if ( drawCount < 0 || drawCount === Infinity ) return;
29228
29229			//
29230
29231			bindingStates.setup( object, material, program, geometry, index );
29232
29233			let attribute;
29234			let renderer = bufferRenderer;
29235
29236			if ( index !== null ) {
29237
29238				attribute = attributes.get( index );
29239
29240				renderer = indexedBufferRenderer;
29241				renderer.setIndex( attribute );
29242
29243			}
29244
29245			//
29246
29247			if ( object.isMesh ) {
29248
29249				if ( material.wireframe === true ) {
29250
29251					state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
29252					renderer.setMode( _gl.LINES );
29253
29254				} else {
29255
29256					renderer.setMode( _gl.TRIANGLES );
29257
29258				}
29259
29260			} else if ( object.isLine ) {
29261
29262				let lineWidth = material.linewidth;
29263
29264				if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
29265
29266				state.setLineWidth( lineWidth * getTargetPixelRatio() );
29267
29268				if ( object.isLineSegments ) {
29269
29270					renderer.setMode( _gl.LINES );
29271
29272				} else if ( object.isLineLoop ) {
29273
29274					renderer.setMode( _gl.LINE_LOOP );
29275
29276				} else {
29277
29278					renderer.setMode( _gl.LINE_STRIP );
29279
29280				}
29281
29282			} else if ( object.isPoints ) {
29283
29284				renderer.setMode( _gl.POINTS );
29285
29286			} else if ( object.isSprite ) {
29287
29288				renderer.setMode( _gl.TRIANGLES );
29289
29290			}
29291
29292			if ( object.isBatchedMesh ) {
29293
29294				renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
29295
29296			} else if ( object.isInstancedMesh ) {
29297
29298				renderer.renderInstances( drawStart, drawCount, object.count );
29299
29300			} else if ( geometry.isInstancedBufferGeometry ) {
29301
29302				const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;
29303				const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );
29304
29305				renderer.renderInstances( drawStart, drawCount, instanceCount );
29306
29307			} else {
29308
29309				renderer.render( drawStart, drawCount );
29310
29311			}
29312
29313		};
29314
29315		// Compile
29316
29317		function prepareMaterial( material, scene, object ) {
29318
29319			if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29320
29321				material.side = BackSide;
29322				material.needsUpdate = true;
29323				getProgram( material, scene, object );
29324
29325				material.side = FrontSide;
29326				material.needsUpdate = true;
29327				getProgram( material, scene, object );
29328
29329				material.side = DoubleSide;
29330
29331			} else {
29332
29333				getProgram( material, scene, object );
29334
29335			}
29336
29337		}
29338
29339		this.compile = function ( scene, camera, targetScene = null ) {
29340
29341			if ( targetScene === null ) targetScene = scene;
29342
29343			currentRenderState = renderStates.get( targetScene );
29344			currentRenderState.init();
29345
29346			renderStateStack.push( currentRenderState );
29347
29348			// gather lights from both the target scene and the new object that will be added to the scene.
29349
29350			targetScene.traverseVisible( function ( object ) {
29351
29352				if ( object.isLight && object.layers.test( camera.layers ) ) {
29353
29354					currentRenderState.pushLight( object );
29355
29356					if ( object.castShadow ) {
29357
29358						currentRenderState.pushShadow( object );
29359
29360					}
29361
29362				}
29363
29364			} );
29365
29366			if ( scene !== targetScene ) {
29367
29368				scene.traverseVisible( function ( object ) {
29369
29370					if ( object.isLight && object.layers.test( camera.layers ) ) {
29371
29372						currentRenderState.pushLight( object );
29373
29374						if ( object.castShadow ) {
29375
29376							currentRenderState.pushShadow( object );
29377
29378						}
29379
29380					}
29381
29382				} );
29383
29384			}
29385
29386			currentRenderState.setupLights( _this._useLegacyLights );
29387
29388			// Only initialize materials in the new scene, not the targetScene.
29389
29390			const materials = new Set();
29391
29392			scene.traverse( function ( object ) {
29393
29394				const material = object.material;
29395
29396				if ( material ) {
29397
29398					if ( Array.isArray( material ) ) {
29399
29400						for ( let i = 0; i < material.length; i ++ ) {
29401
29402							const material2 = material[ i ];
29403
29404							prepareMaterial( material2, targetScene, object );
29405							materials.add( material2 );
29406
29407						}
29408
29409					} else {
29410
29411						prepareMaterial( material, targetScene, object );
29412						materials.add( material );
29413
29414					}
29415
29416				}
29417
29418			} );
29419
29420			renderStateStack.pop();
29421			currentRenderState = null;
29422
29423			return materials;
29424
29425		};
29426
29427		// compileAsync
29428
29429		this.compileAsync = function ( scene, camera, targetScene = null ) {
29430
29431			const materials = this.compile( scene, camera, targetScene );
29432
29433			// Wait for all the materials in the new object to indicate that they're
29434			// ready to be used before resolving the promise.
29435
29436			return new Promise( ( resolve ) => {
29437
29438				function checkMaterialsReady() {
29439
29440					materials.forEach( function ( material ) {
29441
29442						const materialProperties = properties.get( material );
29443						const program = materialProperties.currentProgram;
29444
29445						if ( program.isReady() ) {
29446
29447							// remove any programs that report they're ready to use from the list
29448							materials.delete( material );
29449
29450						}
29451
29452					} );
29453
29454					// once the list of compiling materials is empty, call the callback
29455
29456					if ( materials.size === 0 ) {
29457
29458						resolve( scene );
29459						return;
29460
29461					}
29462
29463					// if some materials are still not ready, wait a bit and check again
29464
29465					setTimeout( checkMaterialsReady, 10 );
29466
29467				}
29468
29469				if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) {
29470
29471					// If we can check the compilation status of the materials without
29472					// blocking then do so right away.
29473
29474					checkMaterialsReady();
29475
29476				} else {
29477
29478					// Otherwise start by waiting a bit to give the materials we just
29479					// initialized a chance to finish.
29480
29481					setTimeout( checkMaterialsReady, 10 );
29482
29483				}
29484
29485			} );
29486
29487		};
29488
29489		// Animation Loop
29490
29491		let onAnimationFrameCallback = null;
29492
29493		function onAnimationFrame( time ) {
29494
29495			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
29496
29497		}
29498
29499		function onXRSessionStart() {
29500
29501			animation.stop();
29502
29503		}
29504
29505		function onXRSessionEnd() {
29506
29507			animation.start();
29508
29509		}
29510
29511		const animation = new WebGLAnimation();
29512		animation.setAnimationLoop( onAnimationFrame );
29513
29514		if ( typeof self !== 'undefined' ) animation.setContext( self );
29515
29516		this.setAnimationLoop = function ( callback ) {
29517
29518			onAnimationFrameCallback = callback;
29519			xr.setAnimationLoop( callback );
29520
29521			( callback === null ) ? animation.stop() : animation.start();
29522
29523		};
29524
29525		xr.addEventListener( 'sessionstart', onXRSessionStart );
29526		xr.addEventListener( 'sessionend', onXRSessionEnd );
29527
29528		// Rendering
29529
29530		this.render = function ( scene, camera ) {
29531
29532			if ( camera !== undefined && camera.isCamera !== true ) {
29533
29534				console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
29535				return;
29536
29537			}
29538
29539			if ( _isContextLost === true ) return;
29540
29541			// update scene graph
29542
29543			if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
29544
29545			// update camera matrices and frustum
29546
29547			if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
29548
29549			if ( xr.enabled === true && xr.isPresenting === true ) {
29550
29551				if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
29552
29553				camera = xr.getCamera(); // use XR camera for rendering
29554
29555			}
29556
29557			//
29558			if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );
29559
29560			currentRenderState = renderStates.get( scene, renderStateStack.length );
29561			currentRenderState.init();
29562
29563			renderStateStack.push( currentRenderState );
29564
29565			_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
29566			_frustum.setFromProjectionMatrix( _projScreenMatrix );
29567
29568			_localClippingEnabled = this.localClippingEnabled;
29569			_clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );
29570
29571			currentRenderList = renderLists.get( scene, renderListStack.length );
29572			currentRenderList.init();
29573
29574			renderListStack.push( currentRenderList );
29575
29576			projectObject( scene, camera, 0, _this.sortObjects );
29577
29578			currentRenderList.finish();
29579
29580			if ( _this.sortObjects === true ) {
29581
29582				currentRenderList.sort( _opaqueSort, _transparentSort );
29583
29584			}
29585
29586			//
29587
29588			this.info.render.frame ++;
29589
29590			if ( _clippingEnabled === true ) clipping.beginShadows();
29591
29592			const shadowsArray = currentRenderState.state.shadowsArray;
29593
29594			shadowMap.render( shadowsArray, scene, camera );
29595
29596			if ( _clippingEnabled === true ) clipping.endShadows();
29597
29598			//
29599
29600			if ( this.info.autoReset === true ) this.info.reset();
29601
29602
29603			//
29604
29605			
29605background.render( currentRenderList, scene );
29606
29607			// render scene
29608
29609			currentRenderState.setupLights( _this._useLegacyLights );
29610
29611			if ( camera.isArrayCamera ) {
29612
29613				const cameras = camera.cameras;
29614
29615				for ( let i = 0, l = cameras.length; i < l; i ++ ) {
29616
29617					const camera2 = cameras[ i ];
29618
29619					renderScene( currentRenderList, scene, camera2, camera2.viewport );
29620
29621				}
29622
29623			} else {
29624
29625				renderScene( currentRenderList, scene, camera );
29626
29627			}
29628
29629			//
29630
29631			if ( _currentRenderTarget !== null ) {
29632
29633				// resolve multisample renderbuffers to a single-sample texture if necessary
29634
29635				textures.updateMultisampleRenderTarget( _currentRenderTarget );
29636
29637				// Generate mipmap if we're using any kind of mipmap filtering
29638
29639				textures.updateRenderTargetMipmap( _currentRenderTarget );
29640
29641			}
29642
29643			//
29644
29645			if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
29646
29647			// _gl.finish();
29648
29649			bindingStates.resetDefaultState();
29650			_currentMaterialId = - 
vendor: 9,575 bytes, lines 29650-30005
296501;
29651			_currentCamera = null;
29652
29653			renderStateStack.pop();
29654
29655			if ( renderStateStack.length > 0 ) {
29656
29657				currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
29658
29659			} else {
29660
29661				currentRenderState = null;
29662
29663			}
29664
29665			renderListStack.pop();
29666
29667			if ( renderListStack.length > 0 ) {
29668
29669				currentRenderList = renderListStack[ renderListStack.length - 1 ];
29670
29671			} else {
29672
29673				currentRenderList = null;
29674
29675			}
29676
29677		};
29678
29679		function projectObject( object, camera, groupOrder, sortObjects ) {
29680
29681			if ( object.visible === false ) return;
29682
29683			const visible = object.layers.test( camera.layers );
29684
29685			if ( visible ) {
29686
29687				if ( object.isGroup ) {
29688
29689					groupOrder = object.renderOrder;
29690
29691				} else if ( object.isLOD ) {
29692
29693					if ( object.autoUpdate === true ) object.update( camera );
29694
29695				} else if ( object.isLight ) {
29696
29697					currentRenderState.pushLight( object );
29698
29699					if ( object.castShadow ) {
29700
29701						currentRenderState.pushShadow( object );
29702
29703					}
29704
29705				} else if ( object.isSprite ) {
29706
29707					if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
29708
29709						if ( sortObjects ) {
29710
29711							_vector3.setFromMatrixPosition( object.matrixWorld )
29712								.applyMatrix4( _projScreenMatrix );
29713
29714						}
29715
29716						const geometry = objects.update( object );
29717						const material = object.material;
29718
29719						if ( material.visible ) {
29720
29721							currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29722
29723						}
29724
29725					}
29726
29727				} else if ( object.isMesh || object.isLine || object.isPoints ) {
29728
29729					if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
29730
29731						const geometry = objects.update( object );
29732						const material = object.material;
29733
29734						if ( sortObjects ) {
29735
29736							if ( object.boundingSphere !== undefined ) {
29737
29738								if ( object.boundingSphere === null ) object.computeBoundingSphere();
29739								_vector3.copy( object.boundingSphere.center );
29740
29741							} else {
29742
29743								if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
29744								_vector3.copy( geometry.boundingSphere.center );
29745
29746							}
29747
29748							_vector3
29749								.applyMatrix4( object.matrixWorld )
29750								.applyMatrix4( _projScreenMatrix );
29751
29752						}
29753
29754						if ( Array.isArray( material ) ) {
29755
29756							const groups = geometry.groups;
29757
29758							for ( let i = 0, l = groups.length; i < l; i ++ ) {
29759
29760								const group = groups[ i ];
29761								const groupMaterial = material[ group.materialIndex ];
29762
29763								if ( groupMaterial && groupMaterial.visible ) {
29764
29765									currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
29766
29767								}
29768
29769							}
29770
29771						} else if ( material.visible ) {
29772
29773							currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29774
29775						}
29776
29777					}
29778
29779				}
29780
29781			}
29782
29783			const children = object.children;
29784
29785			for ( let i = 0, l = children.length; i < l; i ++ ) {
29786
29787				projectObject( children[ i ], camera, groupOrder, sortObjects );
29788
29789			}
29790
29791		}
29792
29793		function renderScene( currentRenderList, scene, camera, viewport ) {
29794
29795			const opaqueObjects = currentRenderList.opaque;
29796			const transmissiveObjects = currentRenderList.transmissive;
29797			const transparentObjects = currentRenderList.transparent;
29798
29799			currentRenderState.setupLightsView( camera );
29800
29801			if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
29802
29803			if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );
29804
29805			if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
29806
29807			if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
29808			if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
29809			if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
29810
29811			// Ensure depth buffer writing is enabled so it can be cleared on next render
29812
29813			state.buffers.depth.setTest( true );
29814			state.buffers.depth.setMask( true );
29815			state.buffers.color.setMask( true );
29816
29817			state.setPolygonOffset( false );
29818
29819		}
29820
29821		function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {
29822
29823			const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29824
29825			if ( overrideMaterial !== null ) {
29826
29827				return;
29828
29829			}
29830
29831			const isWebGL2 = capabilities.isWebGL2;
29832
29833			if ( _transmissionRenderTarget === null ) {
29834
29835				_transmissionRenderTarget = new WebGLRenderTarget( 1, 1, {
29836					generateMipmaps: true,
29837					type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
29838					minFilter: LinearMipmapLinearFilter,
29839					samples: ( isWebGL2 ) ? 4 : 0
29840				} );
29841
29842				// debug
29843
29844				/*
29845				const geometry = new PlaneGeometry();
29846				const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
29847
29848				const mesh = new Mesh( geometry, material );
29849				scene.add( mesh );
29850				*/
29851
29852			}
29853
29854			_this.getDrawingBufferSize( _vector2 );
29855
29856			if ( isWebGL2 ) {
29857
29858				_transmissionRenderTarget.setSize( _vector2.x, _vector2.y );
29859
29860			} else {
29861
29862				_transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) );
29863
29864			}
29865
29866			//
29867
29868			const currentRenderTarget = _this.getRenderTarget();
29869			_this.setRenderTarget( _transmissionRenderTarget );
29870
29871			_this.getClearColor( _currentClearColor );
29872			_currentClearAlpha = _this.getClearAlpha();
29873			if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
29874
29875			_this.clear();
29876
29877			// Turn off the features which can affect the frag color for opaque objects pass.
29878			// Otherwise they are applied twice in opaque objects pass and transmission objects pass.
29879			const currentToneMapping = _this.toneMapping;
29880			_this.toneMapping = NoToneMapping;
29881
29882			renderObjects( opaqueObjects, scene, camera );
29883
29884			textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29885			textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29886
29887			let renderTargetNeedsUpdate = false;
29888
29889			for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
29890
29891				const renderItem = transmissiveObjects[ i ];
29892
29893				const object = renderItem.object;
29894				const geometry = renderItem.geometry;
29895				const material = renderItem.material;
29896				const group = renderItem.group;
29897
29898				if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
29899
29900					const currentSide = material.side;
29901
29902					material.side = BackSide;
29903					material.needsUpdate = true;
29904
29905					renderObject( object, scene, camera, geometry, material, group );
29906
29907					material.side = currentSide;
29908					material.needsUpdate = true;
29909
29910					renderTargetNeedsUpdate = true;
29911
29912				}
29913
29914			}
29915
29916			if ( renderTargetNeedsUpdate === true ) {
29917
29918				textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29919				textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29920
29921			}
29922
29923			_this.setRenderTarget( currentRenderTarget );
29924
29925			_this.setClearColor( _currentClearColor, _currentClearAlpha );
29926
29927			_this.toneMapping = currentToneMapping;
29928
29929		}
29930
29931		function renderObjects( renderList, scene, camera ) {
29932
29933			const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29934
29935			for ( let i = 0, l = renderList.length; i < l; i ++ ) {
29936
29937				const renderItem = renderList[ i ];
29938
29939				const object = renderItem.object;
29940				const geometry = renderItem.geometry;
29941				const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
29942				const group = renderItem.group;
29943
29944				if ( object.layers.test( camera.layers ) ) {
29945
29946					renderObject( object, scene, camera, geometry, material, group );
29947
29948				}
29949
29950			}
29951
29952		}
29953
29954		function renderObject( object, scene, camera, geometry, material, group ) {
29955
29956			object.onBeforeRender( _this, scene, camera, geometry, material, group );
29957
29958			object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
29959			object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
29960
29961			material.onBeforeRender( _this, scene, camera, geometry, object, group );
29962
29963			if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29964
29965				material.side = BackSide;
29966				material.needsUpdate = true;
29967				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29968
29969				material.side = FrontSide;
29970				material.needsUpdate = true;
29971				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29972
29973				material.side = DoubleSide;
29974
29975			} else {
29976
29977				_this.renderBufferDirect( camera, scene, geometry, material, object, group );
29978
29979			}
29980
29981			object.onAfterRender( _this, scene, camera, geometry, material, group );
29982
29983		}
29984
29985		function getProgram( material, scene, object ) {
29986
29987			if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
29988
29989			const materialProperties = properties.get( material );
29990
29991			const lights = currentRenderState.state.lights;
29992			const shadowsArray = currentRenderState.state.shadowsArray;
29993
29994			const lightsStateVersion = lights.state.version;
29995
29996			const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
29997			const programCacheKey = programCache.getProgramCacheKey( parameters );
29998
29999			let programs = materialProperties.programs;
30000
30001			// always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
30002
30003			materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
30004			materialProperties.fog = scene.fog;
30005			materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
vendor: 30,854 bytes, lines 30006-31002
30006
30007			if ( programs === undefined ) {
30008
30009				// new material
30010
30011				material.addEventListener( 'dispose', onMaterialDispose );
30012
30013				programs = new Map();
30014				materialProperties.programs = programs;
30015
30016			}
30017
30018			let program = programs.get( programCacheKey );
30019
30020			if ( program !== undefined ) {
30021
30022				// early out if program and light state is identical
30023
30024				if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
30025
30026					updateCommonMaterialProperties( material, parameters );
30027
30028					return program;
30029
30030				}
30031
30032			} else {
30033
30034				parameters.uniforms = programCache.getUniforms( material );
30035
30036				material.onBuild( object, parameters, _this );
30037
30038				material.onBeforeCompile( parameters, _this );
30039
30040				program = programCache.acquireProgram( parameters, programCacheKey );
30041				programs.set( programCacheKey, program );
30042
30043				materialProperties.uniforms = parameters.uniforms;
30044
30045			}
30046
30047			const uniforms = materialProperties.uniforms;
30048
30049			if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
30050
30051				uniforms.clippingPlanes = clipping.uniform;
30052
30053			}
30054
30055			updateCommonMaterialProperties( material, parameters );
30056
30057			// store the light setup it was created for
30058
30059			materialProperties.needsLights = materialNeedsLights( material );
30060			materialProperties.lightsStateVersion = lightsStateVersion;
30061
30062			if ( materialProperties.needsLights ) {
30063
30064				// wire up the material to this renderer's lighting state
30065
30066				uniforms.ambientLightColor.value = lights.state.ambient;
30067				uniforms.lightProbe.value = lights.state.probe;
30068				uniforms.directionalLights.value = lights.state.directional;
30069				uniforms.directionalLightShadows.value = lights.state.directionalShadow;
30070				uniforms.spotLights.value = lights.state.spot;
30071				uniforms.spotLightShadows.value = lights.state.spotShadow;
30072				uniforms.rectAreaLights.value = lights.state.rectArea;
30073				uniforms.ltc_1.value = lights.state.rectAreaLTC1;
30074				uniforms.ltc_2.value = lights.state.rectAreaLTC2;
30075				uniforms.pointLights.value = lights.state.point;
30076				uniforms.pointLightShadows.value = lights.state.pointShadow;
30077				uniforms.hemisphereLights.value = lights.state.hemi;
30078
30079				uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
30080				uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
30081				uniforms.spotShadowMap.value = lights.state.spotShadowMap;
30082				uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
30083				uniforms.spotLightMap.value = lights.state.spotLightMap;
30084				uniforms.pointShadowMap.value = lights.state.pointShadowMap;
30085				uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
30086				// TODO (abelnation): add area lights shadow info to uniforms
30087
30088			}
30089
30090			materialProperties.currentProgram = program;
30091			materialProperties.uniformsList = null;
30092
30093			return program;
30094
30095		}
30096
30097		function getUniformList( materialProperties ) {
30098
30099			if ( materialProperties.uniformsList === null ) {
30100
30101				const progUniforms = materialProperties.currentProgram.getUniforms();
30102				materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );
30103
30104			}
30105
30106			return materialProperties.uniformsList;
30107
30108		}
30109
30110		function updateCommonMaterialProperties( material, parameters ) {
30111
30112			const materialProperties = properties.get( material );
30113
30114			materialProperties.outputColorSpace = parameters.outputColorSpace;
30115			materialProperties.batching = parameters.batching;
30116			materialProperties.instancing = parameters.instancing;
30117			materialProperties.instancingColor = parameters.instancingColor;
30118			materialProperties.skinning = parameters.skinning;
30119			materialProperties.morphTargets = parameters.morphTargets;
30120			materialProperties.morphNormals = parameters.morphNormals;
30121			materialProperties.morphColors = parameters.morphColors;
30122			materialProperties.morphTargetsCount = parameters.morphTargetsCount;
30123			materialProperties.numClippingPlanes = parameters.numClippingPlanes;
30124			materialProperties.numIntersection = parameters.numClipIntersection;
30125			materialProperties.vertexAlphas = parameters.vertexAlphas;
30126			materialProperties.vertexTangents = parameters.vertexTangents;
30127			materialProperties.toneMapping = parameters.toneMapping;
30128
30129		}
30130
30131		function setProgram( camera, scene, geometry, material, object ) {
30132
30133			if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
30134
30135			textures.resetTextureUnits();
30136
30137			const fog = scene.fog;
30138			const environment = material.isMeshStandardMaterial ? scene.environment : null;
30139			const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );
30140			const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
30141			const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
30142			const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );
30143			const morphTargets = !! geometry.morphAttributes.position;
30144			const morphNormals = !! geometry.morphAttributes.normal;
30145			const morphColors = !! geometry.morphAttributes.color;
30146
30147			let toneMapping = NoToneMapping;
30148
30149			if ( material.toneMapped ) {
30150
30151				if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {
30152
30153					toneMapping = _this.toneMapping;
30154
30155				}
30156
30157			}
30158
30159			const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
30160			const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
30161
30162			const materialProperties = properties.get( material );
30163			const lights = currentRenderState.state.lights;
30164
30165			if ( _clippingEnabled === true ) {
30166
30167				if ( _localClippingEnabled === true || camera !== _currentCamera ) {
30168
30169					const useCache =
30170						camera === _currentCamera &&
30171						material.id === _currentMaterialId;
30172
30173					// we might want to call this function with some ClippingGroup
30174					// object instead of the material, once it becomes feasible
30175					// (#8465, #8379)
30176					clipping.setState( material, camera, useCache );
30177
30178				}
30179
30180			}
30181
30182			//
30183
30184			let needsProgramChange = false;
30185
30186			if ( material.version === materialProperties.__version ) {
30187
30188				if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
30189
30190					needsProgramChange = true;
30191
30192				} else if ( materialProperties.outputColorSpace !== colorSpace ) {
30193
30194					needsProgramChange = true;
30195
30196				} else if ( object.isBatchedMesh && materialProperties.batching === false ) {
30197
30198					needsProgramChange = true;
30199
30200				} else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {
30201
30202					needsProgramChange = true;
30203
30204				} else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
30205
30206					needsProgramChange = true;
30207
30208				} else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
30209
30210					needsProgramChange = true;
30211
30212				} else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {
30213
30214					needsProgramChange = true;
30215
30216				} else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {
30217
30218					needsProgramChange = true;
30219
30220				} else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {
30221
30222					needsProgramChange = true;
30223
30224				} else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {
30225
30226					needsProgramChange = true;
30227
30228				} else if ( materialProperties.envMap !== envMap ) {
30229
30230					needsProgramChange = true;
30231
30232				} else if ( material.fog === true && materialProperties.fog !== fog ) {
30233
30234					needsProgramChange = true;
30235
30236				} else if ( materialProperties.numClippingPlanes !== undefined &&
30237					( materialProperties.numClippingPlanes !== clipping.numPlanes ||
30238					materialProperties.numIntersection !== clipping.numIntersection ) ) {
30239
30240					needsProgramChange = true;
30241
30242				} else if ( materialProperties.vertexAlphas !== vertexAlphas ) {
30243
30244					needsProgramChange = true;
30245
30246				} else if ( materialProperties.vertexTangents !== vertexTangents ) {
30247
30248					needsProgramChange = true;
30249
30250				} else if ( materialProperties.morphTargets !== morphTargets ) {
30251
30252					needsProgramChange = true;
30253
30254				} else if ( materialProperties.morphNormals !== morphNormals ) {
30255
30256					needsProgramChange = true;
30257
30258				} else if ( materialProperties.morphColors !== morphColors ) {
30259
30260					needsProgramChange = true;
30261
30262				} else if ( materialProperties.toneMapping !== toneMapping ) {
30263
30264					needsProgramChange = true;
30265
30266				} else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) {
30267
30268					needsProgramChange = true;
30269
30270				}
30271
30272			} else {
30273
30274				needsProgramChange = true;
30275				materialProperties.__version = material.version;
30276
30277			}
30278
30279			//
30280
30281			let program = materialProperties.currentProgram;
30282
30283			if ( needsProgramChange === true ) {
30284
30285				program = getProgram( material, scene, object );
30286
30287			}
30288
30289			let refreshProgram = false;
30290			let refreshMaterial = false;
30291			let refreshLights = false;
30292
30293			const p_uniforms = program.getUniforms(),
30294				m_uniforms = materialProperties.uniforms;
30295
30296			if ( state.useProgram( program.program ) ) {
30297
30298				refreshProgram = true;
30299				refreshMaterial = true;
30300				refreshLights = true;
30301
30302			}
30303
30304			if ( material.id !== _currentMaterialId ) {
30305
30306				_currentMaterialId = material.id;
30307
30308				refreshMaterial = true;
30309
30310			}
30311
30312			if ( refreshProgram || _currentCamera !== camera ) {
30313
30314				// common camera uniforms
30315
30316				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
30317				p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
30318
30319				const uCamPos = p_uniforms.map.cameraPosition;
30320
30321				if ( uCamPos !== undefined ) {
30322
30323					uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
30324
30325				}
30326
30327				if ( capabilities.logarithmicDepthBuffer ) {
30328
30329					p_uniforms.setValue( _gl, 'logDepthBufFC',
30330						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
30331
30332				}
30333
30334				// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
30335
30336				if ( material.isMeshPhongMaterial ||
30337					material.isMeshToonMaterial ||
30338					material.isMeshLambertMaterial ||
30339					material.isMeshBasicMaterial ||
30340					material.isMeshStandardMaterial ||
30341					material.isShaderMaterial ) {
30342
30343					p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
30344
30345				}
30346
30347				if ( _currentCamera !== camera ) {
30348
30349					_currentCamera = camera;
30350
30351					// lighting uniforms depend on the camera so enforce an update
30352					// now, in case this material supports lights - or later, when
30353					// the next material that does gets activated:
30354
30355					refreshMaterial = true;		// set to true on material change
30356					refreshLights = true;		// remains set until update done
30357
30358				}
30359
30360			}
30361
30362			// skinning and morph target uniforms must be set even if material didn't change
30363			// auto-setting of texture unit for bone and morph texture must go before other textures
30364			// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
30365
30366			if ( object.isSkinnedMesh ) {
30367
30368				p_uniforms.setOptional( _gl, object, 'bindMatrix' );
30369				p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
30370
30371				const skeleton = object.skeleton;
30372
30373				if ( skeleton ) {
30374
30375					if ( capabilities.floatVertexTextures ) {
30376
30377						if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();
30378
30379						p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
30380
30381					} else {
30382
30383						console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' );
30384
30385					}
30386
30387				}
30388
30389			}
30390
30391			if ( object.isBatchedMesh ) {
30392
30393				p_uniforms.setOptional( _gl, object, 'batchingTexture' );
30394				p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );
30395
30396			}
30397
30398			const morphAttributes = geometry.morphAttributes;
30399
30400			if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
30401
30402				morphtargets.update( object, geometry, program );
30403
30404			}
30405
30406			if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
30407
30408				materialProperties.receiveShadow = object.receiveShadow;
30409				p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
30410
30411			}
30412
30413			// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
30414
30415			if ( material.isMeshGouraudMaterial && material.envMap !== null ) {
30416
30417				m_uniforms.envMap.value = envMap;
30418
30419				m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
30420
30421			}
30422
30423			if ( refreshMaterial ) {
30424
30425				p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
30426
30427				if ( materialProperties.needsLights ) {
30428
30429					// the current material requires lighting info
30430
30431					// note: all lighting uniforms are always set correctly
30432					// they simply reference the renderer's state for their
30433					// values
30434					//
30435					// use the current material's .needsUpdate flags to set
30436					// the GL state when required
30437
30438					markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
30439
30440				}
30441
30442				// refresh uniforms common to several materials
30443
30444				if ( fog && material.fog === true ) {
30445
30446					materials.refreshFogUniforms( m_uniforms, fog );
30447
30448				}
30449
30450				materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget );
30451
30452				WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
30453
30454			}
30455
30456			if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
30457
30458				WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
30459				material.uniformsNeedUpdate = false;
30460
30461			}
30462
30463			if ( material.isSpriteMaterial ) {
30464
30465				p_uniforms.setValue( _gl, 'center', object.center );
30466
30467			}
30468
30469			// common matrices
30470
30471			p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
30472			p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
30473			p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
30474
30475			// UBOs
30476
30477			if ( material.isShaderMaterial || material.isRawShaderMaterial ) {
30478
30479				const groups = material.uniformsGroups;
30480
30481				for ( let i = 0, l = groups.length; i < l; i ++ ) {
30482
30483					if ( capabilities.isWebGL2 ) {
30484
30485						const group = groups[ i ];
30486
30487						uniformsGroups.update( group, program );
30488						uniformsGroups.bind( group, program );
30489
30490					} else {
30491
30492						console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' );
30493
30494					}
30495
30496				}
30497
30498			}
30499
30500			return program;
30501
30502		}
30503
30504		// If uniforms are marked as clean, they don't need to be loaded to the GPU.
30505
30506		function markUniformsLightsNeedsUpdate( uniforms, value ) {
30507
30508			uniforms.ambientLightColor.needsUpdate = value;
30509			uniforms.lightProbe.needsUpdate = value;
30510
30511			uniforms.directionalLights.needsUpdate = value;
30512			uniforms.directionalLightShadows.needsUpdate = value;
30513			uniforms.pointLights.needsUpdate = value;
30514			uniforms.pointLightShadows.needsUpdate = value;
30515			uniforms.spotLights.needsUpdate = value;
30516			uniforms.spotLightShadows.needsUpdate = value;
30517			uniforms.rectAreaLights.needsUpdate = value;
30518			uniforms.hemisphereLights.needsUpdate = value;
30519
30520		}
30521
30522		function materialNeedsLights( material ) {
30523
30524			return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
30525				material.isMeshStandardMaterial || material.isShadowMaterial ||
30526				( material.isShaderMaterial && material.lights === true );
30527
30528		}
30529
30530		this.getActiveCubeFace = function () {
30531
30532			return _currentActiveCubeFace;
30533
30534		};
30535
30536		this.getActiveMipmapLevel = function () {
30537
30538			return _currentActiveMipmapLevel;
30539
30540		};
30541
30542		this.getRenderTarget = function () {
30543
30544			return _currentRenderTarget;
30545
30546		};
30547
30548		this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {
30549
30550			properties.get( renderTarget.texture ).__webglTexture = colorTexture;
30551			properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;
30552
30553			const renderTargetProperties = properties.get( renderTarget );
30554			renderTargetProperties.__hasExternalTextures = true;
30555
30556			if ( renderTargetProperties.__hasExternalTextures ) {
30557
30558				renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
30559
30560				if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
30561
30562					// The multisample_render_to_texture extension doesn't work properly if there
30563					// are midframe flushes and an external depth buffer. Disable use of the extension.
30564					if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {
30565
30566						console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
30567						renderTargetProperties.__useRenderToTexture = false;
30568
30569					}
30570
30571				}
30572
30573			}
30574
30575		};
30576
30577		this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {
30578
30579			const renderTargetProperties = properties.get( renderTarget );
30580			renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
30581			renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;
30582
30583		};
30584
30585		this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
30586
30587			_currentRenderTarget = renderTarget;
30588			_currentActiveCubeFace = activeCubeFace;
30589			_currentActiveMipmapLevel = activeMipmapLevel;
30590
30591			let useDefaultFramebuffer = true;
30592			let framebuffer = null;
30593			let isCube = false;
30594			let isRenderTarget3D = false;
30595
30596			if ( renderTarget ) {
30597
30598				const renderTargetProperties = properties.get( renderTarget );
30599
30600				if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {
30601
30602					// We need to make sure to rebind the framebuffer.
30603					state.bindFramebuffer( _gl.FRAMEBUFFER, null );
30604					useDefaultFramebuffer = false;
30605
30606				} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {
30607
30608					textures.setupRenderTarget( renderTarget );
30609
30610				} else if ( renderTargetProperties.__hasExternalTextures ) {
30611
30612					// Color and depth texture must be rebound in order for the swapchain to update.
30613					textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );
30614
30615				}
30616
30617				const texture = renderTarget.texture;
30618
30619				if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30620
30621					isRenderTarget3D = true;
30622
30623				}
30624
30625				const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
30626
30627				if ( renderTarget.isWebGLCubeRenderTarget ) {
30628
30629					if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {
30630
30631						framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];
30632
30633					} else {
30634
30635						framebuffer = __webglFramebuffer[ activeCubeFace ];
30636
30637					}
30638
30639					isCube = true;
30640
30641				} else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {
30642
30643					framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
30644
30645				} else {
30646
30647					if ( Array.isArray( __webglFramebuffer ) ) {
30648
30649						framebuffer = __webglFramebuffer[ activeMipmapLevel ];
30650
30651					} else {
30652
30653						framebuffer = __webglFramebuffer;
30654
30655					}
30656
30657				}
30658
30659				_currentViewport.copy( renderTarget.viewport );
30660				_currentScissor.copy( renderTarget.scissor );
30661				_currentScissorTest = renderTarget.scissorTest;
30662
30663			} else {
30664
30665				_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
30666				_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
30667				_currentScissorTest = _scissorTest;
30668
30669			}
30670
30671			const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30672
30673			if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) {
30674
30675				state.drawBuffers( renderTarget, framebuffer );
30676
30677			}
30678
30679			state.viewport( _currentViewport );
30680			state.scissor( _currentScissor );
30681			state.setScissorTest( _currentScissorTest );
30682
30683			if ( isCube ) {
30684
30685				const textureProperties = properties.get( renderTarget.texture );
30686				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
30687
30688			} else if ( isRenderTarget3D ) {
30689
30690				const textureProperties = properties.get( renderTarget.texture );
30691				const layer = activeCubeFace || 0;
30692				_gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );
30693
30694			}
30695
30696			_currentMaterialId = - 1; // reset current material to ensure correct uniform bindings
30697
30698		};
30699
30700		this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
30701
30702			if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
30703
30704				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
30705				return;
30706
30707			}
30708
30709			let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
30710
30711			if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
30712
30713				framebuffer = framebuffer[ activeCubeFaceIndex ];
30714
30715			}
30716
30717			if ( framebuffer ) {
30718
30719				state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30720
30721				try {
30722
30723					const texture = renderTarget.texture;
30724					const textureFormat = texture.format;
30725					const textureType = texture.type;
30726
30727					if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
30728
30729						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
30730						return;
30731
30732					}
30733
30734					const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
30735
30736					if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
30737						! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
30738						! halfFloatSupportedByExt ) {
30739
30740						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
30741						return;
30742
30743					}
30744
30745					// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
30746
30747					if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
30748
30749						_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
30750
30751					}
30752
30753				} finally {
30754
30755					// restore framebuffer of current render target if necessary
30756
30757					const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
30758					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30759
30760				}
30761
30762			}
30763
30764		};
30765
30766		this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
30767
30768			const levelScale = Math.pow( 2, - level );
30769			const width = Math.floor( texture.image.width * levelScale );
30770			const height = Math.floor( texture.image.height * levelScale );
30771
30772			textures.setTexture2D( texture, 0 );
30773
30774			_gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height );
30775
30776			state.unbindTexture();
30777
30778		};
30779
30780		this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
30781
30782			const width = srcTexture.image.width;
30783			const height = srcTexture.image.height;
30784			const glFormat = utils.convert( dstTexture.format );
30785			const glType = utils.convert( dstTexture.type );
30786
30787			textures.setTexture2D( dstTexture, 0 );
30788
30789			// As another texture upload may have changed pixelStorei
30790			// parameters, make sure they are correct for the dstTexture
30791			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30792			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30793			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30794
30795			if ( srcTexture.isDataTexture ) {
30796
30797				_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
30798
30799			} else {
30800
30801				if ( srcTexture.isCompressedTexture ) {
30802
30803					_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
30804
30805				} else {
30806
30807					_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
30808
30809				}
30810
30811			}
30812
30813			// Generate mipmaps only when copying level 0
30814			if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );
30815
30816			state.unbindTexture();
30817
30818		};
30819
30820		this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
30821
30822			if ( _this.isWebGL1Renderer ) {
30823
30824				console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' );
30825				return;
30826
30827			}
30828
30829			const width = sourceBox.max.x - sourceBox.min.x + 1;
30830			const height = sourceBox.max.y - sourceBox.min.y + 1;
30831			const depth = sourceBox.max.z - sourceBox.min.z + 1;
30832			const glFormat = utils.convert( dstTexture.format );
30833			const glType = utils.convert( dstTexture.type );
30834			let glTarget;
30835
30836			if ( dstTexture.isData3DTexture ) {
30837
30838				textures.setTexture3D( dstTexture, 0 );
30839				glTarget = _gl.TEXTURE_3D;
30840
30841			} else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {
30842
30843				textures.setTexture2DArray( dstTexture, 0 );
30844				glTarget = _gl.TEXTURE_2D_ARRAY;
30845
30846			} else {
30847
30848				console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );
30849				return;
30850
30851			}
30852
30853			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30854			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30855			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30856
30857			const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
30858			const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
30859			const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
30860			const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
30861			const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );
30862
30863			const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
30864
30865			_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
30866			_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
30867			_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x );
30868			_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );
30869			_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z );
30870
30871			if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {
30872
30873				_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
30874
30875			} else {
30876
30877				if ( srcTexture.isCompressedArrayTexture ) {
30878
30879					console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' );
30880					_gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
30881
30882				} else {
30883
30884					_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
30885
30886				}
30887
30888			}
30889
30890			_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen );
30891			_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight );
30892			_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels );
30893			_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows );
30894			_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages );
30895
30896			// Generate mipmaps only when copying level 0
30897			if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
30898
30899			state.unbindTexture();
30900
30901		};
30902
30903		this.initTexture = function ( texture ) {
30904
30905			if ( texture.isCubeTexture ) {
30906
30907				textures.setTextureCube( texture, 0 );
30908
30909			} else if ( texture.isData3DTexture ) {
30910
30911				textures.setTexture3D( texture, 0 );
30912
30913			} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30914
30915				textures.setTexture2DArray( texture, 0 );
30916
30917			} else {
30918
30919				textures.setTexture2D( texture, 0 );
30920
30921			}
30922
30923			state.unbindTexture();
30924
30925		};
30926
30927		this.resetState = function () {
30928
30929			_currentActiveCubeFace = 0;
30930			_currentActiveMipmapLevel = 0;
30931			_currentRenderTarget = null;
30932
30933			state.reset();
30934			bindingStates.reset();
30935
30936		};
30937
30938		if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
30939
30940			__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
30941
30942		}
30943
30944	}
30945
30946	get coordinateSystem() {
30947
30948		return WebGLCoordinateSystem;
30949
30950	}
30951
30952	get outputColorSpace() {
30953
30954		return this._outputColorSpace;
30955
30956	}
30957
30958	set outputColorSpace( colorSpace ) {
30959
30960		this._outputColorSpace = colorSpace;
30961
30962		const gl = this.getContext();
30963		gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';
30964		gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';
30965
30966	}
30967
30968	get outputEncoding() { // @deprecated, r152
30969
30970		console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30971		return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding;
30972
30973	}
30974
30975	set outputEncoding( encoding ) { // @deprecated, r152
30976
30977		console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30978		this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
30979
30980	}
30981
30982	get useLegacyLights() { // @deprecated, r155
30983
30984		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.' );
30985		return this._useLegacyLights;
30986
30987	}
30988
30989	set useLegacyLights( value ) { // @deprecated, r155
30990
30991		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.' );
30992		this._useLegacyLights = value;
30993
30994	}
30995
30996}
30997
30998class WebGL1Renderer extends WebGLRenderer {}
30999
31000WebGL1Renderer.prototype.isWebGL1Renderer = true;
31001
31002class FogExp2 {
vendor: 11,018 bytes, lines 31003-31656
31003
31004	constructor( color, density = 0.00025 ) {
31005
31006		this.isFogExp2 = true;
31007
31008		this.name = '';
31009
31010		this.color = new Color( color );
31011		this.density = density;
31012
31013	}
31014
31015	clone() {
31016
31017		return new FogExp2( this.color, this.density );
31018
31019	}
31020
31021	toJSON( /* meta */ ) {
31022
31023		return {
31024			type: 'FogExp2',
31025			name: this.name,
31026			color: this.color.getHex(),
31027			density: this.density
31028		};
31029
31030	}
31031
31032}
31033
31034class Fog {
31035
31036	constructor( color, near = 1, far = 1000 ) {
31037
31038		this.isFog = true;
31039
31040		this.name = '';
31041
31042		this.color = new Color( color );
31043
31044		this.near = near;
31045		this.far = far;
31046
31047	}
31048
31049	clone() {
31050
31051		return new Fog( this.color, this.near, this.far );
31052
31053	}
31054
31055	toJSON( /* meta */ ) {
31056
31057		return {
31058			type: 'Fog',
31059			name: this.name,
31060			color: this.color.getHex(),
31061			near: this.near,
31062			far: this.far
31063		};
31064
31065	}
31066
31067}
31068
31069class Scene extends Object3D {
31070
31071	constructor() {
31072
31073		super();
31074
31075		this.isScene = true;
31076
31077		this.type = 'Scene';
31078
31079		this.background = null;
31080		this.environment = null;
31081		this.fog = null;
31082
31083		this.backgroundBlurriness = 0;
31084		this.backgroundIntensity = 1;
31085
31086		this.overrideMaterial = null;
31087
31088		if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
31089
31090			__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
31091
31092		}
31093
31094	}
31095
31096	copy( source, recursive ) {
31097
31098		super.copy( source, recursive );
31099
31100		if ( source.background !== null ) this.background = source.background.clone();
31101		if ( source.environment !== null ) this.environment = source.environment.clone();
31102		if ( source.fog !== null ) this.fog = source.fog.clone();
31103
31104		this.backgroundBlurriness = source.backgroundBlurriness;
31105		this.backgroundIntensity = source.backgroundIntensity;
31106
31107		if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
31108
31109		this.matrixAutoUpdate = source.matrixAutoUpdate;
31110
31111		return this;
31112
31113	}
31114
31115	toJSON( meta ) {
31116
31117		const data = super.toJSON( meta );
31118
31119		if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
31120		if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness;
31121		if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity;
31122
31123		return data;
31124
31125	}
31126
31127}
31128
31129class InterleavedBuffer {
31130
31131	constructor( array, stride ) {
31132
31133		this.isInterleavedBuffer = true;
31134
31135		this.array = array;
31136		this.stride = stride;
31137		this.count = array !== undefined ? array.length / stride : 0;
31138
31139		this.usage = StaticDrawUsage;
31140		this._updateRange = { offset: 0, count: - 1 };
31141		this.updateRanges = [];
31142
31143		this.version = 0;
31144
31145		this.uuid = generateUUID();
31146
31147	}
31148
31149	onUploadCallback() {}
31150
31151	set needsUpdate( value ) {
31152
31153		if ( value === true ) this.version ++;
31154
31155	}
31156
31157	get updateRange() {
31158
31159		console.warn( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
31160		return this._updateRange;
31161
31162	}
31163
31164	setUsage( value ) {
31165
31166		this.usage = value;
31167
31168		return this;
31169
31170	}
31171
31172	addUpdateRange( start, count ) {
31173
31174		this.updateRanges.push( { start, count } );
31175
31176	}
31177
31178	clearUpdateRanges() {
31179
31180		this.updateRanges.length = 0;
31181
31182	}
31183
31184	copy( source ) {
31185
31186		this.array = new source.array.constructor( source.array );
31187		this.count = source.count;
31188		this.stride = source.stride;
31189		this.usage = source.usage;
31190
31191		return this;
31192
31193	}
31194
31195	copyAt( index1, attribute, index2 ) {
31196
31197		index1 *= this.stride;
31198		index2 *= attribute.stride;
31199
31200		for ( let i = 0, l = this.stride; i < l; i ++ ) {
31201
31202			this.array[ index1 + i ] = attribute.array[ index2 + i ];
31203
31204		}
31205
31206		return this;
31207
31208	}
31209
31210	set( value, offset = 0 ) {
31211
31212		this.array.set( value, offset );
31213
31214		return this;
31215
31216	}
31217
31218	clone( data ) {
31219
31220		if ( data.arrayBuffers === undefined ) {
31221
31222			data.arrayBuffers = {};
31223
31224		}
31225
31226		if ( this.array.buffer._uuid === undefined ) {
31227
31228			this.array.buffer._uuid = generateUUID();
31229
31230		}
31231
31232		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31233
31234			data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
31235
31236		}
31237
31238		const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
31239
31240		const ib = new this.constructor( array, this.stride );
31241		ib.setUsage( this.usage );
31242
31243		return ib;
31244
31245	}
31246
31247	onUpload( callback ) {
31248
31249		this.onUploadCallback = callback;
31250
31251		return this;
31252
31253	}
31254
31255	toJSON( data ) {
31256
31257		if ( data.arrayBuffers === undefined ) {
31258
31259			data.arrayBuffers = {};
31260
31261		}
31262
31263		// generate UUID for array buffer if necessary
31264
31265		if ( this.array.buffer._uuid === undefined ) {
31266
31267			this.array.buffer._uuid = generateUUID();
31268
31269		}
31270
31271		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31272
31273			data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );
31274
31275		}
31276
31277		//
31278
31279		return {
31280			uuid: this.uuid,
31281			buffer: this.array.buffer._uuid,
31282			type: this.array.constructor.name,
31283			stride: this.stride
31284		};
31285
31286	}
31287
31288}
31289
31290const _vector$6 = /*@__PURE__*/ new Vector3();
31291
31292class InterleavedBufferAttribute {
31293
31294	constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
31295
31296		this.isInterleavedBufferAttribute = true;
31297
31298		this.name = '';
31299
31300		this.data = interleavedBuffer;
31301		this.itemSize = itemSize;
31302		this.offset = offset;
31303
31304		this.normalized = normalized;
31305
31306	}
31307
31308	get count() {
31309
31310		return this.data.count;
31311
31312	}
31313
31314	get array() {
31315
31316		return this.data.array;
31317
31318	}
31319
31320	set needsUpdate( value ) {
31321
31322		this.data.needsUpdate = value;
31323
31324	}
31325
31326	applyMatrix4( m ) {
31327
31328		for ( let i = 0, l = this.data.count; i < l; i ++ ) {
31329
31330			_vector$6.fromBufferAttribute( this, i );
31331
31332			_vector$6.applyMatrix4( m );
31333
31334			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31335
31336		}
31337
31338		return this;
31339
31340	}
31341
31342	applyNormalMatrix( m ) {
31343
31344		for ( let i = 0, l = this.count; i < l; i ++ ) {
31345
31346			_vector$6.fromBufferAttribute( this, i );
31347
31348			_vector$6.applyNormalMatrix( m );
31349
31350			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31351
31352		}
31353
31354		return this;
31355
31356	}
31357
31358	transformDirection( m ) {
31359
31360		for ( let i = 0, l = this.count; i < l; i ++ ) {
31361
31362			_vector$6.fromBufferAttribute( this, i );
31363
31364			_vector$6.transformDirection( m );
31365
31366			this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31367
31368		}
31369
31370		return this;
31371
31372	}
31373
31374	setX( index, x ) {
31375
31376		if ( this.normalized ) x = normalize( x, this.array );
31377
31378		this.data.array[ index * this.data.stride + this.offset ] = x;
31379
31380		return this;
31381
31382	}
31383
31384	setY( index, y ) {
31385
31386		if ( this.normalized ) y = normalize( y, this.array );
31387
31388		this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
31389
31390		return this;
31391
31392	}
31393
31394	setZ( index, z ) {
31395
31396		if ( this.normalized ) z = normalize( z, this.array );
31397
31398		this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
31399
31400		return this;
31401
31402	}
31403
31404	setW( index, w ) {
31405
31406		if ( this.normalized ) w = normalize( w, this.array );
31407
31408		this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
31409
31410		return this;
31411
31412	}
31413
31414	getX( index ) {
31415
31416		let x = this.data.array[ index * this.data.stride + this.offset ];
31417
31418		if ( this.normalized ) x = denormalize( x, this.array );
31419
31420		return x;
31421
31422	}
31423
31424	getY( index ) {
31425
31426		let y = this.data.array[ index * this.data.stride + this.offset + 1 ];
31427
31428		if ( this.normalized ) y = denormalize( y, this.array );
31429
31430		return y;
31431
31432	}
31433
31434	getZ( index ) {
31435
31436		let z = this.data.array[ index * this.data.stride + this.offset + 2 ];
31437
31438		if ( this.normalized ) z = denormalize( z, this.array );
31439
31440		return z;
31441
31442	}
31443
31444	getW( index ) {
31445
31446		let w = this.data.array[ index * this.data.stride + this.offset + 3 ];
31447
31448		if ( this.normalized ) w = denormalize( w, this.array );
31449
31450		return w;
31451
31452	}
31453
31454	setXY( index, x, y ) {
31455
31456		index = index * this.data.stride + this.offset;
31457
31458		if ( this.normalized ) {
31459
31460			x = normalize( x, this.array );
31461			y = normalize( y, this.array );
31462
31463		}
31464
31465		this.data.array[ index + 0 ] = x;
31466		this.data.array[ index + 1 ] = y;
31467
31468		return this;
31469
31470	}
31471
31472	setXYZ( index, x, y, z ) {
31473
31474		index = index * this.data.stride + this.offset;
31475
31476		if ( this.normalized ) {
31477
31478			x = normalize( x, this.array );
31479			y = normalize( y, this.array );
31480			z = normalize( z, this.array );
31481
31482		}
31483
31484		this.data.array[ index + 0 ] = x;
31485		this.data.array[ index + 1 ] = y;
31486		this.data.array[ index + 2 ] = z;
31487
31488		return this;
31489
31490	}
31491
31492	setXYZW( index, x, y, z, w ) {
31493
31494		index = index * this.data.stride + this.offset;
31495
31496		if ( this.normalized ) {
31497
31498			x = normalize( x, this.array );
31499			y = normalize( y, this.array );
31500			z = normalize( z, this.array );
31501			w = normalize( w, this.array );
31502
31503		}
31504
31505		this.data.array[ index + 0 ] = x;
31506		this.data.array[ index + 1 ] = y;
31507		this.data.array[ index + 2 ] = z;
31508		this.data.array[ index + 3 ] = w;
31509
31510		return this;
31511
31512	}
31513
31514	clone( data ) {
31515
31516		if ( data === undefined ) {
31517
31518			console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );
31519
31520			const array = [];
31521
31522			for ( let i = 0; i < this.count; i ++ ) {
31523
31524				const index = i * this.data.stride + this.offset;
31525
31526				for ( let j = 0; j < this.itemSize; j ++ ) {
31527
31528					array.push( this.data.array[ index + j ] );
31529
31530				}
31531
31532			}
31533
31534			return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
31535
31536		} else {
31537
31538			if ( data.interleavedBuffers === undefined ) {
31539
31540				data.interleavedBuffers = {};
31541
31542			}
31543
31544			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31545
31546				data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
31547
31548			}
31549
31550			return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
31551
31552		}
31553
31554	}
31555
31556	toJSON( data ) {
31557
31558		if ( data === undefined ) {
31559
31560			console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );
31561
31562			const array = [];
31563
31564			for ( let i = 0; i < this.count; i ++ ) {
31565
31566				const index = i * this.data.stride + this.offset;
31567
31568				for ( let j = 0; j < this.itemSize; j ++ ) {
31569
31570					array.push( this.data.array[ index + j ] );
31571
31572				}
31573
31574			}
31575
31576			// de-interleave data and save it as an ordinary buffer attribute for now
31577
31578			return {
31579				itemSize: this.itemSize,
31580				type: this.array.constructor.name,
31581				array: array,
31582				normalized: this.normalized
31583			};
31584
31585		} else {
31586
31587			// save as true interleaved attribute
31588
31589			if ( data.interleavedBuffers === undefined ) {
31590
31591				data.interleavedBuffers = {};
31592
31593			}
31594
31595			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31596
31597				data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
31598
31599			}
31600
31601			return {
31602				isInterleavedBufferAttribute: true,
31603				itemSize: this.itemSize,
31604				data: this.data.uuid,
31605				offset: this.offset,
31606				normalized: this.normalized
31607			};
31608
31609		}
31610
31611	}
31612
31613}
31614
31615class SpriteMaterial extends Material {
31616
31617	constructor( parameters ) {
31618
31619		super();
31620
31621		this.isSpriteMaterial = true;
31622
31623		this.type = 'SpriteMaterial';
31624
31625		this.color = new Color( 0xffffff );
31626
31627		this.map = null;
31628
31629		this.alphaMap = null;
31630
31631		this.rotation = 0;
31632
31633		this.sizeAttenuation = true;
31634
31635		this.transparent = true;
31636
31637		this.fog = true;
31638
31639		this.setValues( parameters );
31640
31641	}
31642
31643	copy( source ) {
31644
31645		super.copy( source );
31646
31647		this.color.copy( source.color );
31648
31649		this.map = source.map;
31650
31651		this.alphaMap = source.alphaMap;
31652
31653		this.rotation = source.rotation;
31654
31655		this.sizeAttenuation = source.sizeAttenuation;
31656
vendor: 6,736 bytes, lines 31657-31993
31657		this.fog = source.fog;
31658
31659		return this;
31660
31661	}
31662
31663}
31664
31665let _geometry;
31666
31667const _intersectPoint = /*@__PURE__*/ new Vector3();
31668const _worldScale = /*@__PURE__*/ new Vector3();
31669const _mvPosition = /*@__PURE__*/ new Vector3();
31670
31671const _alignedPosition = /*@__PURE__*/ new Vector2();
31672const _rotatedPosition = /*@__PURE__*/ new Vector2();
31673const _viewWorldMatrix = /*@__PURE__*/ new Matrix4();
31674
31675const _vA = /*@__PURE__*/ new Vector3();
31676const _vB = /*@__PURE__*/ new Vector3();
31677const _vC = /*@__PURE__*/ new Vector3();
31678
31679const _uvA = /*@__PURE__*/ new Vector2();
31680const _uvB = /*@__PURE__*/ new Vector2();
31681const _uvC = /*@__PURE__*/ new Vector2();
31682
31683class Sprite extends Object3D {
31684
31685	constructor( material = new SpriteMaterial() ) {
31686
31687		super();
31688
31689		this.isSprite = true;
31690
31691		this.type = 'Sprite';
31692
31693		if ( _geometry === undefined ) {
31694
31695			_geometry = new BufferGeometry();
31696
31697			const float32Array = new Float32Array( [
31698				- 0.5, - 0.5, 0, 0, 0,
31699				0.5, - 0.5, 0, 1, 0,
31700				0.5, 0.5, 0, 1, 1,
31701				- 0.5, 0.5, 0, 0, 1
31702			] );
31703
31704			const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
31705
31706			_geometry.setIndex( [ 0, 1, 2,	0, 2, 3 ] );
31707			_geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
31708			_geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
31709
31710		}
31711
31712		this.geometry = _geometry;
31713		this.material = material;
31714
31715		this.center = new Vector2( 0.5, 0.5 );
31716
31717	}
31718
31719	raycast( raycaster, intersects ) {
31720
31721		if ( raycaster.camera === null ) {
31722
31723			console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
31724
31725		}
31726
31727		_worldScale.setFromMatrixScale( this.matrixWorld );
31728
31729		_viewWorldMatrix.copy( raycaster.camera.matrixWorld );
31730		this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
31731
31732		_mvPosition.setFromMatrixPosition( this.modelViewMatrix );
31733
31734		if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
31735
31736			_worldScale.multiplyScalar( - _mvPosition.z );
31737
31738		}
31739
31740		const rotation = this.material.rotation;
31741		let sin, cos;
31742
31743		if ( rotation !== 0 ) {
31744
31745			cos = Math.cos( rotation );
31746			sin = Math.sin( rotation );
31747
31748		}
31749
31750		const center = this.center;
31751
31752		transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31753		transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31754		transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31755
31756		_uvA.set( 0, 0 );
31757		_uvB.set( 1, 0 );
31758		_uvC.set( 1, 1 );
31759
31760		// check first triangle
31761		let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );
31762
31763		if ( intersect === null ) {
31764
31765			// check second triangle
31766			transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31767			_uvB.set( 0, 1 );
31768
31769			intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );
31770			if ( intersect === null ) {
31771
31772				return;
31773
31774			}
31775
31776		}
31777
31778		const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
31779
31780		if ( distance < raycaster.near || distance > raycaster.far ) return;
31781
31782		intersects.push( {
31783
31784			distance: distance,
31785			point: _intersectPoint.clone(),
31786			uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),
31787			face: null,
31788			object: this
31789
31790		} );
31791
31792	}
31793
31794	copy( source, recursive ) {
31795
31796		super.copy( source, recursive );
31797
31798		if ( source.center !== undefined ) this.center.copy( source.center );
31799
31800		this.material = source.material;
31801
31802		return this;
31803
31804	}
31805
31806}
31807
31808function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
31809
31810	// compute position in camera space
31811	_alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
31812
31813	// to check if rotation is not zero
31814	if ( sin !== undefined ) {
31815
31816		_rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
31817		_rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
31818
31819	} else {
31820
31821		_rotatedPosition.copy( _alignedPosition );
31822
31823	}
31824
31825
31826	vertexPosition.copy( mvPosition );
31827	vertexPosition.x += _rotatedPosition.x;
31828	vertexPosition.y += _rotatedPosition.y;
31829
31830	// transform to world space
31831	vertexPosition.applyMatrix4( _viewWorldMatrix );
31832
31833}
31834
31835const _v1$2 = /*@__PURE__*/ new Vector3();
31836const _v2$1 = /*@__PURE__*/ new Vector3();
31837
31838class LOD extends Object3D {
31839
31840	constructor() {
31841
31842		super();
31843
31844		this._currentLevel = 0;
31845
31846		this.type = 'LOD';
31847
31848		Object.defineProperties( this, {
31849			levels: {
31850				enumerable: true,
31851				value: []
31852			},
31853			isLOD: {
31854				value: true,
31855			}
31856		} );
31857
31858		this.autoUpdate = true;
31859
31860	}
31861
31862	copy( source ) {
31863
31864		super.copy( source, false );
31865
31866		const levels = source.levels;
31867
31868		for ( let i = 0, l = levels.length; i < l; i ++ ) {
31869
31870			const level = levels[ i ];
31871
31872			this.addLevel( level.object.clone(), level.distance, level.hysteresis );
31873
31874		}
31875
31876		this.autoUpdate = source.autoUpdate;
31877
31878		return this;
31879
31880	}
31881
31882	addLevel( object, distance = 0, hysteresis = 0 ) {
31883
31884		distance = Math.abs( distance );
31885
31886		const levels = this.levels;
31887
31888		let l;
31889
31890		for ( l = 0; l < levels.length; l ++ ) {
31891
31892			if ( distance < levels[ l ].distance ) {
31893
31894				break;
31895
31896			}
31897
31898		}
31899
31900		levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );
31901
31902		this.add( object );
31903
31904		return this;
31905
31906	}
31907
31908	getCurrentLevel() {
31909
31910		return this._currentLevel;
31911
31912	}
31913
31914
31915
31916	getObjectForDistance( distance ) {
31917
31918		const levels = this.levels;
31919
31920		if ( levels.length > 0 ) {
31921
31922			let i, l;
31923
31924			for ( i = 1, l = levels.length; i < l; i ++ ) {
31925
31926				let levelDistance = levels[ i ].distance;
31927
31928				if ( levels[ i ].object.visible ) {
31929
31930					levelDistance -= levelDistance * levels[ i ].hysteresis;
31931
31932				}
31933
31934				if ( distance < levelDistance ) {
31935
31936					break;
31937
31938				}
31939
31940			}
31941
31942			return levels[ i - 1 ].object;
31943
31944		}
31945
31946		return null;
31947
31948	}
31949
31950	raycast( raycaster, intersects ) {
31951
31952		const levels = this.levels;
31953
31954		if ( levels.length > 0 ) {
31955
31956			_v1$2.setFromMatrixPosition( this.matrixWorld );
31957
31958			const distance = raycaster.ray.origin.distanceTo( _v1$2 );
31959
31960			this.getObjectForDistance( distance ).raycast( raycaster, intersects );
31961
31962		}
31963
31964	}
31965
31966	update( camera ) {
31967
31968		const levels = this.levels;
31969
31970		if ( levels.length > 1 ) {
31971
31972			_v1$2.setFromMatrixPosition( camera.matrixWorld );
31973			_v2$1.setFromMatrixPosition( this.matrixWorld );
31974
31975			const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom;
31976
31977			levels[ 0 ].object.visible = true;
31978
31979			let i, l;
31980
31981			for ( i = 1, l = levels.length; i < l; i ++ ) {
31982
31983				let levelDistance = levels[ i ].distance;
31984
31985				if ( levels[ i ].object.visible ) {
31986
31987					levelDistance -= levelDistance * levels[ i ].hysteresis;
31988
31989				}
31990
31991				if ( distance >= levelDistance ) {
31992
31993					levels[ i - 1 ].object.visible = false;
vendor: 4,383 bytes, lines 31994-32227
31994					levels[ i ].object.visible = true;
31995
31996				} else {
31997
31998					break;
31999
32000				}
32001
32002			}
32003
32004			this._currentLevel = i - 1;
32005
32006			for ( ; i < l; i ++ ) {
32007
32008				levels[ i ].object.visible = false;
32009
32010			}
32011
32012		}
32013
32014	}
32015
32016	toJSON( meta ) {
32017
32018		const data = super.toJSON( meta );
32019
32020		if ( this.autoUpdate === false ) data.object.autoUpdate = false;
32021
32022		data.object.levels = [];
32023
32024		const levels = this.levels;
32025
32026		for ( let i = 0, l = levels.length; i < l; i ++ ) {
32027
32028			const level = levels[ i ];
32029
32030			data.object.levels.push( {
32031				object: level.object.uuid,
32032				distance: level.distance,
32033				hysteresis: level.hysteresis
32034			} );
32035
32036		}
32037
32038		return data;
32039
32040	}
32041
32042}
32043
32044const _basePosition = /*@__PURE__*/ new Vector3();
32045
32046const _skinIndex = /*@__PURE__*/ new Vector4();
32047const _skinWeight = /*@__PURE__*/ new Vector4();
32048
32049const _vector3 = /*@__PURE__*/ new Vector3();
32050const _matrix4 = /*@__PURE__*/ new Matrix4();
32051const _vertex = /*@__PURE__*/ new Vector3();
32052
32053const _sphere$4 = /*@__PURE__*/ new Sphere();
32054const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();
32055const _ray$2 = /*@__PURE__*/ new Ray();
32056
32057class SkinnedMesh extends Mesh {
32058
32059	constructor( geometry, material ) {
32060
32061		super( geometry, material );
32062
32063		this.isSkinnedMesh = true;
32064
32065		this.type = 'SkinnedMesh';
32066
32067		this.bindMode = AttachedBindMode;
32068		this.bindMatrix = new Matrix4();
32069		this.bindMatrixInverse = new Matrix4();
32070
32071		this.boundingBox = null;
32072		this.boundingSphere = null;
32073
32074	}
32075
32076	computeBoundingBox() {
32077
32078		const geometry = this.geometry;
32079
32080		if ( this.boundingBox === null ) {
32081
32082			this.boundingBox = new Box3();
32083
32084		}
32085
32086		this.boundingBox.makeEmpty();
32087
32088		const positionAttribute = geometry.getAttribute( 'position' );
32089
32090		for ( let i = 0; i < positionAttribute.count; i ++ ) {
32091
32092			this.getVertexPosition( i, _vertex );
32093			this.boundingBox.expandByPoint( _vertex );
32094
32095		}
32096
32097	}
32098
32099	computeBoundingSphere() {
32100
32101		const geometry = this.geometry;
32102
32103		if ( this.boundingSphere === null ) {
32104
32105			this.boundingSphere = new Sphere();
32106
32107		}
32108
32109		this.boundingSphere.makeEmpty();
32110
32111		const positionAttribute = geometry.getAttribute( 'position' );
32112
32113		for ( let i = 0; i < positionAttribute.count; i ++ ) {
32114
32115			this.getVertexPosition( i, _vertex );
32116			this.boundingSphere.expandByPoint( _vertex );
32117
32118		}
32119
32120	}
32121
32122	copy( source, recursive ) {
32123
32124		super.copy( source, recursive );
32125
32126		this.bindMode = source.bindMode;
32127		this.bindMatrix.copy( source.bindMatrix );
32128		this.bindMatrixInverse.copy( source.bindMatrixInverse );
32129
32130		this.skeleton = source.skeleton;
32131
32132		if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32133		if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32134
32135		return this;
32136
32137	}
32138
32139	raycast( raycaster, intersects ) {
32140
32141		const material = this.material;
32142		const matrixWorld = this.matrixWorld;
32143
32144		if ( material === undefined ) return;
32145
32146		// test with bounding sphere in world space
32147
32148		if ( this.boundingSphere === null ) this.computeBoundingSphere();
32149
32150		_sphere$4.copy( this.boundingSphere );
32151		_sphere$4.applyMatrix4( matrixWorld );
32152
32153		if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return;
32154
32155		// convert ray to local space of skinned mesh
32156
32157		_inverseMatrix$2.copy( matrixWorld ).invert();
32158		_ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
32159
32160		// test with bounding box in local space
32161
32162		if ( this.boundingBox !== null ) {
32163
32164			if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return;
32165
32166		}
32167
32168		// test for intersections with geometry
32169
32170		this._computeIntersections( raycaster, intersects, _ray$2 );
32171
32172	}
32173
32174	getVertexPosition( index, target ) {
32175
32176		super.getVertexPosition( index, target );
32177
32178		this.applyBoneTransform( index, target );
32179
32180		return target;
32181
32182	}
32183
32184	bind( skeleton, bindMatrix ) {
32185
32186		this.skeleton = skeleton;
32187
32188		if ( bindMatrix === undefined ) {
32189
32190			this.updateMatrixWorld( true );
32191
32192			this.skeleton.calculateInverses();
32193
32194			bindMatrix = this.matrixWorld;
32195
32196		}
32197
32198		this.bindMatrix.copy( bindMatrix );
32199		this.bindMatrixInverse.copy( bindMatrix ).invert();
32200
32201	}
32202
32203	pose() {
32204
32205		this.skeleton.pose();
32206
32207	}
32208
32209	normalizeSkinWeights() {
32210
32211		const vector = new Vector4();
32212
32213		const skinWeight = this.geometry.attributes.skinWeight;
32214
32215		for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
32216
32217			vector.fromBufferAttribute( skinWeight, i );
32218
32219			const scale = 1.0 / vector.manhattanLength();
32220
32221			if ( scale !== Infinity ) {
32222
32223				vector.multiplyScalar( scale );
32224
32225			} else {
32226
32227				vector.set( 1, 0, 0, 0 );
vendor: 11,452 bytes, lines 32227-32822
32227 // do something reasonable
32228
32229			}
32230
32231			skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
32232
32233		}
32234
32235	}
32236
32237	updateMatrixWorld( force ) {
32238
32239		super.updateMatrixWorld( force );
32240
32241		if ( this.bindMode === AttachedBindMode ) {
32242
32243			this.bindMatrixInverse.copy( this.matrixWorld ).invert();
32244
32245		} else if ( this.bindMode === DetachedBindMode ) {
32246
32247			this.bindMatrixInverse.copy( this.bindMatrix ).invert();
32248
32249		} else {
32250
32251			console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
32252
32253		}
32254
32255	}
32256
32257	applyBoneTransform( index, vector ) {
32258
32259		const skeleton = this.skeleton;
32260		const geometry = this.geometry;
32261
32262		_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
32263		_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
32264
32265		_basePosition.copy( vector ).applyMatrix4( this.bindMatrix );
32266
32267		vector.set( 0, 0, 0 );
32268
32269		for ( let i = 0; i < 4; i ++ ) {
32270
32271			const weight = _skinWeight.getComponent( i );
32272
32273			if ( weight !== 0 ) {
32274
32275				const boneIndex = _skinIndex.getComponent( i );
32276
32277				_matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
32278
32279				vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );
32280
32281			}
32282
32283		}
32284
32285		return vector.applyMatrix4( this.bindMatrixInverse );
32286
32287	}
32288
32289	boneTransform( index, vector ) { // @deprecated, r151
32290
32291		console.warn( 'THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151.' );
32292		return this.applyBoneTransform( index, vector );
32293
32294	}
32295
32296
32297}
32298
32299class Bone extends Object3D {
32300
32301	constructor() {
32302
32303		super();
32304
32305		this.isBone = true;
32306
32307		this.type = 'Bone';
32308
32309	}
32310
32311}
32312
32313class DataTexture extends Texture {
32314
32315	constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) {
32316
32317		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
32318
32319		this.isDataTexture = true;
32320
32321		this.image = { data: data, width: width, height: height };
32322
32323		this.generateMipmaps = false;
32324		this.flipY = false;
32325		this.unpackAlignment = 1;
32326
32327	}
32328
32329}
32330
32331const _offsetMatrix = /*@__PURE__*/ new Matrix4();
32332const _identityMatrix$1 = /*@__PURE__*/ new Matrix4();
32333
32334class Skeleton {
32335
32336	constructor( bones = [], boneInverses = [] ) {
32337
32338		this.uuid = generateUUID();
32339
32340		this.bones = bones.slice( 0 );
32341		this.boneInverses = boneInverses;
32342		this.boneMatrices = null;
32343
32344		this.boneTexture = null;
32345
32346		this.init();
32347
32348	}
32349
32350	init() {
32351
32352		const bones = this.bones;
32353		const boneInverses = this.boneInverses;
32354
32355		this.boneMatrices = new Float32Array( bones.length * 16 );
32356
32357		// calculate inverse bone matrices if necessary
32358
32359		if ( boneInverses.length === 0 ) {
32360
32361			this.calculateInverses();
32362
32363		} else {
32364
32365			// handle special case
32366
32367			if ( bones.length !== boneInverses.length ) {
32368
32369				console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
32370
32371				this.boneInverses = [];
32372
32373				for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32374
32375					this.boneInverses.push( new Matrix4() );
32376
32377				}
32378
32379			}
32380
32381		}
32382
32383	}
32384
32385	calculateInverses() {
32386
32387		this.boneInverses.length = 0;
32388
32389		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32390
32391			const inverse = new Matrix4();
32392
32393			if ( this.bones[ i ] ) {
32394
32395				inverse.copy( this.bones[ i ].matrixWorld ).invert();
32396
32397			}
32398
32399			this.boneInverses.push( inverse );
32400
32401		}
32402
32403	}
32404
32405	pose() {
32406
32407		// recover the bind-time world matrices
32408
32409		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32410
32411			const bone = this.bones[ i ];
32412
32413			if ( bone ) {
32414
32415				bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
32416
32417			}
32418
32419		}
32420
32421		// compute the local matrices, positions, rotations and scales
32422
32423		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32424
32425			const bone = this.bones[ i ];
32426
32427			if ( bone ) {
32428
32429				if ( bone.parent && bone.parent.isBone ) {
32430
32431					bone.matrix.copy( bone.parent.matrixWorld ).invert();
32432					bone.matrix.multiply( bone.matrixWorld );
32433
32434				} else {
32435
32436					bone.matrix.copy( bone.matrixWorld );
32437
32438				}
32439
32440				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
32441
32442			}
32443
32444		}
32445
32446	}
32447
32448	update() {
32449
32450		const bones = this.bones;
32451		const boneInverses = this.boneInverses;
32452		const boneMatrices = this.boneMatrices;
32453		const boneTexture = this.boneTexture;
32454
32455		// flatten bone matrices to array
32456
32457		for ( let i = 0, il = bones.length; i < il; i ++ ) {
32458
32459			// compute the offset between the current and the original transform
32460
32461			const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1;
32462
32463			_offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
32464			_offsetMatrix.toArray( boneMatrices, i * 16 );
32465
32466		}
32467
32468		if ( boneTexture !== null ) {
32469
32470			boneTexture.needsUpdate = true;
32471
32472		}
32473
32474	}
32475
32476	clone() {
32477
32478		return new Skeleton( this.bones, this.boneInverses );
32479
32480	}
32481
32482	computeBoneTexture() {
32483
32484		// layout (1 matrix = 4 pixels)
32485		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
32486		//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
32487		//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
32488		//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
32489		//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
32490
32491		let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
32492		size = Math.ceil( size / 4 ) * 4;
32493		size = Math.max( size, 4 );
32494
32495		const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
32496		boneMatrices.set( this.boneMatrices ); // copy current values
32497
32498		const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
32499		boneTexture.needsUpdate = true;
32500
32501		this.boneMatrices = boneMatrices;
32502		this.boneTexture = boneTexture;
32503
32504		return this;
32505
32506	}
32507
32508	getBoneByName( name ) {
32509
32510		for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32511
32512			const bone = this.bones[ i ];
32513
32514			if ( bone.name === name ) {
32515
32516				return bone;
32517
32518			}
32519
32520		}
32521
32522		return undefined;
32523
32524	}
32525
32526	dispose( ) {
32527
32528		if ( this.boneTexture !== null ) {
32529
32530			this.boneTexture.dispose();
32531
32532			this.boneTexture = null;
32533
32534		}
32535
32536	}
32537
32538	fromJSON( json, bones ) {
32539
32540		this.uuid = json.uuid;
32541
32542		for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
32543
32544			const uuid = json.bones[ i ];
32545			let bone = bones[ uuid ];
32546
32547			if ( bone === undefined ) {
32548
32549				console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
32550				bone = new Bone();
32551
32552			}
32553
32554			this.bones.push( bone );
32555			this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
32556
32557		}
32558
32559		this.init();
32560
32561		return this;
32562
32563	}
32564
32565	toJSON() {
32566
32567		const data = {
32568			metadata: {
32569				version: 4.6,
32570				type: 'Skeleton',
32571				generator: 'Skeleton.toJSON'
32572			},
32573			bones: [],
32574			boneInverses: []
32575		};
32576
32577		data.uuid = this.uuid;
32578
32579		const bones = this.bones;
32580		const boneInverses = this.boneInverses;
32581
32582		for ( let i = 0, l = bones.length; i < l; i ++ ) {
32583
32584			const bone = bones[ i ];
32585			data.bones.push( bone.uuid );
32586
32587			const boneInverse = boneInverses[ i ];
32588			data.boneInverses.push( boneInverse.toArray() );
32589
32590		}
32591
32592		return data;
32593
32594	}
32595
32596}
32597
32598class InstancedBufferAttribute extends BufferAttribute {
32599
32600	constructor( array, itemSize, normalized, meshPerAttribute = 1 ) {
32601
32602		super( array, itemSize, normalized );
32603
32604		this.isInstancedBufferAttribute = true;
32605
32606		this.meshPerAttribute = meshPerAttribute;
32607
32608	}
32609
32610	copy( source ) {
32611
32612		super.copy( source );
32613
32614		this.meshPerAttribute = source.meshPerAttribute;
32615
32616		return this;
32617
32618	}
32619
32620	toJSON() {
32621
32622		const data = super.toJSON();
32623
32624		data.meshPerAttribute = this.meshPerAttribute;
32625
32626		data.isInstancedBufferAttribute = true;
32627
32628		return data;
32629
32630	}
32631
32632}
32633
32634const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();
32635const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();
32636
32637const _instanceIntersects = [];
32638
32639const _box3 = /*@__PURE__*/ new Box3();
32640const _identity = /*@__PURE__*/ new Matrix4();
32641const _mesh$1 = /*@__PURE__*/ new Mesh();
32642const _sphere$3 = /*@__PURE__*/ new Sphere();
32643
32644class InstancedMesh extends Mesh {
32645
32646	constructor( geometry, material, count ) {
32647
32648		super( geometry, material );
32649
32650		this.isInstancedMesh = true;
32651
32652		this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );
32653		this.instanceColor = null;
32654
32655		this.count = count;
32656
32657		this.boundingBox = null;
32658		this.boundingSphere = null;
32659
32660		for ( let i = 0; i < count; i ++ ) {
32661
32662			this.setMatrixAt( i, _identity );
32663
32664		}
32665
32666	}
32667
32668	computeBoundingBox() {
32669
32670		const geometry = this.geometry;
32671		const count = this.count;
32672
32673		if ( this.boundingBox === null ) {
32674
32675			this.boundingBox = new Box3();
32676
32677		}
32678
32679		if ( geometry.boundingBox === null ) {
32680
32681			geometry.computeBoundingBox();
32682
32683		}
32684
32685		this.boundingBox.makeEmpty();
32686
32687		for ( let i = 0; i < count; i ++ ) {
32688
32689			this.getMatrixAt( i, _instanceLocalMatrix );
32690
32691			_box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );
32692
32693			this.boundingBox.union( _box3 );
32694
32695		}
32696
32697	}
32698
32699	computeBoundingSphere() {
32700
32701		const geometry = this.geometry;
32702		const count = this.count;
32703
32704		if ( this.boundingSphere === null ) {
32705
32706			this.boundingSphere = new Sphere();
32707
32708		}
32709
32710		if ( geometry.boundingSphere === null ) {
32711
32712			geometry.computeBoundingSphere();
32713
32714		}
32715
32716		this.boundingSphere.makeEmpty();
32717
32718		for ( let i = 0; i < count; i ++ ) {
32719
32720			this.getMatrixAt( i, _instanceLocalMatrix );
32721
32722			_sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );
32723
32724			this.boundingSphere.union( _sphere$3 );
32725
32726		}
32727
32728	}
32729
32730	copy( source, recursive ) {
32731
32732		super.copy( source, recursive );
32733
32734		this.instanceMatrix.copy( source.instanceMatrix );
32735
32736		if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
32737
32738		this.count = source.count;
32739
32740		if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32741		if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32742
32743		return this;
32744
32745	}
32746
32747	getColorAt( index, color ) {
32748
32749		color.fromArray( this.instanceColor.array, index * 3 );
32750
32751	}
32752
32753	getMatrixAt( index, matrix ) {
32754
32755		matrix.fromArray( this.instanceMatrix.array, index * 16 );
32756
32757	}
32758
32759	raycast( raycaster, intersects ) {
32760
32761		const matrixWorld = this.matrixWorld;
32762		const raycastTimes = this.count;
32763
32764		_mesh$1.geometry = this.geometry;
32765		_mesh$1.material = this.material;
32766
32767		if ( _mesh$1.material === undefined ) return;
32768
32769		// test with bounding sphere first
32770
32771		if ( this.boundingSphere === null ) this.computeBoundingSphere();
32772
32773		_sphere$3.copy( this.boundingSphere );
32774		_sphere$3.applyMatrix4( matrixWorld );
32775
32776		if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
32777
32778		// now test each instance
32779
32780		for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
32781
32782			// calculate the world matrix for each instance
32783
32784			this.getMatrixAt( instanceId, _instanceLocalMatrix );
32785
32786			_instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
32787
32788			// the mesh represents this single instance
32789
32790			_mesh$1.matrixWorld = _instanceWorldMatrix;
32791
32792			_mesh$1.raycast( raycaster, _instanceIntersects );
32793
32794			// process the result of raycast
32795
32796			for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
32797
32798				const intersect = _instanceIntersects[ i ];
32799				intersect.instanceId = instanceId;
32800				intersect.object = this;
32801				intersects.push( intersect );
32802
32803			}
32804
32805			_instanceIntersects.length = 0;
32806
32807		}
32808
32809	}
32810
32811	setColorAt( index, color ) {
32812
32813		if ( this.instanceColor === null ) {
32814
32815			this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 );
32816
32817		}
32818
32819		color.toArray( this.instanceColor.array, index * 3 );
32820
32821	}
32822
32823	setMatrixAt( index, matrix ) {
32824
32825		matrix.toArray( this.instanceMatrix.array, index * 16 );
32826
32827	}
32828
32829	updateMorphTargets() {
32830
32831	}
32832
32833	dispose() {
32834
32835		this.dispatchEvent( { type: 'dispose' } );
32836
32837	}
32838
32839}
32840
32841function sortOpaque( a, b ) {
32842
32843	return a.z - b.z;
32844
32845}
32846
32847function sortTransparent( a, b ) {
32848
32849	return b.z - a.z;
32850
32851}
32852
32853class MultiDrawRenderList {
32854
32855	constructor() {
32856
32857		this.index = 0;
32858		this.pool = [];
32859		this.list = [];
32860
32861	}
32862
32863	push( drawRange, z ) {
32864
32865		const pool = this.pool;
32866		const list = this.list;
32867		if ( this.index >= pool.length ) {
32868
32869			pool.push( {
32870
32871				start: - 1,
32872				count: - 1,
32873				z: - 1,
32874
32875			} );
32876
32877		}
32878
32879		const item = pool[ this.index ];
32880		list.push( item );
32881		this.index ++;
32882
32883		item.start = drawRange.start;
32884		item.count = drawRange.count;
32885		item.z = z;
32886
32887	}
32888
32889	reset() {
32890
32891		this.list.length = 0;
32892		this.index = 0;
32893
32894	}
32895
32896}
32897
32898const ID_ATTR_NAME = 'batchId';
32899const _matrix = /*@__PURE__*/ new Matrix4();
32900const _invMatrixWorld = /*@__PURE__*/ new Matrix4();
32901const _identityMatrix = /*@__PURE__*/ new Matrix4();
32902const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4();
32903const _frustum = /*@__PURE__*/ new Frustum();
32904const _box$1 = /*@__PURE__*/ new Box3();
32905const _sphere$2 = /*@__PURE__*/ new Sphere();
32906const _vector$5 = /*@__PURE__*/ new Vector3();
32907const _renderList = /*@__PURE__*/ new MultiDrawRenderList();
32908const _mesh = /*@__PURE__*/ new Mesh();
32909const _batchIntersects = [];
32910
32911// @TODO: SkinnedMesh support?
32912// @TODO: geometry.groups support?
32913// @TODO: geometry.drawRange support?
32914// @TODO: geometry.morphAttributes support?
32915// @TODO: Support uniform parameter per geometry
32916// @TODO: Add an "optimize" function to pack geometry and remove data gaps
32917
32918// copies data from attribute "src" into "target" starting at "targetOffset"
32919function copyAttributeData( src, target, targetOffset = 0 ) {
32920
32921	const itemSize = target.itemSize;
32922	if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {
32923
32924		// use the component getters and setters if the array data cannot
32925		// be copied directly
32926		const vertexCount = src.count;
32927		for ( let i = 0; i < vertexCount; i ++ ) {
32928
32929			for ( let c = 0; c < itemSize; c ++ ) {
32930
32931				target.setComponent( i + targetOffset, c, src.getComponent( i, c ) );
32932
32933			}
32934
32935		}
32936
32937	} else {
32938
32939		// faster copy approach using typed array set function
32940		target.array.set( src.array, targetOffset * itemSize );
32941
32942	}
32943
32944	target.needsUpdate = true;
32945
32946}
32947
32948class BatchedMesh extends Mesh {
32949
32950	get maxGeometryCount() {
32951
32952		return this._maxGeometryCount;
32953
32954	}
32955
32956	constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {
32957
32958		super( new BufferGeometry(), material );
32959
32960		this.isBatchedMesh = true;
32961		this.perObjectFrustumCulled = true;
32962		this.sortObjects = true;
32963		this.boundingBox = null;
32964		this.boundingSphere = null;
32965		this.customSort = null;
32966
32967		this._drawRanges = [];
32968		this._reservedRanges = [];
32969
32970		this._visibility = [];
32971		this._active = [];
32972		this._bounds = [];
32973
32974		this._maxGeometryCount = maxGeometryCount;
32975		this._maxVertexCount = maxVertexCount;
32976		this._maxIndexCount = maxIndexCount;
32977
32978		this._geometryInitialized = false;
32979		this._geometryCount = 0;
32980		this._multiDrawCounts = new Int32Array( maxGeometryCount );
32981		this._multiDrawStarts = new Int32Array( maxGeometryCount );
32982		this._multiDrawCount = 0;
32983		this._visibilityChanged = true;
32984
32985		// Local matrix per geometry by using data texture
32986		this._matricesTexture = null;
32987
32988		this._initMatricesTexture();
32989
32990	}
32991
32992	_initMatricesTexture() {
32993
32994		// layout (1 matrix = 4 pixels)
32995		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
32996		//  with  8x8  pixel texture max   16 matrices * 4 pixels =  (8 * 8)
32997		//       16x16 pixel texture max   64 matrices * 4 pixels = (16 * 16)
32998		//       32x32 pixel texture max  256 matrices * 4 pixels = (32 * 32)
32999		//       64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)
33000
33001		let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
33002		size = Math.ceil( size / 4 ) * 4;
33003		size = Math.max( size, 4 );
33004
33005		const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
33006		const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );
33007
33008		this._matricesTexture = matricesTexture;
33009
33010	}
33011
33012	_initializeGeometry( reference ) {
33013
33014		const geometry = this.geometry;
33015		const maxVertexCount = this._maxVertexCount;
33016		const maxGeometryCount = this._maxGeometryCount;
33017		const maxIndexCount = this._maxIndexCount;
33018		if ( this._geometryInitialized === false ) {
33019
33020			for ( const attributeName in reference.attributes ) {
33021
33022				const srcAttribute = reference.getAttribute( attributeName );
33023				const { array, itemSize, normalized } = srcAttribute;
33024
33025				const dstArray = new array.constructor( maxVertexCount * itemSize );
33026				const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized );
33027				dstAttribute.setUsage( srcAttribute.usage );
33028
33029				geometry.setAttribute( attributeName, dstAttribute );
33030
33031			}
33032
33033			if ( reference.getIndex() !== null ) {
33034
33035				const indexArray = maxVertexCount > 65536
33036					? new Uint32Array( maxIndexCount )
33037					: new Uint16Array( maxIndexCount );
33038
33039				geometry.setIndex( new BufferAttribute( indexArray, 1 ) );
33040
33041			}
33042
33043			const idArray = maxGeometryCount > 65536
33044				? new Uint32Array( maxVertexCount )
33045				: new Uint16Array( maxVertexCount );
33046			geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );
33047
33048			this._geometryInitialized = true;
33049
33050		}
33051
33052	}
33053
33054	// Make sure the geometry is compatible with the existing combined geometry atributes
33055	_validateGeometry( geometry ) {
33056
33057		// check that the geometry doesn't have a version of our reserved id attribute
33058		if ( geometry.getAttribute( ID_ATTR_NAME ) ) {
33059
33060			throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` );
33061
33062		}
33063
33064		// check to ensure the geometries are using consistent attributes and indices
33065		const batchGeometry = this.geometry;
33066		if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {
33067
33068			throw new Error( 'BatchedMesh: All geometries must consistently have "index".' );
33069
33070		}
33071
33072		for ( const attributeName in batchGeometry.attributes ) {
33073
33074			if ( attributeName === ID_ATTR_NAME ) {
33075
33076				continue;
33077
33078			}
33079
33080			if ( ! geometry.hasAttribute( attributeName ) ) {
33081
33082				throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );
33083
33084			}
33085
33086			const srcAttribute = geometry.getAttribute( attributeName );
33087			const dstAttribute = batchGeometry.getAttribute( attributeName );
33088			if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {
33089
33090				throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );
33091
33092			}
33093
33094		}
33095
33096	}
33097
33098	setCustomSort( func ) {
33099
33100		this.customSort = func;
33101		return this;
33102
33103	}
33104
33105	computeBoundingBox() {
33106
33107		if ( this.boundingBox === null ) {
33108
33109			this.boundingBox = new Box3();
33110
33111		}
33112
33113		const geometryCount = this._geometryCount;
33114		const boundingBox = this.boundingBox;
33115		const active = this._active;
33116
33117		boundingBox.makeEmpty();
33118		for ( let i = 0; i < geometryCount; i ++ ) {
33119
33120			if ( active[ i ] === false ) continue;
33121
33122			this.getMatrixAt( i, _matrix );
33123			this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix );
33124			boundingBox.union( _box$1 );
33125
33126		}
33127
33128	}
33129
33130	computeBoundingSphere() {
33131
33132		if ( this.boundingSphere === null ) {
33133
33134			this.boundingSphere = new Sphere();
33135
33136		}
33137
33138		const geometryCount = this._geometryCount;
33139		const boundingSphere = this.boundingSphere;
33140		const active = this._active;
33141
33142		boundingSphere.makeEmpty();
33143		for ( let i = 0; i < geometryCount; i ++ ) {
33144
33145			if ( active[ i ] === false ) continue;
33146
33147			this.getMatrixAt( i, _matrix );
33148			this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33149			boundingSphere.union( _sphere$2 );
33150
33151		}
33152
33153	}
33154
33155	addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {
33156
33157		this._initializeGeometry( geometry );
33158
33159		this._validateGeometry( geometry );
33160
33161		// ensure we're not over geometry
33162		if ( this._geometryCount >= this._maxGeometryCount ) {
33163
33164			throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33165
33166		}
33167
33168		// get the necessary range fo the geometry
33169		const reservedRange = {
33170			vertexStart: - 1,
33171			vertexCount: - 1,
33172			indexStart: - 1,
33173			indexCount: - 1,
33174		};
33175
33176		let lastRange = null;
33177		const reservedRanges = this._reservedRanges;
33178		const drawRanges = this._drawRanges;
33179		const bounds = this._bounds;
33180		if ( this._geometryCount !== 0 ) {
33181
33182			lastRange = reservedRanges[ reservedRanges.length - 1 ];
33183
33184		}
33185
33186		if ( vertexCount === - 1 ) {
33187
33188			reservedRange.vertexCount = geometry.getAttribute( 'position' ).count;
33189
33190		} else {
33191
33192			reservedRange.vertexCount = vertexCount;
33193
33194		}
33195
33196		if ( lastRange === null ) {
33197
33198			reservedRange.vertexStart = 0;
33199
33200		} else {
33201
33202			reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;
33203
33204		}
33205
33206		const index = geometry.getIndex();
33207		const hasIndex = index !== null;
33208		if ( hasIndex ) {
33209
33210			if ( indexCount	=== - 1 ) {
33211
33212				reservedRange.indexCount = index.count;
33213
33214			} else {
33215
33216				reservedRange.indexCount = indexCount;
33217
33218			}
33219
33220			if ( lastRange === null ) {
33221
33222				reservedRange.indexStart = 0;
33223
33224			} else {
33225
33226				reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;
33227
33228			}
33229
33230		}
33231
33232		if (
33233			reservedRange.indexStart !== - 1 &&
33234			reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||
33235			reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount
33236		) {
33237
33238			throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );
33239
33240		}
33241
33242		const visibility = this._visibility;
33243		const active = this._active;
33244		const matricesTexture = this._matricesTexture;
33245		const matricesArray = this._matricesTexture.image.data;
33246
33247		// push new visibility states
33248		visibility.push( true );
33249		active.push( true );
33250
33251		// update id
33252		const geometryId = this._geometryCount;
33253		this._geometryCount ++;
33254
33255		// initialize matrix information
33256		_identityMatrix.toArray( matricesArray, geometryId * 16 );
33257		matricesTexture.needsUpdate = true;
33258
33259		// add the reserved range and draw range objects
33260		reservedRanges.push( reservedRange );
33261		drawRanges.push( {
33262			start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,
33263			count: - 1
33264		} );
33265		bounds.push( {
33266			boxInitialized: false,
33267			box: new Box3(),
33268
33269			sphereInitialized: false,
33270			sphere: new Sphere()
33271		} );
33272
33273		// set the id for the geometry
33274		const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME );
33275		for ( let i = 0; i < reservedRange.vertexCount; i ++ ) {
33276
33277			idAttribute.setX( reservedRange.vertexStart + i, geometryId );
33278
33279		}
33280
33281		idAttribute.needsUpdate = true;
33282
33283		// update the geometry
33284		this.setGeometryAt( geometryId, geometry );
33285
33286		return geometryId;
33287
33288	}
33289
33290	setGeometryAt( id, geometry ) {
33291
33292		if ( id >= this._geometryCount ) {
33293
33294			throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33295
33296		}
33297
33298		this._validateGeometry( geometry );
33299
33300		const batchGeometry = this.geometry;
33301		const hasIndex = batchGeometry.getIndex() !== null;
33302		const dstIndex = batchGeometry.getIndex();
33303		const srcIndex = geometry.getIndex();
33304		const reservedRange = this._reservedRanges[ id ];
33305		if (
33306			hasIndex &&
33307			srcIndex.count > reservedRange.indexCount ||
33308			geometry.attributes.position.count > reservedRange.vertexCount
33309		) {
33310
33311			throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );
33312
33313		}
33314
33315		// copy geometry over
33316		const vertexStart = reservedRange.vertexStart;
33317		const vertexCount = reservedRange.vertexCount;
33318		for ( const attributeName in batchGeometry.attributes ) {
33319
33320			if ( attributeName === ID_ATTR_NAME ) {
33321
33322				continue;
33323
33324			}
33325
33326			// copy attribute data
33327			const srcAttribute = geometry.getAttribute( attributeName );
33328			const dstAttribute = batchGeometry.getAttribute( attributeName );
33329			copyAttributeData( srcAttribute, dstAttribute, vertexStart );
33330
33331			// fill the rest in with zeroes
33332			const itemSize = srcAttribute.itemSize;
33333			for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {
33334
33335				const index = vertexStart + i;
33336				for ( let c = 0; c < itemSize; c ++ ) {
33337
33338					dstAttribute.setComponent( index, c, 0 );
33339
33340				}
33341
33342			}
33343
33344			dstAttribute.needsUpdate = true;
33345
33346		}
33347
33348		// copy index
33349		if ( hasIndex ) {
33350
33351			const indexStart = reservedRange.indexStart;
33352
33353			// copy index data over
33354			for ( let i = 0; i < srcIndex.count; i ++ ) {
33355
33356				dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );
33357
33358			}
33359
33360			// fill the rest in with zeroes
33361			for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {
33362
33363				dstIndex.setX( indexStart + i, vertexStart );
33364
33365			}
33366
33367			dstIndex.needsUpdate = true;
33368
33369		}
33370
33371		// store the bounding boxes
33372		const bound = this._bounds[ id ];
33373		if ( geometry.boundingBox !== null ) {
33374
33375			bound.box.copy( geometry.boundingBox );
33376			bound.boxInitialized = true;
33377
33378		} else {
33379
33380			bound.boxInitialized = false;
33381
33382		}
33383
33384		if ( geometry.boundingSphere !== null ) {
33385
33386			bound.sphere.copy( geometry.boundingSphere );
33387			bound.sphereInitialized = true;
33388
33389		} else {
33390
33391			bound.sphereInitialized = false;
33392
33393		}
33394
33395		// set drawRange count
33396		const drawRange = this._drawRanges[ id ];
33397		const posAttr = geometry.getAttribute( 'position' );
33398		drawRange.count = hasIndex ? srcIndex.count : posAttr.count;
33399		this._visibilityChanged = true;
33400
33401		return id;
33402
33403	}
33404
33405	deleteGeometry( geometryId ) {
33406
33407		// Note: User needs to call optimize() afterward to pack the data.
33408
33409		const active = this._active;
33410		if ( geometryId >= active.length || active[ geometryId ] === false ) {
33411
33412			return this;
33413
33414		}
33415
33416		active[ geometryId ] = false;
33417		this._visibilityChanged = true;
33418
33419		return this;
33420
33421	}
33422
33423	// get bounding box and compute it if it doesn't exist
33424	getBoundingBoxAt( id, target ) {
33425
33426		const active = this._active;
33427		if ( active[ id ] === false ) {
33428
33429			return this;
33430
33431		}
33432
33433		// compute bounding box
33434		const bound = this._bounds[ id ];
33435		const box = bound.box;
33436		const geometry = this.geometry;
33437		if ( bound.boxInitialized === false ) {
33438
33439			box.makeEmpty();
33440
33441			const index = geometry.index;
33442			const position = geometry.attributes.position;
33443			const drawRange = this._drawRanges[ id ];
33444			for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33445
33446				let iv = i;
33447				if ( index ) {
33448
33449					iv = index.getX( iv );
33450
33451				}
33452
33453				box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) );
33454
33455			}
33456
33457			bound.boxInitialized = true;
33458
33459		}
33460
33461		target.copy( box );
33462		return target;
33463
33464	}
33465
33466	// get bounding sphere and compute it if it doesn't exist
33467	getBoundingSphereAt( id, target ) {
33468
33469		const active = this._active;
33470		if ( active[ id ] === false ) {
33471
33472			return this;
33473
33474		}
33475
33476		// compute bounding sphere
33477		const bound = this._bounds[ id ];
33478		const sphere = bound.sphere;
33479		const geometry = this.geometry;
33480		if ( bound.sphereInitialized === false ) {
33481
33482			sphere.makeEmpty();
33483
33484			this.getBoundingBoxAt( id, _box$1 );
33485			_box$1.getCenter( sphere.center );
33486
33487			const index = geometry.index;
33488			const position = geometry.attributes.position;
33489			const drawRange = this._drawRanges[ id ];
33490
33491			let maxRadiusSq = 0;
33492			for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33493
33494				let iv = i;
33495				if ( index ) {
33496
33497					iv = index.getX( iv );
33498
33499				}
33500
33501				_vector$5.fromBufferAttribute( position, iv );
33502				maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) );
33503
33504			}
33505
33506			sphere.radius = Math.sqrt( maxRadiusSq );
33507			bound.sphereInitialized = true;
33508
33509		}
33510
33511		target.copy( sphere );
33512		return target;
33513
33514	}
33515
33516	setMatrixAt( geometryId, matrix ) {
33517
33518		// @TODO: Map geometryId to index of the arrays because
33519		//        optimize() can make geometryId mismatch the index
33520
33521		const active = this._active;
33522		const matricesTexture = this._matricesTexture;
33523		const matricesArray = this._matricesTexture.image.data;
33524		const geometryCount = this._geometryCount;
33525		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33526
33527			return this;
33528
33529		}
33530
33531		matrix.toArray( matricesArray, geometryId * 16 );
33532		matricesTexture.needsUpdate = true;
33533
33534		return this;
33535
33536	}
33537
33538	getMatrixAt( geometryId, matrix ) {
33539
33540		const active = this._active;
33541		const matricesArray = this._matricesTexture.image.data;
33542		const geometryCount = this._geometryCount;
33543		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33544
33545			return null;
33546
33547		}
33548
33549		return matrix.fromArray( matricesArray, geometryId * 16 );
33550
33551	}
33552
33553	setVisibleAt( geometryId, value ) {
33554
33555		const visibility = this._visibility;
33556		const active = this._active;
33557		const geometryCount = this._geometryCount;
33558
33559		// if the geometry is out of range, not active, or visibility state
33560		// does not change then return early
33561		if (
33562			geometryId >= geometryCount ||
33563			active[ geometryId ] === false ||
33564			visibility[ geometryId ] === value
33565		) {
33566
33567			return this;
33568
33569		}
33570
33571		visibility[ geometryId ] = value;
33572		this._visibilityChanged = true;
33573
33574		return this;
33575
33576	}
33577
33578	getVisibleAt( geometryId ) {
33579
33580		const visibility = this._visibility;
33581		const active = this._active;
33582		const geometryCount = this._geometryCount;
33583
33584		// return early if the geometry is out of range or not active
33585		if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33586
33587			return false;
33588
33589		}
33590
33591		return visibility[ geometryId ];
33592
33593	}
33594
33595	raycast( raycaster, intersects ) {
33596
33597		const visibility = this._visibility;
33598		const active = this._active;
33599		const drawRanges = this._drawRanges;
33600		const geometryCount = this._geometryCount;
33601		const matrixWorld = this.matrixWorld;
33602		const batchGeometry = this.geometry;
33603
33604		// iterate over each geometry
33605		_mesh.material = this.material;
33606		_mesh.geometry.index = batchGeometry.index;
33607		_mesh.geometry.attributes = batchGeometry.attributes;
33608		if ( _mesh.geometry.boundingBox === null ) {
33609
33610			_mesh.geometry.boundingBox = new Box3();
33611
33612		}
33613
33614		if ( _mesh.geometry.boundingSphere === null ) {
33615
33616			_mesh.geometry.boundingSphere = new Sphere();
33617
33618		}
33619
33620		for ( let i = 0; i < geometryCount; i ++ ) {
33621
33622			if ( ! visibility[ i ] || ! active[ i ] ) {
33623
33624				continue;
33625
33626			}
33627
33628			const drawRange = drawRanges[ i ];
33629			_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );
33630
33631			// ge the intersects
33632			this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );
33633			this.getBoundingBoxAt( i, _mesh.geometry.boundingBox );
33634			this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere );
33635			_mesh.raycast( raycaster, _batchIntersects );
33636
33637			// add batch id to the intersects
33638			for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {
33639
33640				const intersect = _batchIntersects[ j ];
33641				intersect.object = this;
33642				intersect.batchId = i;
33643				intersects.push( intersect );
33644
33645			}
33646
33647			_batchIntersects.length = 0;
33648
33649		}
33650
33651		_mesh.material = null;
33652		_mesh.geometry.index = null;
33653		_mesh.geometry.attributes = {};
33654		_mesh.geometry.setDrawRange( 0, Infinity );
33655
33656	}
33657
33658	copy( source ) {
33659
33660		super.copy( source );
33661
33662		this.geometry = source.geometry.clone();
33663		this.perObjectFrustumCulled = source.perObjectFrustumCulled;
33664		this.sortObjects = source.sortObjects;
33665		this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
33666		this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
33667
33668		this._drawRanges = source._drawRanges.map( range => ( { ...range } ) );
33669		this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );
33670
33671		this._visibility = source._visibility.slice();
33672		this._active = source._active.slice();
33673		this._bounds = source._bounds.map( bound => ( {
33674			boxInitialized: bound.boxInitialized,
33675			box: bound.box.clone(),
33676
33677			sphereInitialized: bound.sphereInitialized,
33678			sphere: bound.sphere.clone()
33679		} ) );
33680
33681		this._maxGeometryCount = source._maxGeometryCount;
33682		this._maxVertexCount = source._maxVertexCount;
33683		this._maxIndexCount = source._maxIndexCount;
33684
33685		this._geometryInitialized = source._geometryInitialized;
33686		this._geometryCount = source._geometryCount;
33687		this._multiDrawCounts = source._multiDrawCounts.slice();
33688		this._multiDrawStarts = source._multiDrawStarts.slice();
33689
33690		this._matricesTexture = source._matricesTexture.clone();
33691		this._matricesTexture.image.data = this._matricesTexture.image.slice();
33692
33693		return this;
33694
33695	}
33696
33697	dispose() {
33698
33699		// Assuming the geometry is not shared with other meshes
33700		this.geometry.dispose();
33701
33702		this._matricesTexture.dispose();
33703		this._matricesTexture = null;
33704		return this;
33705
33706	}
33707
33708	onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {
33709
33710		// if visibility has not changed and frustum culling and object sorting is not required
33711		// then skip iterating over all items
33712		if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {
33713
33714			return;
33715
33716		}
33717
33718		// the indexed version of the multi draw function requires specifying the start
33719		// offset in bytes.
33720		const index = geometry.getIndex();
33721		const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;
33722
33723		const visibility = this._visibility;
33724		const multiDrawStarts = this._multiDrawStarts;
33725		const multiDrawCounts = this._multiDrawCounts;
33726		const drawRanges = this._drawRanges;
33727		const perObjectFrustumCulled = this.perObjectFrustumCulled;
33728
33729		// prepare the frustum in the local frame
33730		if ( perObjectFrustumCulled ) {
33731
33732			_projScreenMatrix$2
33733				.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )
33734				.multiply( this.matrixWorld );
33735			_frustum.setFromProjectionMatrix(
33736				_projScreenMatrix$2,
33737				renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem
33738			);
33739
33740		}
33741
33742		let count = 0;
33743		if ( this.sortObjects ) {
33744
33745			// get the camera position in the local frame
33746			_invMatrixWorld.copy( this.matrixWorld ).invert();
33747			_vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );
33748
33749			for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33750
33751				if ( visibility[ i ] ) {
33752
33753					// get the bounds in world space
33754					this.getMatrixAt( i, _matrix );
33755					this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33756
33757					// determine whether the batched geometry is within the frustum
vendor: 13,526 bytes, lines 33758-34378
33758					let culled = false;
33759					if ( perObjectFrustumCulled ) {
33760
33761						culled = ! _frustum.intersectsSphere( _sphere$2 );
33762
33763					}
33764
33765					if ( ! culled ) {
33766
33767						// get the distance from camera used for sorting
33768						const z = _vector$5.distanceTo( _sphere$2.center );
33769						_renderList.push( drawRanges[ i ], z );
33770
33771					}
33772
33773				}
33774
33775			}
33776
33777			// Sort the draw ranges and prep for rendering
33778			const list = _renderList.list;
33779			const customSort = this.customSort;
33780			if ( customSort === null ) {
33781
33782				list.sort( material.transparent ? sortTransparent : sortOpaque );
33783
33784			} else {
33785
33786				customSort.call( this, list, camera );
33787
33788			}
33789
33790			for ( let i = 0, l = list.length; i < l; i ++ ) {
33791
33792				const item = list[ i ];
33793				multiDrawStarts[ count ] = item.start * bytesPerElement;
33794				multiDrawCounts[ count ] = item.count;
33795				count ++;
33796
33797			}
33798
33799			_renderList.reset();
33800
33801		} else {
33802
33803			for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33804
33805				if ( visibility[ i ] ) {
33806
33807					// determine whether the batched geometry is within the frustum
33808					let culled = false;
33809					if ( perObjectFrustumCulled ) {
33810
33811						// get the bounds in world space
33812						this.getMatrixAt( i, _matrix );
33813						this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33814						culled = ! _frustum.intersectsSphere( _sphere$2 );
33815
33816					}
33817
33818					if ( ! culled ) {
33819
33820						const range = drawRanges[ i ];
33821						multiDrawStarts[ count ] = range.start * bytesPerElement;
33822						multiDrawCounts[ count ] = range.count;
33823						count ++;
33824
33825					}
33826
33827				}
33828
33829			}
33830
33831		}
33832
33833		this._multiDrawCount = count;
33834		this._visibilityChanged = false;
33835
33836	}
33837
33838	onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {
33839
33840		this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );
33841
33842	}
33843
33844}
33845
33846class LineBasicMaterial extends Material {
33847
33848	constructor( parameters ) {
33849
33850		super();
33851
33852		this.isLineBasicMaterial = true;
33853
33854		this.type = 'LineBasicMaterial';
33855
33856		this.color = new Color( 0xffffff );
33857
33858		this.map = null;
33859
33860		this.linewidth = 1;
33861		this.linecap = 'round';
33862		this.linejoin = 'round';
33863
33864		this.fog = true;
33865
33866		this.setValues( parameters );
33867
33868	}
33869
33870
33871	copy( source ) {
33872
33873		super.copy( source );
33874
33875		this.color.copy( source.color );
33876
33877		this.map = source.map;
33878
33879		this.linewidth = source.linewidth;
33880		this.linecap = source.linecap;
33881		this.linejoin = source.linejoin;
33882
33883		this.fog = source.fog;
33884
33885		return this;
33886
33887	}
33888
33889}
33890
33891const _start$1 = /*@__PURE__*/ new Vector3();
33892const _end$1 = /*@__PURE__*/ new Vector3();
33893const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();
33894const _ray$1 = /*@__PURE__*/ new Ray();
33895const _sphere$1 = /*@__PURE__*/ new Sphere();
33896
33897class Line extends Object3D {
33898
33899	constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
33900
33901		super();
33902
33903		this.isLine = true;
33904
33905		this.type = 'Line';
33906
33907		this.geometry = geometry;
33908		this.material = material;
33909
33910		this.updateMorphTargets();
33911
33912	}
33913
33914	copy( source, recursive ) {
33915
33916		super.copy( source, recursive );
33917
33918		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
33919		this.geometry = source.geometry;
33920
33921		return this;
33922
33923	}
33924
33925	computeLineDistances() {
33926
33927		const geometry = this.geometry;
33928
33929		// we assume non-indexed geometry
33930
33931		if ( geometry.index === null ) {
33932
33933			const positionAttribute = geometry.attributes.position;
33934			const lineDistances = [ 0 ];
33935
33936			for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
33937
33938				_start$1.fromBufferAttribute( positionAttribute, i - 1 );
33939				_end$1.fromBufferAttribute( positionAttribute, i );
33940
33941				lineDistances[ i ] = lineDistances[ i - 1 ];
33942				lineDistances[ i ] += _start$1.distanceTo( _end$1 );
33943
33944			}
33945
33946			geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
33947
33948		} else {
33949
33950			console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
33951
33952		}
33953
33954		return this;
33955
33956	}
33957
33958	raycast( raycaster, intersects ) {
33959
33960		const geometry = this.geometry;
33961		const matrixWorld = this.matrixWorld;
33962		const threshold = raycaster.params.Line.threshold;
33963		const drawRange = geometry.drawRange;
33964
33965		// Checking boundingSphere distance to ray
33966
33967		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
33968
33969		_sphere$1.copy( geometry.boundingSphere );
33970		_sphere$1.applyMatrix4( matrixWorld );
33971		_sphere$1.radius += threshold;
33972
33973		if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;
33974
33975		//
33976
33977		_inverseMatrix$1.copy( matrixWorld ).invert();
33978		_ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
33979
33980		const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
33981		const localThresholdSq = localThreshold * localThreshold;
33982
33983		const vStart = new Vector3();
33984		const vEnd = new Vector3();
33985		const interSegment = new Vector3();
33986		const interRay = new Vector3();
33987		const step = this.isLineSegments ? 2 : 1;
33988
33989		const index = geometry.index;
33990		const attributes = geometry.attributes;
33991		const positionAttribute = attributes.position;
33992
33993		if ( index !== null ) {
33994
33995			const start = Math.max( 0, drawRange.start );
33996			const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
33997
33998			for ( let i = start, l = end - 1; i < l; i += step ) {
33999
34000				const a = index.getX( i );
34001				const b = index.getX( i + 1 );
34002
34003				vStart.fromBufferAttribute( positionAttribute, a );
34004				vEnd.fromBufferAttribute( positionAttribute, b );
34005
34006				const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34007
34008				if ( distSq > localThresholdSq ) continue;
34009
34010				interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34011
34012				const distance = raycaster.ray.origin.distanceTo( interRay );
34013
34014				if ( distance < raycaster.near || distance > raycaster.far ) continue;
34015
34016				intersects.push( {
34017
34018					distance: distance,
34019					// What do we want? intersection point on the ray or on the segment??
34020					// point: raycaster.ray.at( distance ),
34021					point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34022					index: i,
34023					face: null,
34024					faceIndex: null,
34025					object: this
34026
34027				} );
34028
34029			}
34030
34031		} else {
34032
34033			const start = Math.max( 0, drawRange.start );
34034			const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34035
34036			for ( let i = start, l = end - 1; i < l; i += step ) {
34037
34038				vStart.fromBufferAttribute( positionAttribute, i );
34039				vEnd.fromBufferAttribute( positionAttribute, i + 1 );
34040
34041				const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34042
34043				if ( distSq > localThresholdSq ) continue;
34044
34045				interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34046
34047				const distance = raycaster.ray.origin.distanceTo( interRay );
34048
34049				if ( distance < raycaster.near || distance > raycaster.far ) continue;
34050
34051				intersects.push( {
34052
34053					distance: distance,
34054					// What do we want? intersection point on the ray or on the segment??
34055					// point: raycaster.ray.at( distance ),
34056					point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34057					index: i,
34058					face: null,
34059					faceIndex: null,
34060					object: this
34061
34062				} );
34063
34064			}
34065
34066		}
34067
34068	}
34069
34070	updateMorphTargets() {
34071
34072		const geometry = this.geometry;
34073
34074		const morphAttributes = geometry.morphAttributes;
34075		const keys = Object.keys( morphAttributes );
34076
34077		if ( keys.length > 0 ) {
34078
34079			const morphAttribute = morphAttributes[ keys[ 0 ] ];
34080
34081			if ( morphAttribute !== undefined ) {
34082
34083				this.morphTargetInfluences = [];
34084				this.morphTargetDictionary = {};
34085
34086				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34087
34088					const name = morphAttribute[ m ].name || String( m );
34089
34090					this.morphTargetInfluences.push( 0 );
34091					this.morphTargetDictionary[ name ] = m;
34092
34093				}
34094
34095			}
34096
34097		}
34098
34099	}
34100
34101}
34102
34103const _start = /*@__PURE__*/ new Vector3();
34104const _end = /*@__PURE__*/ new Vector3();
34105
34106class LineSegments extends Line {
34107
34108	constructor( geometry, material ) {
34109
34110		super( geometry, material );
34111
34112		this.isLineSegments = true;
34113
34114		this.type = 'LineSegments';
34115
34116	}
34117
34118	computeLineDistances() {
34119
34120		const geometry = this.geometry;
34121
34122		// we assume non-indexed geometry
34123
34124		if ( geometry.index === null ) {
34125
34126			const positionAttribute = geometry.attributes.position;
34127			const lineDistances = [];
34128
34129			for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
34130
34131				_start.fromBufferAttribute( positionAttribute, i );
34132				_end.fromBufferAttribute( positionAttribute, i + 1 );
34133
34134				lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
34135				lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );
34136
34137			}
34138
34139			geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
34140
34141		} else {
34142
34143			console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
34144
34145		}
34146
34147		return this;
34148
34149	}
34150
34151}
34152
34153class LineLoop extends Line {
34154
34155	constructor( geometry, material ) {
34156
34157		super( geometry, material );
34158
34159		this.isLineLoop = true;
34160
34161		this.type = 'LineLoop';
34162
34163	}
34164
34165}
34166
34167class PointsMaterial extends Material {
34168
34169	constructor( parameters ) {
34170
34171		super();
34172
34173		this.isPointsMaterial = true;
34174
34175		this.type = 'PointsMaterial';
34176
34177		this.color = new Color( 0xffffff );
34178
34179		this.map = null;
34180
34181		this.alphaMap = null;
34182
34183		this.size = 1;
34184		this.sizeAttenuation = true;
34185
34186		this.fog = true;
34187
34188		this.setValues( parameters );
34189
34190	}
34191
34192	copy( source ) {
34193
34194		super.copy( source );
34195
34196		this.color.copy( source.color );
34197
34198		this.map = source.map;
34199
34200		this.alphaMap = source.alphaMap;
34201
34202		this.size = source.size;
34203		this.sizeAttenuation = source.sizeAttenuation;
34204
34205		this.fog = source.fog;
34206
34207		return this;
34208
34209	}
34210
34211}
34212
34213const _inverseMatrix = /*@__PURE__*/ new Matrix4();
34214const _ray = /*@__PURE__*/ new Ray();
34215const _sphere = /*@__PURE__*/ new Sphere();
34216const _position$2 = /*@__PURE__*/ new Vector3();
34217
34218class Points extends Object3D {
34219
34220	constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
34221
34222		super();
34223
34224		this.isPoints = true;
34225
34226		this.type = 'Points';
34227
34228		this.geometry = geometry;
34229		this.material = material;
34230
34231		this.updateMorphTargets();
34232
34233	}
34234
34235	copy( source, recursive ) {
34236
34237		super.copy( source, recursive );
34238
34239		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
34240		this.geometry = source.geometry;
34241
34242		return this;
34243
34244	}
34245
34246	raycast( raycaster, intersects ) {
34247
34248		const geometry = this.geometry;
34249		const matrixWorld = this.matrixWorld;
34250		const threshold = raycaster.params.Points.threshold;
34251		const drawRange = geometry.drawRange;
34252
34253		// Checking boundingSphere distance to ray
34254
34255		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
34256
34257		_sphere.copy( geometry.boundingSphere );
34258		_sphere.applyMatrix4( matrixWorld );
34259		_sphere.radius += threshold;
34260
34261		if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
34262
34263		//
34264
34265		_inverseMatrix.copy( matrixWorld ).invert();
34266		_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
34267
34268		const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
34269		const localThresholdSq = localThreshold * localThreshold;
34270
34271		const index = geometry.index;
34272		const attributes = geometry.attributes;
34273		const positionAttribute = attributes.position;
34274
34275		if ( index !== null ) {
34276
34277			const start = Math.max( 0, drawRange.start );
34278			const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
34279
34280			for ( let i = start, il = end; i < il; i ++ ) {
34281
34282				const a = index.getX( i );
34283
34284				_position$2.fromBufferAttribute( positionAttribute, a );
34285
34286				testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
34287
34288			}
34289
34290		} else {
34291
34292			const start = Math.max( 0, drawRange.start );
34293			const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34294
34295			for ( let i = start, l = end; i < l; i ++ ) {
34296
34297				_position$2.fromBufferAttribute( positionAttribute, i );
34298
34299				testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
34300
34301			}
34302
34303		}
34304
34305	}
34306
34307	updateMorphTargets() {
34308
34309		const geometry = this.geometry;
34310
34311		const morphAttributes = geometry.morphAttributes;
34312		const keys = Object.keys( morphAttributes );
34313
34314		if ( keys.length > 0 ) {
34315
34316			const morphAttribute = morphAttributes[ keys[ 0 ] ];
34317
34318			if ( morphAttribute !== undefined ) {
34319
34320				this.morphTargetInfluences = [];
34321				this.morphTargetDictionary = {};
34322
34323				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34324
34325					const name = morphAttribute[ m ].name || String( m );
34326
34327					this.morphTargetInfluences.push( 0 );
34328					this.morphTargetDictionary[ name ] = m;
34329
34330				}
34331
34332			}
34333
34334		}
34335
34336	}
34337
34338}
34339
34340function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
34341
34342	const rayPointDistanceSq = _ray.distanceSqToPoint( point );
34343
34344	if ( rayPointDistanceSq < localThresholdSq ) {
34345
34346		const intersectPoint = new Vector3();
34347
34348		_ray.closestPointToPoint( point, intersectPoint );
34349		intersectPoint.applyMatrix4( matrixWorld );
34350
34351		const distance = raycaster.ray.origin.distanceTo( intersectPoint );
34352
34353		if ( distance < raycaster.near || distance > raycaster.far ) return;
34354
34355		intersects.push( {
34356
34357			distance: distance,
34358			distanceToRay: Math.sqrt( rayPointDistanceSq ),
34359			point: intersectPoint,
34360			index: index,
34361			face: null,
34362			object: object
34363
34364		} );
34365
34366	}
34367
34368}
34369
34370class VideoTexture extends Texture {
34371
34372	constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
34373
34374		super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
34375
34376		this.isVideoTexture = true;
34377
34378		this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
34379		this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
34380
34381		this.generateMipmaps = false;
34382
34383		const scope = this;
34384
34385		function updateVideo() {
34386
34387			scope.needsUpdate = true;
34388			video.requestVideoFrameCallback( updateVideo );
34389
34390		}
34391
34392		if ( 'requestVideoFrameCallback' in video ) {
34393
34394			video.requestVideoFrameCallback( updateVideo );
34395
34396		}
34397
34398	}
34399
34400	clone() {
34401
34402		return new this.constructor( this.image ).copy( this );
34403
34404	}
34405
34406	update() {
34407
34408		const video = this.image;
34409		const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
34410
34411		if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
34412
34413			this.needsUpdate = true;
34414
34415		}
34416
34417	}
34418
34419}
34420
34421class FramebufferTexture extends Texture {
34422
34423	constructor( width, height ) {
34424
34425		super( { width, height } );
34426
34427		this.isFramebufferTexture = true;
34428
34429		this.magFilter = NearestFilter;
34430		this.minFilter = NearestFilter;
34431
34432		this.generateMipmaps = false;
34433
34434		this.needsUpdate = true;
34435
34436	}
34437
34438}
34439
34440class CompressedTexture extends Texture {
34441
34442	constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) {
34443
34444		super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
34445
34446		this.isCompressedTexture = true;
34447
34448		this.image = { width: width, height: height };
34449		this.mipmaps = mipmaps;
34450
34451		// no flipping for cube textures
34452		// (also flipping doesn't work for compressed textures )
34453
34454		this.flipY = false;
34455
34456		// can't generate mipmaps for compressed textures
34457		// mips must be embedded in DDS files
34458
34459		this.generateMipmaps = false;
34460
34461	}
34462
34463}
34464
34465class CompressedArrayTexture extends CompressedTexture {
34466
34467	constructor( mipmaps, width, height, depth, format, type ) {
34468
34469		super( mipmaps, width, height, format, type );
34470
34471		this.isCompressedArrayTexture = true;
34472		this.image.depth = depth;
34473		this.wrapR = ClampToEdgeWrapping;
34474
34475	}
34476
34477}
34478
34479class CompressedCubeTexture extends CompressedTexture {
34480
34481	constructor( images, format, type ) {
34482
34483		super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );
34484
34485		this.isCompressedCubeTexture = true;
34486		this.isCubeTexture = true;
34487
34488		this.image = images;
34489
34490	}
34491
34492}
34493
34494class CanvasTexture extends Texture {
34495
34496	constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
34497
34498		super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
34499
34500		this.isCanvasTexture = true;
34501
34502		this.needsUpdate = true;
34503
34504	}
34505
34506}
34507
34508/**
34509 * Extensible curve object.
34510 *
34511 * Some common of curve methods:
34512 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
34513 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
34514 * .getPoints(), .getSpacedPoints()
34515 * .getLength()
34516 * .updateArcLengths()
34517 *
34518 * This following curves inherit from THREE.Curve:
34519 *
34520 * -- 2D curves --
34521 * THREE.ArcCurve
34522 * THREE.CubicBezierCurve
34523 * THREE.EllipseCurve
34524 * THREE.LineCurve
34525 * THREE.QuadraticBezierCurve
34526 * THREE.SplineCurve
34527 *
34528 * -- 3D curves --
34529 * THREE.CatmullRomCurve3
34530 * THREE.CubicBezierCurve3
34531 * THREE.LineCurve3
34532 * THREE.QuadraticBezierCurve3
34533 *
34534 * A series of curves can be represented as a THREE.CurvePath.
34535 *
34536 **/
34537
34538class Curve {
34539
34540	constructor() {
34541
34542		this.type = 'Curve';
34543
34544		this.arcLengthDivisions = 200;
34545
34546	}
34547
34548	// Virtual base class method to overwrite and implement in subclasses
34549	//	- t [0 .. 1]
34550
34551	getPoint( /* t, optionalTarget */ ) {
34552
34553		console.warn( 'THREE.Curve: .getPoint() not implemented.' );
34554		return null;
34555
34556	}
34557
34558	// Get point at relative position in curve according to arc length
34559	// - u [0 .. 1]
34560
34561	getPointAt( u, optionalTarget ) {
34562
34563		const t = this.getUtoTmapping( u );
34564		return this.getPoint( t, optionalTarget );
34565
34566	}
34567
34568	// Get sequence of points using getPoint( t )
34569
34570	getPoints( divisions = 5 ) {
34571
34572		const points = [];
34573
34574		for ( let d = 0; d <= divisions; d ++ ) {
34575
34576			points.push( this.getPoint( d / divisions ) );
34577
34578		}
34579
34580		return points;
34581
34582	}
34583
34584	// Get sequence of points using getPointAt( u )
34585
34586	getSpacedPoints( divisions = 5 ) {
34587
34588		const points = [];
34589
34590		for ( let d = 0; d <= divisions; d ++ ) {
34591
34592			points.push( this.getPointAt( d / divisions ) );
34593
34594		}
34595
34596		return points;
34597
34598	}
34599
34600	// Get total curve arc length
34601
34602	getLength() {
34603
34604		const lengths = this.getLengths();
34605		return lengths[ lengths.length - 1 ];
34606
34607	}
34608
34609	// Get list of cumulative segment lengths
34610
34611	getLengths( divisions = this.arcLengthDivisions ) {
34612
34613		if ( this.cacheArcLengths &&
34614			( this.cacheArcLengths.length === divisions + 1 ) &&
34615			! this.needsUpdate ) {
34616
34617			return this.cacheArcLengths;
34618
34619		}
34620
34621		this.needsUpdate = false;
vendor: 7,518 bytes, lines 34622-35013
34622
34623		const cache = [];
34624		let current, last = this.getPoint( 0 );
34625		let sum = 0;
34626
34627		cache.push( 0 );
34628
34629		for ( let p = 1; p <= divisions; p ++ ) {
34630
34631			current = this.getPoint( p / divisions );
34632			sum += current.distanceTo( last );
34633			cache.push( sum );
34634			last = current;
34635
34636		}
34637
34638		this.cacheArcLengths = cache;
34639
34640		return cache; // { sums: cache, sum: sum }; Sum is in the last element.
34641
34642	}
34643
34644	updateArcLengths() {
34645
34646		this.needsUpdate = true;
34647		this.getLengths();
34648
34649	}
34650
34651	// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
34652
34653	getUtoTmapping( u, distance ) {
34654
34655		const arcLengths = this.getLengths();
34656
34657		let i = 0;
34658		const il = arcLengths.length;
34659
34660		let targetArcLength; // The targeted u distance value to get
34661
34662		if ( distance ) {
34663
34664			targetArcLength = distance;
34665
34666		} else {
34667
34668			targetArcLength = u * arcLengths[ il - 1 ];
34669
34670		}
34671
34672		// binary search for the index with largest value smaller than target u distance
34673
34674		let low = 0, high = il - 1, comparison;
34675
34676		while ( low <= high ) {
34677
34678			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
34679
34680			comparison = arcLengths[ i ] - targetArcLength;
34681
34682			if ( comparison < 0 ) {
34683
34684				low = i + 1;
34685
34686			} else if ( comparison > 0 ) {
34687
34688				high = i - 1;
34689
34690			} else {
34691
34692				high = i;
34693				break;
34694
34695				// DONE
34696
34697			}
34698
34699		}
34700
34701		i = high;
34702
34703		if ( arcLengths[ i ] === targetArcLength ) {
34704
34705			return i / ( il - 1 );
34706
34707		}
34708
34709		// we could get finer grain at lengths, or use simple interpolation between two points
34710
34711		const lengthBefore = arcLengths[ i ];
34712		const lengthAfter = arcLengths[ i + 1 ];
34713
34714		const segmentLength = lengthAfter - lengthBefore;
34715
34716		// determine where we are between the 'before' and 'after' points
34717
34718		const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
34719
34720		// add that fractional amount to t
34721
34722		const t = ( i + segmentFraction ) / ( il - 1 );
34723
34724		return t;
34725
34726	}
34727
34728	// Returns a unit vector tangent at t
34729	// In case any sub curve does not implement its tangent derivation,
34730	// 2 points a small delta apart will be used to find its gradient
34731	// which seems to give a reasonable approximation
34732
34733	getTangent( t, optionalTarget ) {
34734
34735		const delta = 0.0001;
34736		let t1 = t - delta;
34737		let t2 = t + delta;
34738
34739		// Capping in case of danger
34740
34741		if ( t1 < 0 ) t1 = 0;
34742		if ( t2 > 1 ) t2 = 1;
34743
34744		const pt1 = this.getPoint( t1 );
34745		const pt2 = this.getPoint( t2 );
34746
34747		const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
34748
34749		tangent.copy( pt2 ).sub( pt1 ).normalize();
34750
34751		return tangent;
34752
34753	}
34754
34755	getTangentAt( u, optionalTarget ) {
34756
34757		const t = this.getUtoTmapping( u );
34758		return this.getTangent( t, optionalTarget );
34759
34760	}
34761
34762	computeFrenetFrames( segments, closed ) {
34763
34764		// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
34765
34766		const normal = new Vector3();
34767
34768		const tangents = [];
34769		const normals = [];
34770		const binormals = [];
34771
34772		const vec = new Vector3();
34773		const mat = new Matrix4();
34774
34775		// compute the tangent vectors for each segment on the curve
34776
34777		for ( let i = 0; i <= segments; i ++ ) {
34778
34779			const u = i / segments;
34780
34781			tangents[ i ] = this.getTangentAt( u, new Vector3() );
34782
34783		}
34784
34785		// select an initial normal vector perpendicular to the first tangent vector,
34786		// and in the direction of the minimum tangent xyz component
34787
34788		normals[ 0 ] = new Vector3();
34789		binormals[ 0 ] = new Vector3();
34790		let min = Number.MAX_VALUE;
34791		const tx = Math.abs( tangents[ 0 ].x );
34792		const ty = Math.abs( tangents[ 0 ].y );
34793		const tz = Math.abs( tangents[ 0 ].z );
34794
34795		if ( tx <= min ) {
34796
34797			min = tx;
34798			normal.set( 1, 0, 0 );
34799
34800		}
34801
34802		if ( ty <= min ) {
34803
34804			min = ty;
34805			normal.set( 0, 1, 0 );
34806
34807		}
34808
34809		if ( tz <= min ) {
34810
34811			normal.set( 0, 0, 1 );
34812
34813		}
34814
34815		vec.crossVectors( tangents[ 0 ], normal ).normalize();
34816
34817		normals[ 0 ].crossVectors( tangents[ 0 ], vec );
34818		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
34819
34820
34821		// compute the slowly-varying normal and binormal vectors for each segment on the curve
34822
34823		for ( let i = 1; i <= segments; i ++ ) {
34824
34825			normals[ i ] = normals[ i - 1 ].clone();
34826
34827			binormals[ i ] = binormals[ i - 1 ].clone();
34828
34829			vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
34830
34831			if ( vec.length() > Number.EPSILON ) {
34832
34833				vec.normalize();
34834
34835				const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
34836
34837				normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
34838
34839			}
34840
34841			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34842
34843		}
34844
34845		// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
34846
34847		if ( closed === true ) {
34848
34849			let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
34850			theta /= segments;
34851
34852			if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
34853
34854				theta = - theta;
34855
34856			}
34857
34858			for ( let i = 1; i <= segments; i ++ ) {
34859
34860				// twist a little...
34861				normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
34862				binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34863
34864			}
34865
34866		}
34867
34868		return {
34869			tangents: tangents,
34870			normals: normals,
34871			binormals: binormals
34872		};
34873
34874	}
34875
34876	clone() {
34877
34878		return new this.constructor().copy( this );
34879
34880	}
34881
34882	copy( source ) {
34883
34884		this.arcLengthDivisions = source.arcLengthDivisions;
34885
34886		return this;
34887
34888	}
34889
34890	toJSON() {
34891
34892		const data = {
34893			metadata: {
34894				version: 4.6,
34895				type: 'Curve',
34896				generator: 'Curve.toJSON'
34897			}
34898		};
34899
34900		data.arcLengthDivisions = this.arcLengthDivisions;
34901		data.type = this.type;
34902
34903		return data;
34904
34905	}
34906
34907	fromJSON( json ) {
34908
34909		this.arcLengthDivisions = json.arcLengthDivisions;
34910
34911		return this;
34912
34913	}
34914
34915}
34916
34917class EllipseCurve extends Curve {
34918
34919	constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
34920
34921		super();
34922
34923		this.isEllipseCurve = true;
34924
34925		this.type = 'EllipseCurve';
34926
34927		this.aX = aX;
34928		this.aY = aY;
34929
34930		this.xRadius = xRadius;
34931		this.yRadius = yRadius;
34932
34933		this.aStartAngle = aStartAngle;
34934		this.aEndAngle = aEndAngle;
34935
34936		this.aClockwise = aClockwise;
34937
34938		this.aRotation = aRotation;
34939
34940	}
34941
34942	getPoint( t, optionalTarget ) {
34943
34944		const point = optionalTarget || new Vector2();
34945
34946		const twoPi = Math.PI * 2;
34947		let deltaAngle = this.aEndAngle - this.aStartAngle;
34948		const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
34949
34950		// ensures that deltaAngle is 0 .. 2 PI
34951		while ( deltaAngle < 0 ) deltaAngle += twoPi;
34952		while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
34953
34954		if ( deltaAngle < Number.EPSILON ) {
34955
34956			if ( samePoints ) {
34957
34958				deltaAngle = 0;
34959
34960			} else {
34961
34962				deltaAngle = twoPi;
34963
34964			}
34965
34966		}
34967
34968		if ( this.aClockwise === true && ! samePoints ) {
34969
34970			if ( deltaAngle === twoPi ) {
34971
34972				deltaAngle = - twoPi;
34973
34974			} else {
34975
34976				deltaAngle = deltaAngle - twoPi;
34977
34978			}
34979
34980		}
34981
34982		const angle = this.aStartAngle + t * deltaAngle;
34983		let x = this.aX + this.xRadius * Math.cos( angle );
34984		let y = this.aY + this.yRadius * Math.sin( angle );
34985
34986		if ( this.aRotation !== 0 ) {
34987
34988			const cos = Math.cos( this.aRotation );
34989			const sin = Math.sin( this.aRotation );
34990
34991			const tx = x - this.aX;
34992			const ty = y - this.aY;
34993
34994			// Rotate the point about the center of the ellipse.
34995			x = tx * cos - ty * sin + this.aX;
34996			y = tx * sin + ty * cos + this.aY;
34997
34998		}
34999
35000		return point.set( x, y );
35001
35002	}
35003
35004	copy( source ) {
35005
35006		super.copy( source );
35007
35008		this.aX = source.aX;
35009		this.aY = source.aY;
35010
35011		this.xRadius = source.xRadius;
35012		this.yRadius = source.yRadius;
35013
vendor: 29,619 bytes, lines 35014-36696
35014		this.aStartAngle = source.aStartAngle;
35015		this.aEndAngle = source.aEndAngle;
35016
35017		this.aClockwise = source.aClockwise;
35018
35019		this.aRotation = source.aRotation;
35020
35021		return this;
35022
35023	}
35024
35025	toJSON() {
35026
35027		const data = super.toJSON();
35028
35029		data.aX = this.aX;
35030		data.aY = this.aY;
35031
35032		data.xRadius = this.xRadius;
35033		data.yRadius = this.yRadius;
35034
35035		data.aStartAngle = this.aStartAngle;
35036		data.aEndAngle = this.aEndAngle;
35037
35038		data.aClockwise = this.aClockwise;
35039
35040		data.aRotation = this.aRotation;
35041
35042		return data;
35043
35044	}
35045
35046	fromJSON( json ) {
35047
35048		super.fromJSON( json );
35049
35050		this.aX = json.aX;
35051		this.aY = json.aY;
35052
35053		this.xRadius = json.xRadius;
35054		this.yRadius = json.yRadius;
35055
35056		this.aStartAngle = json.aStartAngle;
35057		this.aEndAngle = json.aEndAngle;
35058
35059		this.aClockwise = json.aClockwise;
35060
35061		this.aRotation = json.aRotation;
35062
35063		return this;
35064
35065	}
35066
35067}
35068
35069class ArcCurve extends EllipseCurve {
35070
35071	constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35072
35073		super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
35074
35075		this.isArcCurve = true;
35076
35077		this.type = 'ArcCurve';
35078
35079	}
35080
35081}
35082
35083/**
35084 * Centripetal CatmullRom Curve - which is useful for avoiding
35085 * cusps and self-intersections in non-uniform catmull rom curves.
35086 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
35087 *
35088 * curve.type accepts centripetal(default), chordal and catmullrom
35089 * curve.tension is used for catmullrom which defaults to 0.5
35090 */
35091
35092
35093/*
35094Based on an optimized c++ solution in
35095 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
35096 - http://ideone.com/NoEbVM
35097
35098This CubicPoly class could be used for reusing some variables and calculations,
35099but for three.js curve use, it could be possible inlined and flatten into a single function call
35100which can be placed in CurveUtils.
35101*/
35102
35103function CubicPoly() {
35104
35105	let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
35106
35107	/*
35108	 * Compute coefficients for a cubic polynomial
35109	 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
35110	 * such that
35111	 *   p(0) = x0, p(1) = x1
35112	 *  and
35113	 *   p'(0) = t0, p'(1) = t1.
35114	 */
35115	function init( x0, x1, t0, t1 ) {
35116
35117		c0 = x0;
35118		c1 = t0;
35119		c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
35120		c3 = 2 * x0 - 2 * x1 + t0 + t1;
35121
35122	}
35123
35124	return {
35125
35126		initCatmullRom: function ( x0, x1, x2, x3, tension ) {
35127
35128			init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
35129
35130		},
35131
35132		initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
35133
35134			// compute tangents when parameterized in [t1,t2]
35135			let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
35136			let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
35137
35138			// rescale tangents for parametrization in [0,1]
35139			t1 *= dt1;
35140			t2 *= dt1;
35141
35142			init( x1, x2, t1, t2 );
35143
35144		},
35145
35146		calc: function ( t ) {
35147
35148			const t2 = t * t;
35149			const t3 = t2 * t;
35150			return c0 + c1 * t + c2 * t2 + c3 * t3;
35151
35152		}
35153
35154	};
35155
35156}
35157
35158//
35159
35160const tmp = /*@__PURE__*/ new Vector3();
35161const px = /*@__PURE__*/ new CubicPoly();
35162const py = /*@__PURE__*/ new CubicPoly();
35163const pz = /*@__PURE__*/ new CubicPoly();
35164
35165class CatmullRomCurve3 extends Curve {
35166
35167	constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
35168
35169		super();
35170
35171		this.isCatmullRomCurve3 = true;
35172
35173		this.type = 'CatmullRomCurve3';
35174
35175		this.points = points;
35176		this.closed = closed;
35177		this.curveType = curveType;
35178		this.tension = tension;
35179
35180	}
35181
35182	getPoint( t, optionalTarget = new Vector3() ) {
35183
35184		const point = optionalTarget;
35185
35186		const points = this.points;
35187		const l = points.length;
35188
35189		const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
35190		let intPoint = Math.floor( p );
35191		let weight = p - intPoint;
35192
35193		if ( this.closed ) {
35194
35195			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
35196
35197		} else if ( weight === 0 && intPoint === l - 1 ) {
35198
35199			intPoint = l - 2;
35200			weight = 1;
35201
35202		}
35203
35204		let p0, p3; // 4 points (p1 & p2 defined below)
35205
35206		if ( this.closed || intPoint > 0 ) {
35207
35208			p0 = points[ ( intPoint - 1 ) % l ];
35209
35210		} else {
35211
35212			// extrapolate first point
35213			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
35214			p0 = tmp;
35215
35216		}
35217
35218		const p1 = points[ intPoint % l ];
35219		const p2 = points[ ( intPoint + 1 ) % l ];
35220
35221		if ( this.closed || intPoint + 2 < l ) {
35222
35223			p3 = points[ ( intPoint + 2 ) % l ];
35224
35225		} else {
35226
35227			// extrapolate last point
35228			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
35229			p3 = tmp;
35230
35231		}
35232
35233		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
35234
35235			// init Centripetal / Chordal Catmull-Rom
35236			const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
35237			let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
35238			let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
35239			let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
35240
35241			// safety check for repeated points
35242			if ( dt1 < 1e-4 ) dt1 = 1.0;
35243			if ( dt0 < 1e-4 ) dt0 = dt1;
35244			if ( dt2 < 1e-4 ) dt2 = dt1;
35245
35246			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
35247			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
35248			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
35249
35250		} else if ( this.curveType === 'catmullrom' ) {
35251
35252			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
35253			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
35254			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
35255
35256		}
35257
35258		point.set(
35259			px.calc( weight ),
35260			py.calc( weight ),
35261			pz.calc( weight )
35262		);
35263
35264		return point;
35265
35266	}
35267
35268	copy( source ) {
35269
35270		super.copy( source );
35271
35272		this.points = [];
35273
35274		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35275
35276			const point = source.points[ i ];
35277
35278			this.points.push( point.clone() );
35279
35280		}
35281
35282		this.closed = source.closed;
35283		this.curveType = source.curveType;
35284		this.tension = source.tension;
35285
35286		return this;
35287
35288	}
35289
35290	toJSON() {
35291
35292		const data = super.toJSON();
35293
35294		data.points = [];
35295
35296		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35297
35298			const point = this.points[ i ];
35299			data.points.push( point.toArray() );
35300
35301		}
35302
35303		data.closed = this.closed;
35304		data.curveType = this.curveType;
35305		data.tension = this.tension;
35306
35307		return data;
35308
35309	}
35310
35311	fromJSON( json ) {
35312
35313		super.fromJSON( json );
35314
35315		this.points = [];
35316
35317		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35318
35319			const point = json.points[ i ];
35320			this.points.push( new Vector3().fromArray( point ) );
35321
35322		}
35323
35324		this.closed = json.closed;
35325		this.curveType = json.curveType;
35326		this.tension = json.tension;
35327
35328		return this;
35329
35330	}
35331
35332}
35333
35334/**
35335 * Bezier Curves formulas obtained from
35336 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
35337 */
35338
35339function CatmullRom( t, p0, p1, p2, p3 ) {
35340
35341	const v0 = ( p2 - p0 ) * 0.5;
35342	const v1 = ( p3 - p1 ) * 0.5;
35343	const t2 = t * t;
35344	const t3 = t * t2;
35345	return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
35346
35347}
35348
35349//
35350
35351function QuadraticBezierP0( t, p ) {
35352
35353	const k = 1 - t;
35354	return k * k * p;
35355
35356}
35357
35358function QuadraticBezierP1( t, p ) {
35359
35360	return 2 * ( 1 - t ) * t * p;
35361
35362}
35363
35364function QuadraticBezierP2( t, p ) {
35365
35366	return t * t * p;
35367
35368}
35369
35370function QuadraticBezier( t, p0, p1, p2 ) {
35371
35372	return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
35373		QuadraticBezierP2( t, p2 );
35374
35375}
35376
35377//
35378
35379function CubicBezierP0( t, p ) {
35380
35381	const k = 1 - t;
35382	return k * k * k * p;
35383
35384}
35385
35386function CubicBezierP1( t, p ) {
35387
35388	const k = 1 - t;
35389	return 3 * k * k * t * p;
35390
35391}
35392
35393function CubicBezierP2( t, p ) {
35394
35395	return 3 * ( 1 - t ) * t * t * p;
35396
35397}
35398
35399function CubicBezierP3( t, p ) {
35400
35401	return t * t * t * p;
35402
35403}
35404
35405function CubicBezier( t, p0, p1, p2, p3 ) {
35406
35407	return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
35408		CubicBezierP3( t, p3 );
35409
35410}
35411
35412class CubicBezierCurve extends Curve {
35413
35414	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
35415
35416		super();
35417
35418		this.isCubicBezierCurve = true;
35419
35420		this.type = 'CubicBezierCurve';
35421
35422		this.v0 = v0;
35423		this.v1 = v1;
35424		this.v2 = v2;
35425		this.v3 = v3;
35426
35427	}
35428
35429	getPoint( t, optionalTarget = new Vector2() ) {
35430
35431		const point = optionalTarget;
35432
35433		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35434
35435		point.set(
35436			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35437			CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
35438		);
35439
35440		return point;
35441
35442	}
35443
35444	copy( source ) {
35445
35446		super.copy( source );
35447
35448		this.v0.copy( source.v0 );
35449		this.v1.copy( source.v1 );
35450		this.v2.copy( source.v2 );
35451		this.v3.copy( source.v3 );
35452
35453		return this;
35454
35455	}
35456
35457	toJSON() {
35458
35459		const data = super.toJSON();
35460
35461		data.v0 = this.v0.toArray();
35462		data.v1 = this.v1.toArray();
35463		data.v2 = this.v2.toArray();
35464		data.v3 = this.v3.toArray();
35465
35466		return data;
35467
35468	}
35469
35470	fromJSON( json ) {
35471
35472		super.fromJSON( json );
35473
35474		this.v0.fromArray( json.v0 );
35475		this.v1.fromArray( json.v1 );
35476		this.v2.fromArray( json.v2 );
35477		this.v3.fromArray( json.v3 );
35478
35479		return this;
35480
35481	}
35482
35483}
35484
35485class CubicBezierCurve3 extends Curve {
35486
35487	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
35488
35489		super();
35490
35491		this.isCubicBezierCurve3 = true;
35492
35493		this.type = 'CubicBezierCurve3';
35494
35495		this.v0 = v0;
35496		this.v1 = v1;
35497		this.v2 = v2;
35498		this.v3 = v3;
35499
35500	}
35501
35502	getPoint( t, optionalTarget = new Vector3() ) {
35503
35504		const point = optionalTarget;
35505
35506		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35507
35508		point.set(
35509			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35510			CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
35511			CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
35512		);
35513
35514		return point;
35515
35516	}
35517
35518	copy( source ) {
35519
35520		super.copy( source );
35521
35522		this.v0.copy( source.v0 );
35523		this.v1.copy( source.v1 );
35524		this.v2.copy( source.v2 );
35525		this.v3.copy( source.v3 );
35526
35527		return this;
35528
35529	}
35530
35531	toJSON() {
35532
35533		const data = super.toJSON();
35534
35535		data.v0 = this.v0.toArray();
35536		data.v1 = this.v1.toArray();
35537		data.v2 = this.v2.toArray();
35538		data.v3 = this.v3.toArray();
35539
35540		return data;
35541
35542	}
35543
35544	fromJSON( json ) {
35545
35546		super.fromJSON( json );
35547
35548		this.v0.fromArray( json.v0 );
35549		this.v1.fromArray( json.v1 );
35550		this.v2.fromArray( json.v2 );
35551		this.v3.fromArray( json.v3 );
35552
35553		return this;
35554
35555	}
35556
35557}
35558
35559class LineCurve extends Curve {
35560
35561	constructor( v1 = new Vector2(), v2 = new Vector2() ) {
35562
35563		super();
35564
35565		this.isLineCurve = true;
35566
35567		this.type = 'LineCurve';
35568
35569		this.v1 = v1;
35570		this.v2 = v2;
35571
35572	}
35573
35574	getPoint( t, optionalTarget = new Vector2() ) {
35575
35576		const point = optionalTarget;
35577
35578		if ( t === 1 ) {
35579
35580			point.copy( this.v2 );
35581
35582		} else {
35583
35584			point.copy( this.v2 ).sub( this.v1 );
35585			point.multiplyScalar( t ).add( this.v1 );
35586
35587		}
35588
35589		return point;
35590
35591	}
35592
35593	// Line curve is linear, so we can overwrite default getPointAt
35594	getPointAt( u, optionalTarget ) {
35595
35596		return this.getPoint( u, optionalTarget );
35597
35598	}
35599
35600	getTangent( t, optionalTarget = new Vector2() ) {
35601
35602		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35603
35604	}
35605
35606	getTangentAt( u, optionalTarget ) {
35607
35608		return this.getTangent( u, optionalTarget );
35609
35610	}
35611
35612	copy( source ) {
35613
35614		super.copy( source );
35615
35616		this.v1.copy( source.v1 );
35617		this.v2.copy( source.v2 );
35618
35619		return this;
35620
35621	}
35622
35623	toJSON() {
35624
35625		const data = super.toJSON();
35626
35627		data.v1 = this.v1.toArray();
35628		data.v2 = this.v2.toArray();
35629
35630		return data;
35631
35632	}
35633
35634	fromJSON( json ) {
35635
35636		super.fromJSON( json );
35637
35638		this.v1.fromArray( json.v1 );
35639		this.v2.fromArray( json.v2 );
35640
35641		return this;
35642
35643	}
35644
35645}
35646
35647class LineCurve3 extends Curve {
35648
35649	constructor( v1 = new Vector3(), v2 = new Vector3() ) {
35650
35651		super();
35652
35653		this.isLineCurve3 = true;
35654
35655		this.type = 'LineCurve3';
35656
35657		this.v1 = v1;
35658		this.v2 = v2;
35659
35660	}
35661
35662	getPoint( t, optionalTarget = new Vector3() ) {
35663
35664		const point = optionalTarget;
35665
35666		if ( t === 1 ) {
35667
35668			point.copy( this.v2 );
35669
35670		} else {
35671
35672			point.copy( this.v2 ).sub( this.v1 );
35673			point.multiplyScalar( t ).add( this.v1 );
35674
35675		}
35676
35677		return point;
35678
35679	}
35680
35681	// Line curve is linear, so we can overwrite default getPointAt
35682	getPointAt( u, optionalTarget ) {
35683
35684		return this.getPoint( u, optionalTarget );
35685
35686	}
35687
35688	getTangent( t, optionalTarget = new Vector3() ) {
35689
35690		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35691
35692	}
35693
35694	getTangentAt( u, optionalTarget ) {
35695
35696		return this.getTangent( u, optionalTarget );
35697
35698	}
35699
35700	copy( source ) {
35701
35702		super.copy( source );
35703
35704		this.v1.copy( source.v1 );
35705		this.v2.copy( source.v2 );
35706
35707		return this;
35708
35709	}
35710
35711	toJSON() {
35712
35713		const data = super.toJSON();
35714
35715		data.v1 = this.v1.toArray();
35716		data.v2 = this.v2.toArray();
35717
35718		return data;
35719
35720	}
35721
35722	fromJSON( json ) {
35723
35724		super.fromJSON( json );
35725
35726		this.v1.fromArray( json.v1 );
35727		this.v2.fromArray( json.v2 );
35728
35729		return this;
35730
35731	}
35732
35733}
35734
35735class QuadraticBezierCurve extends Curve {
35736
35737	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
35738
35739		super();
35740
35741		this.isQuadraticBezierCurve = true;
35742
35743		this.type = 'QuadraticBezierCurve';
35744
35745		this.v0 = v0;
35746		this.v1 = v1;
35747		this.v2 = v2;
35748
35749	}
35750
35751	getPoint( t, optionalTarget = new Vector2() ) {
35752
35753		const point = optionalTarget;
35754
35755		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35756
35757		point.set(
35758			QuadraticBezier( t, v0.x, v1.x, v2.x ),
35759			QuadraticBezier( t, v0.y, v1.y, v2.y )
35760		);
35761
35762		return point;
35763
35764	}
35765
35766	copy( source ) {
35767
35768		super.copy( source );
35769
35770		this.v0.copy( source.v0 );
35771		this.v1.copy( source.v1 );
35772		this.v2.copy( source.v2 );
35773
35774		return this;
35775
35776	}
35777
35778	toJSON() {
35779
35780		const data = super.toJSON();
35781
35782		data.v0 = this.v0.toArray();
35783		data.v1 = this.v1.toArray();
35784		data.v2 = this.v2.toArray();
35785
35786		return data;
35787
35788	}
35789
35790	fromJSON( json ) {
35791
35792		super.fromJSON( json );
35793
35794		this.v0.fromArray( json.v0 );
35795		this.v1.fromArray( json.v1 );
35796		this.v2.fromArray( json.v2 );
35797
35798		return this;
35799
35800	}
35801
35802}
35803
35804class QuadraticBezierCurve3 extends Curve {
35805
35806	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
35807
35808		super();
35809
35810		this.isQuadraticBezierCurve3 = true;
35811
35812		this.type = 'QuadraticBezierCurve3';
35813
35814		this.v0 = v0;
35815		this.v1 = v1;
35816		this.v2 = v2;
35817
35818	}
35819
35820	getPoint( t, optionalTarget = new Vector3() ) {
35821
35822		const point = optionalTarget;
35823
35824		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35825
35826		point.set(
35827			QuadraticBezier( t, v0.x, v1.x, v2.x ),
35828			QuadraticBezier( t, v0.y, v1.y, v2.y ),
35829			QuadraticBezier( t, v0.z, v1.z, v2.z )
35830		);
35831
35832		return point;
35833
35834	}
35835
35836	copy( source ) {
35837
35838		super.copy( source );
35839
35840		this.v0.copy( source.v0 );
35841		this.v1.copy( source.v1 );
35842		this.v2.copy( source.v2 );
35843
35844		return this;
35845
35846	}
35847
35848	toJSON() {
35849
35850		const data = super.toJSON();
35851
35852		data.v0 = this.v0.toArray();
35853		data.v1 = this.v1.toArray();
35854		data.v2 = this.v2.toArray();
35855
35856		return data;
35857
35858	}
35859
35860	fromJSON( json ) {
35861
35862		super.fromJSON( json );
35863
35864		this.v0.fromArray( json.v0 );
35865		this.v1.fromArray( json.v1 );
35866		this.v2.fromArray( json.v2 );
35867
35868		return this;
35869
35870	}
35871
35872}
35873
35874class SplineCurve extends Curve {
35875
35876	constructor( points = [] ) {
35877
35878		super();
35879
35880		this.isSplineCurve = true;
35881
35882		this.type = 'SplineCurve';
35883
35884		this.points = points;
35885
35886	}
35887
35888	getPoint( t, optionalTarget = new Vector2() ) {
35889
35890		const point = optionalTarget;
35891
35892		const points = this.points;
35893		const p = ( points.length - 1 ) * t;
35894
35895		const intPoint = Math.floor( p );
35896		const weight = p - intPoint;
35897
35898		const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
35899		const p1 = points[ intPoint ];
35900		const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
35901		const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
35902
35903		point.set(
35904			CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
35905			CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
35906		);
35907
35908		return point;
35909
35910	}
35911
35912	copy( source ) {
35913
35914		super.copy( source );
35915
35916		this.points = [];
35917
35918		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35919
35920			const point = source.points[ i ];
35921
35922			this.points.push( point.clone() );
35923
35924		}
35925
35926		return this;
35927
35928	}
35929
35930	toJSON() {
35931
35932		const data = super.toJSON();
35933
35934		data.points = [];
35935
35936		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35937
35938			const point = this.points[ i ];
35939			data.points.push( point.toArray() );
35940
35941		}
35942
35943		return data;
35944
35945	}
35946
35947	fromJSON( json ) {
35948
35949		super.fromJSON( json );
35950
35951		this.points = [];
35952
35953		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35954
35955			const point = json.points[ i ];
35956			this.points.push( new Vector2().fromArray( point ) );
35957
35958		}
35959
35960		return this;
35961
35962	}
35963
35964}
35965
35966var Curves = /*#__PURE__*/Object.freeze({
35967	__proto__: null,
35968	ArcCurve: ArcCurve,
35969	CatmullRomCurve3: CatmullRomCurve3,
35970	CubicBezierCurve: CubicBezierCurve,
35971	CubicBezierCurve3: CubicBezierCurve3,
35972	EllipseCurve: EllipseCurve,
35973	LineCurve: LineCurve,
35974	LineCurve3: LineCurve3,
35975	QuadraticBezierCurve: QuadraticBezierCurve,
35976	QuadraticBezierCurve3: QuadraticBezierCurve3,
35977	SplineCurve: SplineCurve
35978});
35979
35980/**************************************************************
35981 *	Curved Path - a curve path is simply a array of connected
35982 *  curves, but retains the api of a curve
35983 **************************************************************/
35984
35985class CurvePath extends Curve {
35986
35987	constructor() {
35988
35989		super();
35990
35991		this.type = 'CurvePath';
35992
35993		this.curves = [];
35994		this.autoClose = false; // Automatically closes the path
35995
35996	}
35997
35998	add( curve ) {
35999
36000		this.curves.push( curve );
36001
36002	}
36003
36004	closePath() {
36005
36006		// Add a line curve if start and end of lines are not connected
36007		const startPoint = this.curves[ 0 ].getPoint( 0 );
36008		const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
36009
36010		if ( ! startPoint.equals( endPoint ) ) {
36011
36012			const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
36013			this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
36014
36015		}
36016
36017		return this;
36018
36019	}
36020
36021	// To get accurate point with reference to
36022	// entire path distance at time t,
36023	// following has to be done:
36024
36025	// 1. Length of each sub path have to be known
36026	// 2. Locate and identify type of curve
36027	// 3. Get t for the curve
36028	// 4. Return curve.getPointAt(t')
36029
36030	getPoint( t, optionalTarget ) {
36031
36032		const d = t * this.getLength();
36033		const curveLengths = this.getCurveLengths();
36034		let i = 0;
36035
36036		// To think about boundaries points.
36037
36038		while ( i < curveLengths.length ) {
36039
36040			if ( curveLengths[ i ] >= d ) {
36041
36042				const diff = curveLengths[ i ] - d;
36043				const curve = this.curves[ i ];
36044
36045				const segmentLength = curve.getLength();
36046				const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
36047
36048				return curve.getPointAt( u, optionalTarget );
36049
36050			}
36051
36052			i ++;
36053
36054		}
36055
36056		return null;
36057
36058		// loop where sum != 0, sum > d , sum+1 <d
36059
36060	}
36061
36062	// We cannot use the default THREE.Curve getPoint() with getLength() because in
36063	// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
36064	// getPoint() depends on getLength
36065
36066	getLength() {
36067
36068		const lens = this.getCurveLengths();
36069		return lens[ lens.length - 1 ];
36070
36071	}
36072
36073	// cacheLengths must be recalculated.
36074	updateArcLengths() {
36075
36076		this.needsUpdate = true;
36077		this.cacheLengths = null;
36078		this.getCurveLengths();
36079
36080	}
36081
36082	// Compute lengths and cache them
36083	// We cannot overwrite getLengths() because UtoT mapping uses it.
36084
36085	getCurveLengths() {
36086
36087		// We use cache values if curves and cache array are same length
36088
36089		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
36090
36091			return this.cacheLengths;
36092
36093		}
36094
36095		// Get length of sub-curve
36096		// Push sums into cached array
36097
36098		const lengths = [];
36099		let sums = 0;
36100
36101		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36102
36103			sums += this.curves[ i ].getLength();
36104			lengths.push( sums );
36105
36106		}
36107
36108		this.cacheLengths = lengths;
36109
36110		return lengths;
36111
36112	}
36113
36114	getSpacedPoints( divisions = 40 ) {
36115
36116		const points = [];
36117
36118		for ( let i = 0; i <= divisions; i ++ ) {
36119
36120			points.push( this.getPoint( i / divisions ) );
36121
36122		}
36123
36124		if ( this.autoClose ) {
36125
36126			points.push( points[ 0 ] );
36127
36128		}
36129
36130		return points;
36131
36132	}
36133
36134	getPoints( divisions = 12 ) {
36135
36136		const points = [];
36137		let last;
36138
36139		for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
36140
36141			const curve = curves[ i ];
36142			const resolution = curve.isEllipseCurve ? divisions * 2
36143				: ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
36144					: curve.isSplineCurve ? divisions * curve.points.length
36145						: divisions;
36146
36147			const pts = curve.getPoints( resolution );
36148
36149			for ( let j = 0; j < pts.length; j ++ ) {
36150
36151				const point = pts[ j ];
36152
36153				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
36154
36155				points.push( point );
36156				last = point;
36157
36158			}
36159
36160		}
36161
36162		if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
36163
36164			points.push( points[ 0 ] );
36165
36166		}
36167
36168		return points;
36169
36170	}
36171
36172	copy( source ) {
36173
36174		super.copy( source );
36175
36176		this.curves = [];
36177
36178		for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
36179
36180			const curve = source.curves[ i ];
36181
36182			this.curves.push( curve.clone() );
36183
36184		}
36185
36186		this.autoClose = source.autoClose;
36187
36188		return this;
36189
36190	}
36191
36192	toJSON() {
36193
36194		const data = super.toJSON();
36195
36196		data.autoClose = this.autoClose;
36197		data.curves = [];
36198
36199		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36200
36201			const curve = this.curves[ i ];
36202			data.curves.push( curve.toJSON() );
36203
36204		}
36205
36206		return data;
36207
36208	}
36209
36210	fromJSON( json ) {
36211
36212		super.fromJSON( json );
36213
36214		this.autoClose = json.autoClose;
36215		this.curves = [];
36216
36217		for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
36218
36219			const curve = json.curves[ i ];
36220			this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
36221
36222		}
36223
36224		return this;
36225
36226	}
36227
36228}
36229
36230class Path extends CurvePath {
36231
36232	constructor( points ) {
36233
36234		super();
36235
36236		this.type = 'Path';
36237
36238		this.currentPoint = new Vector2();
36239
36240		if ( points ) {
36241
36242			this.setFromPoints( points );
36243
36244		}
36245
36246	}
36247
36248	setFromPoints( points ) {
36249
36250		this.moveTo( points[ 0 ].x, points[ 0 ].y );
36251
36252		for ( let i = 1, l = points.length; i < l; i ++ ) {
36253
36254			this.lineTo( points[ i ].x, points[ i ].y );
36255
36256		}
36257
36258		return this;
36259
36260	}
36261
36262	moveTo( x, y ) {
36263
36264		this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
36265
36266		return this;
36267
36268	}
36269
36270	lineTo( x, y ) {
36271
36272		const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
36273		this.curves.push( curve );
36274
36275		this.currentPoint.set( x, y );
36276
36277		return this;
36278
36279	}
36280
36281	quadraticCurveTo( aCPx, aCPy, aX, aY ) {
36282
36283		const curve = new QuadraticBezierCurve(
36284			this.currentPoint.clone(),
36285			new Vector2( aCPx, aCPy ),
36286			new Vector2( aX, aY )
36287		);
36288
36289		this.curves.push( curve );
36290
36291		this.currentPoint.set( aX, aY );
36292
36293		return this;
36294
36295	}
36296
36297	bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
36298
36299		const curve = new CubicBezierCurve(
36300			this.currentPoint.clone(),
36301			new Vector2( aCP1x, aCP1y ),
36302			new Vector2( aCP2x, aCP2y ),
36303			new Vector2( aX, aY )
36304		);
36305
36306		this.curves.push( curve );
36307
36308		this.currentPoint.set( aX, aY );
36309
36310		return this;
36311
36312	}
36313
36314	splineThru( pts /*Array of Vector*/ ) {
36315
36316		const npts = [ this.currentPoint.clone() ].concat( pts );
36317
36318		const curve = new SplineCurve( npts );
36319		this.curves.push( curve );
36320
36321		this.currentPoint.copy( pts[ pts.length - 1 ] );
36322
36323		return this;
36324
36325	}
36326
36327	arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36328
36329		const x0 = this.currentPoint.x;
36330		const y0 = this.currentPoint.y;
36331
36332		this.absarc( aX + x0, aY + y0, aRadius,
36333			aStartAngle, aEndAngle, aClockwise );
36334
36335		return this;
36336
36337	}
36338
36339	absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36340
36341		this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
36342
36343		return this;
36344
36345	}
36346
36347	ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36348
36349		const x0 = this.currentPoint.x;
36350		const y0 = this.currentPoint.y;
36351
36352		this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36353
36354		return this;
36355
36356	}
36357
36358	absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36359
36360		const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36361
36362		if ( this.curves.length > 0 ) {
36363
36364			// if a previous curve is present, attempt to join
36365			const firstPoint = curve.getPoint( 0 );
36366
36367			if ( ! firstPoint.equals( this.currentPoint ) ) {
36368
36369				this.lineTo( firstPoint.x, firstPoint.y );
36370
36371			}
36372
36373		}
36374
36375		this.curves.push( curve );
36376
36377		const lastPoint = curve.getPoint( 1 );
36378		this.currentPoint.copy( lastPoint );
36379
36380		return this;
36381
36382	}
36383
36384	copy( source ) {
36385
36386		super.copy( source );
36387
36388		this.currentPoint.copy( source.currentPoint );
36389
36390		return this;
36391
36392	}
36393
36394	toJSON() {
36395
36396		const data = super.toJSON();
36397
36398		data.currentPoint = this.currentPoint.toArray();
36399
36400		return data;
36401
36402	}
36403
36404	fromJSON( json ) {
36405
36406		super.fromJSON( json );
36407
36408		this.currentPoint.fromArray( json.currentPoint );
36409
36410		return this;
36411
36412	}
36413
36414}
36415
36416class LatheGeometry extends BufferGeometry {
36417
36418	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 ) {
36419
36420		super();
36421
36422		this.type = 'LatheGeometry';
36423
36424		this.parameters = {
36425			points: points,
36426			segments: segments,
36427			phiStart: phiStart,
36428			phiLength: phiLength
36429		};
36430
36431		segments = Math.floor( segments );
36432
36433		// clamp phiLength so it's in range of [ 0, 2PI ]
36434
36435		phiLength = clamp( phiLength, 0, Math.PI * 2 );
36436
36437		// buffers
36438
36439		const indices = [];
36440		const vertices = [];
36441		const uvs = [];
36442		const initNormals = [];
36443		const normals = [];
36444
36445		// helper variables
36446
36447		const inverseSegments = 1.0 / segments;
36448		const vertex = new Vector3();
36449		const uv = new Vector2();
36450		const normal = new Vector3();
36451		const curNormal = new Vector3();
36452		const prevNormal = new Vector3();
36453		let dx = 0;
36454		let dy = 0;
36455
36456		// pre-compute normals for initial "meridian"
36457
36458		for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36459
36460			switch ( j ) {
36461
36462				case 0:				// special handling for 1st vertex on path
36463
36464					dx = points[ j + 1 ].x - points[ j ].x;
36465					dy = points[ j + 1 ].y - points[ j ].y;
36466
36467					normal.x = dy * 1.0;
36468					normal.y = - dx;
36469					normal.z = dy * 0.0;
36470
36471					prevNormal.copy( normal );
36472
36473					normal.normalize();
36474
36475					initNormals.push( normal.x, normal.y, normal.z );
36476
36477					break;
36478
36479				case ( points.length - 1 ):	// special handling for last Vertex on path
36480
36481					initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z );
36482
36483					break;
36484
36485				default:			// default handling for all vertices in between
36486
36487					dx = points[ j + 1 ].x - points[ j ].x;
36488					dy = points[ j + 1 ].y - points[ j ].y;
36489
36490					normal.x = dy * 1.0;
36491					normal.y = - dx;
36492					normal.z = dy * 0.0;
36493
36494					curNormal.copy( normal );
36495
36496					normal.x += prevNormal.x;
36497					normal.y += prevNormal.y;
36498					normal.z += prevNormal.z;
36499
36500					normal.normalize();
36501
36502					initNormals.push( normal.x, normal.y, normal.z );
36503
36504					prevNormal.copy( curNormal );
36505
36506			}
36507
36508		}
36509
36510		// generate vertices, uvs and normals
36511
36512		for ( let i = 0; i <= segments; i ++ ) {
36513
36514			const phi = phiStart + i * inverseSegments * phiLength;
36515
36516			const sin = Math.sin( phi );
36517			const cos = Math.cos( phi );
36518
36519			for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36520
36521				// vertex
36522
36523				vertex.x = points[ j ].x * sin;
36524				vertex.y = points[ j ].y;
36525				vertex.z = points[ j ].x * cos;
36526
36527				vertices.push( vertex.x, vertex.y, vertex.z );
36528
36529				// uv
36530
36531				uv.x = i / segments;
36532				uv.y = j / ( points.length - 1 );
36533
36534				uvs.push( uv.x, uv.y );
36535
36536				// normal
36537
36538				const x = initNormals[ 3 * j + 0 ] * sin;
36539				const y = initNormals[ 3 * j + 1 ];
36540				const z = initNormals[ 3 * j + 0 ] * cos;
36541
36542				normals.push( x, y, z );
36543
36544			}
36545
36546		}
36547
36548		// indices
36549
36550		for ( let i = 0; i < segments; i ++ ) {
36551
36552			for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
36553
36554				const base = j + i * points.length;
36555
36556				const a = base;
36557				const b = base + points.length;
36558				const c = base + points.length + 1;
36559				const d = base + 1;
36560
36561				// faces
36562
36563				indices.push( a, b, d );
36564				indices.push( c, d, b );
36565
36566			}
36567
36568		}
36569
36570		// build geometry
36571
36572		this.setIndex( indices );
36573		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36574		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36575		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36576
36577	}
36578
36579	copy( source ) {
36580
36581		super.copy( source );
36582
36583		this.parameters = Object.assign( {}, source.parameters );
36584
36585		return this;
36586
36587	}
36588
36589	static fromJSON( data ) {
36590
36591		return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength );
36592
36593	}
36594
36595}
36596
36597class CapsuleGeometry extends LatheGeometry {
36598
36599	constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) {
36600
36601		const path = new Path();
36602		path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );
36603		path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );
36604
36605		super( path.getPoints( capSegments ), radialSegments );
36606
36607		this.type = 'CapsuleGeometry';
36608
36609		this.parameters = {
36610			radius: radius,
36611			length: length,
36612			capSegments: capSegments,
36613			radialSegments: radialSegments,
36614		};
36615
36616	}
36617
36618	static fromJSON( data ) {
36619
36620		return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments );
36621
36622	}
36623
36624}
36625
36626class CircleGeometry extends BufferGeometry {
36627
36628	constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36629
36630		super();
36631
36632		this.type = 'CircleGeometry';
36633
36634		this.parameters = {
36635			radius: radius,
36636			segments: segments,
36637			thetaStart: thetaStart,
36638			thetaLength: thetaLength
36639		};
36640
36641		segments = Math.max( 3, segments );
36642
36643		// buffers
36644
36645		const indices = [];
36646		const vertices = [];
36647		const normals = [];
36648		const uvs = [];
36649
36650		// helper variables
36651
36652		const vertex = new Vector3();
36653		const uv = new Vector2();
36654
36655		// center point
36656
36657		vertices.push( 0, 0, 0 );
36658		normals.push( 0, 0, 1 );
36659		uvs.push( 0.5, 0.5 );
36660
36661		for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
36662
36663			const segment = thetaStart + s / segments * thetaLength;
36664
36665			// vertex
36666
36667			vertex.x = radius * Math.cos( segment );
36668			vertex.y = radius * Math.sin( segment );
36669
36670			vertices.push( vertex.x, vertex.y, vertex.z );
36671
36672			// normal
36673
36674			normals.push( 0, 0, 1 );
36675
36676			// uvs
36677
36678			uv.x = ( vertices[ i ] / radius + 1 ) / 2;
36679			uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
36680
36681			uvs.push( uv.x, uv.y );
36682
36683		}
36684
36685		// indices
36686
36687		for ( let i = 1; i <= segments; i ++ ) {
36688
36689			indices.push( i, i + 1, 0 );
36690
36691		}
36692
36693		// build geometry
36694
36695		this.setIndex( indices );
36696		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,756 bytes, lines 36697-36922
36697		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36698		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36699
36700	}
36701
36702	copy( source ) {
36703
36704		super.copy( source );
36705
36706		this.parameters = Object.assign( {}, source.parameters );
36707
36708		return this;
36709
36710	}
36711
36712	static fromJSON( data ) {
36713
36714		return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );
36715
36716	}
36717
36718}
36719
36720class CylinderGeometry extends BufferGeometry {
36721
36722	constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36723
36724		super();
36725
36726		this.type = 'CylinderGeometry';
36727
36728		this.parameters = {
36729			radiusTop: radiusTop,
36730			radiusBottom: radiusBottom,
36731			height: height,
36732			radialSegments: radialSegments,
36733			heightSegments: heightSegments,
36734			openEnded: openEnded,
36735			thetaStart: thetaStart,
36736			thetaLength: thetaLength
36737		};
36738
36739		const scope = this;
36740
36741		radialSegments = Math.floor( radialSegments );
36742		heightSegments = Math.floor( heightSegments );
36743
36744		// buffers
36745
36746		const indices = [];
36747		const vertices = [];
36748		const normals = [];
36749		const uvs = [];
36750
36751		// helper variables
36752
36753		let index = 0;
36754		const indexArray = [];
36755		const halfHeight = height / 2;
36756		let groupStart = 0;
36757
36758		// generate geometry
36759
36760		generateTorso();
36761
36762		if ( openEnded === false ) {
36763
36764			if ( radiusTop > 0 ) generateCap( true );
36765			if ( radiusBottom > 0 ) generateCap( false );
36766
36767		}
36768
36769		// build geometry
36770
36771		this.setIndex( indices );
36772		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36773		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36774		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36775
36776		function generateTorso() {
36777
36778			const normal = new Vector3();
36779			const vertex = new Vector3();
36780
36781			let groupCount = 0;
36782
36783			// this will be used to calculate the normal
36784			const slope = ( radiusBottom - radiusTop ) / height;
36785
36786			// generate vertices, normals and uvs
36787
36788			for ( let y = 0; y <= heightSegments; y ++ ) {
36789
36790				const indexRow = [];
36791
36792				const v = y / heightSegments;
36793
36794				// calculate the radius of the current row
36795
36796				const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
36797
36798				for ( let x = 0; x <= radialSegments; x ++ ) {
36799
36800					const u = x / radialSegments;
36801
36802					const theta = u * thetaLength + thetaStart;
36803
36804					const sinTheta = Math.sin( theta );
36805					const cosTheta = Math.cos( theta );
36806
36807					// vertex
36808
36809					vertex.x = radius * sinTheta;
36810					vertex.y = - v * height + halfHeight;
36811					vertex.z = radius * cosTheta;
36812					vertices.push( vertex.x, vertex.y, vertex.z );
36813
36814					// normal
36815
36816					normal.set( sinTheta, slope, cosTheta ).normalize();
36817					normals.push( normal.x, normal.y, normal.z );
36818
36819					// uv
36820
36821					uvs.push( u, 1 - v );
36822
36823					// save index of vertex in respective row
36824
36825					indexRow.push( index ++ );
36826
36827				}
36828
36829				// now save vertices of the row in our index array
36830
36831				indexArray.push( indexRow );
36832
36833			}
36834
36835			// generate indices
36836
36837			for ( let x = 0; x < radialSegments; x ++ ) {
36838
36839				for ( let y = 0; y < heightSegments; y ++ ) {
36840
36841					// we use the index array to access the correct indices
36842
36843					const a = indexArray[ y ][ x ];
36844					const b = indexArray[ y + 1 ][ x ];
36845					const c = indexArray[ y + 1 ][ x + 1 ];
36846					const d = indexArray[ y ][ x + 1 ];
36847
36848					// faces
36849
36850					indices.push( a, b, d );
36851					indices.push( b, c, d );
36852
36853					// update group counter
36854
36855					groupCount += 6;
36856
36857				}
36858
36859			}
36860
36861			// add a group to the geometry. this will ensure multi material support
36862
36863			scope.addGroup( groupStart, groupCount, 0 );
36864
36865			// calculate new start value for groups
36866
36867			groupStart += groupCount;
36868
36869		}
36870
36871		function generateCap( top ) {
36872
36873			// save the index of the first center vertex
36874			const centerIndexStart = index;
36875
36876			const uv = new Vector2();
36877			const vertex = new Vector3();
36878
36879			let groupCount = 0;
36880
36881			const radius = ( top === true ) ? radiusTop : radiusBottom;
36882			const sign = ( top === true ) ? 1 : - 1;
36883
36884			// first we generate the center vertex data of the cap.
36885			// because the geometry needs one set of uvs per face,
36886			// we must generate a center vertex per face/segment
36887
36888			for ( let x = 1; x <= radialSegments; x ++ ) {
36889
36890				// vertex
36891
36892				vertices.push( 0, halfHeight * sign, 0 );
36893
36894				// normal
36895
36896				normals.push( 0, sign, 0 );
36897
36898				// uv
36899
36900				uvs.push( 0.5, 0.5 );
36901
36902				// increase index
36903
36904				index ++;
36905
36906			}
36907
36908			// save the index of the last center vertex
36909			const centerIndexEnd = index;
36910
36911			// now we generate the surrounding vertices, normals and uvs
36912
36913			for ( let x = 0; x <= radialSegments; x ++ ) {
36914
36915				const u = x / radialSegments;
36916				const theta = u * thetaLength + thetaStart;
36917
36918				const cosTheta = Math.cos( theta );
36919				const sinTheta = Math.sin( theta );
36920
36921				// vertex
36922
vendor: 16,069 bytes, lines 36923-37701
36923				vertex.x = radius * sinTheta;
36924				vertex.y = halfHeight * sign;
36925				vertex.z = radius * cosTheta;
36926				vertices.push( vertex.x, vertex.y, vertex.z );
36927
36928				// normal
36929
36930				normals.push( 0, sign, 0 );
36931
36932				// uv
36933
36934				uv.x = ( cosTheta * 0.5 ) + 0.5;
36935				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
36936				uvs.push( uv.x, uv.y );
36937
36938				// increase index
36939
36940				index ++;
36941
36942			}
36943
36944			// generate indices
36945
36946			for ( let x = 0; x < radialSegments; x ++ ) {
36947
36948				const c = centerIndexStart + x;
36949				const i = centerIndexEnd + x;
36950
36951				if ( top === true ) {
36952
36953					// face top
36954
36955					indices.push( i, i + 1, c );
36956
36957				} else {
36958
36959					// face bottom
36960
36961					indices.push( i + 1, i, c );
36962
36963				}
36964
36965				groupCount += 3;
36966
36967			}
36968
36969			// add a group to the geometry. this will ensure multi material support
36970
36971			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
36972
36973			// calculate new start value for groups
36974
36975			groupStart += groupCount;
36976
36977		}
36978
36979	}
36980
36981	copy( source ) {
36982
36983		super.copy( source );
36984
36985		this.parameters = Object.assign( {}, source.parameters );
36986
36987		return this;
36988
36989	}
36990
36991	static fromJSON( data ) {
36992
36993		return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
36994
36995	}
36996
36997}
36998
36999class ConeGeometry extends CylinderGeometry {
37000
37001	constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
37002
37003		super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
37004
37005		this.type = 'ConeGeometry';
37006
37007		this.parameters = {
37008			radius: radius,
37009			height: height,
37010			radialSegments: radialSegments,
37011			heightSegments: heightSegments,
37012			openEnded: openEnded,
37013			thetaStart: thetaStart,
37014			thetaLength: thetaLength
37015		};
37016
37017	}
37018
37019	static fromJSON( data ) {
37020
37021		return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
37022
37023	}
37024
37025}
37026
37027class PolyhedronGeometry extends BufferGeometry {
37028
37029	constructor( vertices = [], indices = [], radius = 1, detail = 0 ) {
37030
37031		super();
37032
37033		this.type = 'PolyhedronGeometry';
37034
37035		this.parameters = {
37036			vertices: vertices,
37037			indices: indices,
37038			radius: radius,
37039			detail: detail
37040		};
37041
37042		// default buffer data
37043
37044		const vertexBuffer = [];
37045		const uvBuffer = [];
37046
37047		// the subdivision creates the vertex buffer data
37048
37049		subdivide( detail );
37050
37051		// all vertices should lie on a conceptual sphere with a given radius
37052
37053		applyRadius( radius );
37054
37055		// finally, create the uv data
37056
37057		generateUVs();
37058
37059		// build non-indexed geometry
37060
37061		this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
37062		this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
37063		this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
37064
37065		if ( detail === 0 ) {
37066
37067			this.computeVertexNormals(); // flat normals
37068
37069		} else {
37070
37071			this.normalizeNormals(); // smooth normals
37072
37073		}
37074
37075		// helper functions
37076
37077		function subdivide( detail ) {
37078
37079			const a = new Vector3();
37080			const b = new Vector3();
37081			const c = new Vector3();
37082
37083			// iterate over all faces and apply a subdivision with the given detail value
37084
37085			for ( let i = 0; i < indices.length; i += 3 ) {
37086
37087				// get the vertices of the face
37088
37089				getVertexByIndex( indices[ i + 0 ], a );
37090				getVertexByIndex( indices[ i + 1 ], b );
37091				getVertexByIndex( indices[ i + 2 ], c );
37092
37093				// perform subdivision
37094
37095				subdivideFace( a, b, c, detail );
37096
37097			}
37098
37099		}
37100
37101		function subdivideFace( a, b, c, detail ) {
37102
37103			const cols = detail + 1;
37104
37105			// we use this multidimensional array as a data structure for creating the subdivision
37106
37107			const v = [];
37108
37109			// construct all of the vertices for this subdivision
37110
37111			for ( let i = 0; i <= cols; i ++ ) {
37112
37113				v[ i ] = [];
37114
37115				const aj = a.clone().lerp( c, i / cols );
37116				const bj = b.clone().lerp( c, i / cols );
37117
37118				const rows = cols - i;
37119
37120				for ( let j = 0; j <= rows; j ++ ) {
37121
37122					if ( j === 0 && i === cols ) {
37123
37124						v[ i ][ j ] = aj;
37125
37126					} else {
37127
37128						v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
37129
37130					}
37131
37132				}
37133
37134			}
37135
37136			// construct all of the faces
37137
37138			for ( let i = 0; i < cols; i ++ ) {
37139
37140				for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
37141
37142					const k = Math.floor( j / 2 );
37143
37144					if ( j % 2 === 0 ) {
37145
37146						pushVertex( v[ i ][ k + 1 ] );
37147						pushVertex( v[ i + 1 ][ k ] );
37148						pushVertex( v[ i ][ k ] );
37149
37150					} else {
37151
37152						pushVertex( v[ i ][ k + 1 ] );
37153						pushVertex( v[ i + 1 ][ k + 1 ] );
37154						pushVertex( v[ i + 1 ][ k ] );
37155
37156					}
37157
37158				}
37159
37160			}
37161
37162		}
37163
37164		function applyRadius( radius ) {
37165
37166			const vertex = new Vector3();
37167
37168			// iterate over the entire buffer and apply the radius to each vertex
37169
37170			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37171
37172				vertex.x = vertexBuffer[ i + 0 ];
37173				vertex.y = vertexBuffer[ i + 1 ];
37174				vertex.z = vertexBuffer[ i + 2 ];
37175
37176				vertex.normalize().multiplyScalar( radius );
37177
37178				vertexBuffer[ i + 0 ] = vertex.x;
37179				vertexBuffer[ i + 1 ] = vertex.y;
37180				vertexBuffer[ i + 2 ] = vertex.z;
37181
37182			}
37183
37184		}
37185
37186		function generateUVs() {
37187
37188			const vertex = new Vector3();
37189
37190			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37191
37192				vertex.x = vertexBuffer[ i + 0 ];
37193				vertex.y = vertexBuffer[ i + 1 ];
37194				vertex.z = vertexBuffer[ i + 2 ];
37195
37196				const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
37197				const v = inclination( vertex ) / Math.PI + 0.5;
37198				uvBuffer.push( u, 1 - v );
37199
37200			}
37201
37202			correctUVs();
37203
37204			correctSeam();
37205
37206		}
37207
37208		function correctSeam() {
37209
37210			// handle case when face straddles the seam, see #3269
37211
37212			for ( let i = 0; i < uvBuffer.length; i += 6 ) {
37213
37214				// uv data of a single face
37215
37216				const x0 = uvBuffer[ i + 0 ];
37217				const x1 = uvBuffer[ i + 2 ];
37218				const x2 = uvBuffer[ i + 4 ];
37219
37220				const max = Math.max( x0, x1, x2 );
37221				const min = Math.min( x0, x1, x2 );
37222
37223				// 0.9 is somewhat arbitrary
37224
37225				if ( max > 0.9 && min < 0.1 ) {
37226
37227					if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
37228					if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
37229					if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
37230
37231				}
37232
37233			}
37234
37235		}
37236
37237		function pushVertex( vertex ) {
37238
37239			vertexBuffer.push( vertex.x, vertex.y, vertex.z );
37240
37241		}
37242
37243		function getVertexByIndex( index, vertex ) {
37244
37245			const stride = index * 3;
37246
37247			vertex.x = vertices[ stride + 0 ];
37248			vertex.y = vertices[ stride + 1 ];
37249			vertex.z = vertices[ stride + 2 ];
37250
37251		}
37252
37253		function correctUVs() {
37254
37255			const a = new Vector3();
37256			const b = new Vector3();
37257			const c = new Vector3();
37258
37259			const centroid = new Vector3();
37260
37261			const uvA = new Vector2();
37262			const uvB = new Vector2();
37263			const uvC = new Vector2();
37264
37265			for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
37266
37267				a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
37268				b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
37269				c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
37270
37271				uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
37272				uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
37273				uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
37274
37275				centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
37276
37277				const azi = azimuth( centroid );
37278
37279				correctUV( uvA, j + 0, a, azi );
37280				correctUV( uvB, j + 2, b, azi );
37281				correctUV( uvC, j + 4, c, azi );
37282
37283			}
37284
37285		}
37286
37287		function correctUV( uv, stride, vector, azimuth ) {
37288
37289			if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
37290
37291				uvBuffer[ stride ] = uv.x - 1;
37292
37293			}
37294
37295			if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
37296
37297				uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
37298
37299			}
37300
37301		}
37302
37303		// Angle around the Y axis, counter-clockwise when looking from above.
37304
37305		function azimuth( vector ) {
37306
37307			return Math.atan2( vector.z, - vector.x );
37308
37309		}
37310
37311
37312		// Angle above the XZ plane.
37313
37314		function inclination( vector ) {
37315
37316			return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
37317
37318		}
37319
37320	}
37321
37322	copy( source ) {
37323
37324		super.copy( source );
37325
37326		this.parameters = Object.assign( {}, source.parameters );
37327
37328		return this;
37329
37330	}
37331
37332	static fromJSON( data ) {
37333
37334		return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details );
37335
37336	}
37337
37338}
37339
37340class DodecahedronGeometry extends PolyhedronGeometry {
37341
37342	constructor( radius = 1, detail = 0 ) {
37343
37344		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
37345		const r = 1 / t;
37346
37347		const vertices = [
37348
37349			// (±1, ±1, ±1)
37350			- 1, - 1, - 1,	- 1, - 1, 1,
37351			- 1, 1, - 1, - 1, 1, 1,
37352			1, - 1, - 1, 1, - 1, 1,
37353			1, 1, - 1, 1, 1, 1,
37354
37355			// (0, ±1/φ, ±φ)
37356			0, - r, - t, 0, - r, t,
37357			0, r, - t, 0, r, t,
37358
37359			// (±1/φ, ±φ, 0)
37360			- r, - t, 0, - r, t, 0,
37361			r, - t, 0, r, t, 0,
37362
37363			// (±φ, 0, ±1/φ)
37364			- t, 0, - r, t, 0, - r,
37365			- t, 0, r, t, 0, r
37366		];
37367
37368		const indices = [
37369			3, 11, 7, 	3, 7, 15, 	3, 15, 13,
37370			7, 19, 17, 	7, 17, 6, 	7, 6, 15,
37371			17, 4, 8, 	17, 8, 10, 	17, 10, 6,
37372			8, 0, 16, 	8, 16, 2, 	8, 2, 10,
37373			0, 12, 1, 	0, 1, 18, 	0, 18, 16,
37374			6, 10, 2, 	6, 2, 13, 	6, 13, 15,
37375			2, 16, 18, 	2, 18, 3, 	2, 3, 13,
37376			18, 1, 9, 	18, 9, 11, 	18, 11, 3,
37377			4, 14, 12, 	4, 12, 0, 	4, 0, 8,
37378			11, 9, 5, 	11, 5, 19, 	11, 19, 7,
37379			19, 5, 14, 	19, 14, 4, 	19, 4, 17,
37380			1, 12, 14, 	1, 14, 5, 	1, 5, 9
37381		];
37382
37383		super( vertices, indices, radius, detail );
37384
37385		this.type = 'DodecahedronGeometry';
37386
37387		this.parameters = {
37388			radius: radius,
37389			detail: detail
37390		};
37391
37392	}
37393
37394	static fromJSON( data ) {
37395
37396		return new DodecahedronGeometry( data.radius, data.detail );
37397
37398	}
37399
37400}
37401
37402const _v0 = /*@__PURE__*/ new Vector3();
37403const _v1$1 = /*@__PURE__*/ new Vector3();
37404const _normal = /*@__PURE__*/ new Vector3();
37405const _triangle = /*@__PURE__*/ new Triangle();
37406
37407class EdgesGeometry extends BufferGeometry {
37408
37409	constructor( geometry = null, thresholdAngle = 1 ) {
37410
37411		super();
37412
37413		this.type = 'EdgesGeometry';
37414
37415		this.parameters = {
37416			geometry: geometry,
37417			thresholdAngle: thresholdAngle
37418		};
37419
37420		if ( geometry !== null ) {
37421
37422			const precisionPoints = 4;
37423			const precision = Math.pow( 10, precisionPoints );
37424			const thresholdDot = Math.cos( DEG2RAD * thresholdAngle );
37425
37426			const indexAttr = geometry.getIndex();
37427			const positionAttr = geometry.getAttribute( 'position' );
37428			const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
37429
37430			const indexArr = [ 0, 0, 0 ];
37431			const vertKeys = [ 'a', 'b', 'c' ];
37432			const hashes = new Array( 3 );
37433
37434			const edgeData = {};
37435			const vertices = [];
37436			for ( let i = 0; i < indexCount; i += 3 ) {
37437
37438				if ( indexAttr ) {
37439
37440					indexArr[ 0 ] = indexAttr.getX( i );
37441					indexArr[ 1 ] = indexAttr.getX( i + 1 );
37442					indexArr[ 2 ] = indexAttr.getX( i + 2 );
37443
37444				} else {
37445
37446					indexArr[ 0 ] = i;
37447					indexArr[ 1 ] = i + 1;
37448					indexArr[ 2 ] = i + 2;
37449
37450				}
37451
37452				const { a, b, c } = _triangle;
37453				a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
37454				b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
37455				c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
37456				_triangle.getNormal( _normal );
37457
37458				// create hashes for the edge from the vertices
37459				hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
37460				hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
37461				hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
37462
37463				// skip degenerate triangles
37464				if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
37465
37466					continue;
37467
37468				}
37469
37470				// iterate over every edge
37471				for ( let j = 0; j < 3; j ++ ) {
37472
37473					// get the first and next vertex making up the edge
37474					const jNext = ( j + 1 ) % 3;
37475					const vecHash0 = hashes[ j ];
37476					const vecHash1 = hashes[ jNext ];
37477					const v0 = _triangle[ vertKeys[ j ] ];
37478					const v1 = _triangle[ vertKeys[ jNext ] ];
37479
37480					const hash = `${ vecHash0 }_${ vecHash1 }`;
37481					const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
37482
37483					if ( reverseHash in edgeData && edgeData[ reverseHash ] ) {
37484
37485						// if we found a sibling edge add it into the vertex array if
37486						// it meets the angle threshold and delete the edge from the map.
37487						if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
37488
37489							vertices.push( v0.x, v0.y, v0.z );
37490							vertices.push( v1.x, v1.y, v1.z );
37491
37492						}
37493
37494						edgeData[ reverseHash ] = null;
37495
37496					} else if ( ! ( hash in edgeData ) ) {
37497
37498						// if we've already got an edge here then skip adding a new one
37499						edgeData[ hash ] = {
37500
37501							index0: indexArr[ j ],
37502							index1: indexArr[ jNext ],
37503							normal: _normal.clone(),
37504
37505						};
37506
37507					}
37508
37509				}
37510
37511			}
37512
37513			// iterate over all remaining, unmatched edges and add them to the vertex array
37514			for ( const key in edgeData ) {
37515
37516				if ( edgeData[ key ] ) {
37517
37518					const { index0, index1 } = edgeData[ key ];
37519					_v0.fromBufferAttribute( positionAttr, index0 );
37520					_v1$1.fromBufferAttribute( positionAttr, index1 );
37521
37522					vertices.push( _v0.x, _v0.y, _v0.z );
37523					vertices.push( _v1$1.x, _v1$1.y, _v1$1.z );
37524
37525				}
37526
37527			}
37528
37529			this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
37530
37531		}
37532
37533	}
37534
37535	copy( source ) {
37536
37537		super.copy( source );
37538
37539		this.parameters = Object.assign( {}, source.parameters );
37540
37541		return this;
37542
37543	}
37544
37545}
37546
37547class Shape extends Path {
37548
37549	constructor( points ) {
37550
37551		super( points );
37552
37553		this.uuid = generateUUID();
37554
37555		this.type = 'Shape';
37556
37557		this.holes = [];
37558
37559	}
37560
37561	getPointsHoles( divisions ) {
37562
37563		const holesPts = [];
37564
37565		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37566
37567			holesPts[ i ] = this.holes[ i ].getPoints( divisions );
37568
37569		}
37570
37571		return holesPts;
37572
37573	}
37574
37575	// get points of shape and holes (keypoints based on segments parameter)
37576
37577	extractPoints( divisions ) {
37578
37579		return {
37580
37581			shape: this.getPoints( divisions ),
37582			holes: this.getPointsHoles( divisions )
37583
37584		};
37585
37586	}
37587
37588	copy( source ) {
37589
37590		super.copy( source );
37591
37592		this.holes = [];
37593
37594		for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
37595
37596			const hole = source.holes[ i ];
37597
37598			this.holes.push( hole.clone() );
37599
37600		}
37601
37602		return this;
37603
37604	}
37605
37606	toJSON() {
37607
37608		const data = super.toJSON();
37609
37610		data.uuid = this.uuid;
37611		data.holes = [];
37612
37613		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37614
37615			const hole = this.holes[ i ];
37616			data.holes.push( hole.toJSON() );
37617
37618		}
37619
37620		return data;
37621
37622	}
37623
37624	fromJSON( json ) {
37625
37626		super.fromJSON( json );
37627
37628		this.uuid = json.uuid;
37629		this.holes = [];
37630
37631		for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
37632
37633			const hole = json.holes[ i ];
37634			this.holes.push( new Path().fromJSON( hole ) );
37635
37636		}
37637
37638		return this;
37639
37640	}
37641
37642}
37643
37644/**
37645 * Port from https://github.com/mapbox/earcut (v2.2.4)
37646 */
37647
37648const Earcut = {
37649
37650	triangulate: function ( data, holeIndices, dim = 2 ) {
37651
37652		const hasHoles = holeIndices && holeIndices.length;
37653		const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
37654		let outerNode = linkedList( data, 0, outerLen, dim, true );
37655		const triangles = [];
37656
37657		if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
37658
37659		let minX, minY, maxX, maxY, x, y, invSize;
37660
37661		if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
37662
37663		// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
37664		if ( data.length > 80 * dim ) {
37665
37666			minX = maxX = data[ 0 ];
37667			minY = maxY = data[ 1 ];
37668
37669			for ( let i = dim; i < outerLen; i += dim ) {
37670
37671				x = data[ i ];
37672				y = data[ i + 1 ];
37673				if ( x < minX ) minX = x;
37674				if ( y < minY ) minY = y;
37675				if ( x > maxX ) maxX = x;
37676				if ( y > maxY ) maxY = y;
37677
37678			}
37679
37680			// minX, minY and invSize are later used to transform coords into integers for z-order calculation
37681			invSize = Math.max( maxX - minX, maxY - minY );
37682			invSize = invSize !== 0 ? 32767 / invSize : 0;
37683
37684		}
37685
37686		earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );
37687
37688		return triangles;
37689
37690	}
37691
37692};
37693
37694// create a circular doubly linked list from polygon points in the specified winding order
37695function linkedList( data, start, end, dim, clockwise ) {
37696
37697	let i, last;
37698
37699	if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
37700
37701		for ( i = start; i < end;
vendor: 10,405 bytes, lines 37701-38174
37701 i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37702
37703	} else {
37704
37705		for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37706
37707	}
37708
37709	if ( last && equals( last, last.next ) ) {
37710
37711		removeNode( last );
37712		last = last.next;
37713
37714	}
37715
37716	return last;
37717
37718}
37719
37720// eliminate colinear or duplicate points
37721function filterPoints( start, end ) {
37722
37723	if ( ! start ) return start;
37724	if ( ! end ) end = start;
37725
37726	let p = start,
37727		again;
37728	do {
37729
37730		again = false;
37731
37732		if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
37733
37734			removeNode( p );
37735			p = end = p.prev;
37736			if ( p === p.next ) break;
37737			again = true;
37738
37739		} else {
37740
37741			p = p.next;
37742
37743		}
37744
37745	} while ( again || p !== end );
37746
37747	return end;
37748
37749}
37750
37751// main ear slicing loop which triangulates a polygon (given as a linked list)
37752function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
37753
37754	if ( ! ear ) return;
37755
37756	// interlink polygon nodes in z-order
37757	if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
37758
37759	let stop = ear,
37760		prev, next;
37761
37762	// iterate through ears, slicing them one by one
37763	while ( ear.prev !== ear.next ) {
37764
37765		prev = ear.prev;
37766		next = ear.next;
37767
37768		if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
37769
37770			// cut off the triangle
37771			triangles.push( prev.i / dim | 0 );
37772			triangles.push( ear.i / dim | 0 );
37773			triangles.push( next.i / dim | 0 );
37774
37775			removeNode( ear );
37776
37777			// skipping the next vertex leads to less sliver triangles
37778			ear = next.next;
37779			stop = next.next;
37780
37781			continue;
37782
37783		}
37784
37785		ear = next;
37786
37787		// if we looped through the whole remaining polygon and can't find any more ears
37788		if ( ear === stop ) {
37789
37790			// try filtering points and slicing again
37791			if ( ! pass ) {
37792
37793				earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
37794
37795				// if this didn't work, try curing all small self-intersections locally
37796
37797			} else if ( pass === 1 ) {
37798
37799				ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
37800				earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
37801
37802				// as a last resort, try splitting the remaining polygon into two
37803
37804			} else if ( pass === 2 ) {
37805
37806				splitEarcut( ear, triangles, dim, minX, minY, invSize );
37807
37808			}
37809
37810			break;
37811
37812		}
37813
37814	}
37815
37816}
37817
37818// check whether a polygon node forms a valid ear with adjacent nodes
37819function isEar( ear ) {
37820
37821	const a = ear.prev,
37822		b = ear,
37823		c = ear.next;
37824
37825	if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37826
37827	// now make sure we don't have other points inside the potential ear
37828	const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37829
37830	// triangle bbox; min & max are calculated like this for speed
37831	const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37832		y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37833		x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37834		y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37835
37836	let p = c.next;
37837	while ( p !== a ) {
37838
37839		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
37840			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
37841			area( p.prev, p, p.next ) >= 0 ) return false;
37842		p = p.next;
37843
37844	}
37845
37846	return true;
37847
37848}
37849
37850function isEarHashed( ear, minX, minY, invSize ) {
37851
37852	const a = ear.prev,
37853		b = ear,
37854		c = ear.next;
37855
37856	if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37857
37858	const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37859
37860	// triangle bbox; min & max are calculated like this for speed
37861	const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37862		y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37863		x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37864		y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37865
37866	// z-order range for the current triangle bbox;
37867	const minZ = zOrder( x0, y0, minX, minY, invSize ),
37868		maxZ = zOrder( x1, y1, minX, minY, invSize );
37869
37870	let p = ear.prevZ,
37871		n = ear.nextZ;
37872
37873	// look for points inside the triangle in both directions
37874	while ( p && p.z >= minZ && n && n.z <= maxZ ) {
37875
37876		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37877			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37878		p = p.prevZ;
37879
37880		if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37881			pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37882		n = n.nextZ;
37883
37884	}
37885
37886	// look for remaining points in decreasing z-order
37887	while ( p && p.z >= minZ ) {
37888
37889		if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37890			pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37891		p = p.prevZ;
37892
37893	}
37894
37895	// look for remaining points in increasing z-order
37896	while ( n && n.z <= maxZ ) {
37897
37898		if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37899			pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37900		n = n.nextZ;
37901
37902	}
37903
37904	return true;
37905
37906}
37907
37908// go through all polygon nodes and cure small local self-intersections
37909function cureLocalIntersections( start, triangles, dim ) {
37910
37911	let p = start;
37912	do {
37913
37914		const a = p.prev,
37915			b = p.next.next;
37916
37917		if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
37918
37919			triangles.push( a.i / dim | 0 );
37920			triangles.push( p.i / dim | 0 );
37921			triangles.push( b.i / dim | 0 );
37922
37923			// remove two nodes involved
37924			removeNode( p );
37925			removeNode( p.next );
37926
37927			p = start = b;
37928
37929		}
37930
37931		p = p.next;
37932
37933	} while ( p !== start );
37934
37935	return filterPoints( p );
37936
37937}
37938
37939// try splitting polygon into two and triangulate them independently
37940function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
37941
37942	// look for a valid diagonal that divides the polygon into two
37943	let a = start;
37944	do {
37945
37946		let b = a.next.next;
37947		while ( b !== a.prev ) {
37948
37949			if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
37950
37951				// split the polygon in two by the diagonal
37952				let c = splitPolygon( a, b );
37953
37954				// filter colinear points around the cuts
37955				a = filterPoints( a, a.next );
37956				c = filterPoints( c, c.next );
37957
37958				// run earcut on each half
37959				earcutLinked( a, triangles, dim, minX, minY, invSize, 0 );
37960				earcutLinked( c, triangles, dim, minX, minY, invSize, 0 );
37961				return;
37962
37963			}
37964
37965			b = b.next;
37966
37967		}
37968
37969		a = a.next;
37970
37971	} while ( a !== start );
37972
37973}
37974
37975// link every hole into the outer loop, producing a single-ring polygon without holes
37976function eliminateHoles( data, holeIndices, outerNode, dim ) {
37977
37978	const queue = [];
37979	let i, len, start, end, list;
37980
37981	for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
37982
37983		start = holeIndices[ i ] * dim;
37984		end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
37985		list = linkedList( data, start, end, dim, false );
37986		if ( list === list.next ) list.steiner = true;
37987		queue.push( getLeftmost( list ) );
37988
37989	}
37990
37991	queue.sort( compareX );
37992
37993	// process holes from left to right
37994	for ( i = 0; i < queue.length; i ++ ) {
37995
37996		outerNode = eliminateHole( queue[ i ], outerNode );
37997
37998	}
37999
38000	return outerNode;
38001
38002}
38003
38004function compareX( a, b ) {
38005
38006	return a.x - b.x;
38007
38008}
38009
38010// find a bridge between vertices that connects hole with an outer ring and link it
38011function eliminateHole( hole, outerNode ) {
38012
38013	const bridge = findHoleBridge( hole, outerNode );
38014	if ( ! bridge ) {
38015
38016		return outerNode;
38017
38018	}
38019
38020	const bridgeReverse = splitPolygon( bridge, hole );
38021
38022	// filter collinear points around the cuts
38023	filterPoints( bridgeReverse, bridgeReverse.next );
38024	return filterPoints( bridge, bridge.next );
38025
38026}
38027
38028// David Eberly's algorithm for finding a bridge between hole and outer polygon
38029function findHoleBridge( hole, outerNode ) {
38030
38031	let p = outerNode,
38032		qx = - Infinity,
38033		m;
38034
38035	const hx = hole.x, hy = hole.y;
38036
38037	// find a segment intersected by a ray from the hole's leftmost point to the left;
38038	// segment's endpoint with lesser x will be potential connection point
38039	do {
38040
38041		if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
38042
38043			const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
38044			if ( x <= hx && x > qx ) {
38045
38046				qx = x;
38047				m = p.x < p.next.x ? p : p.next;
38048				if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint
38049
38050			}
38051
38052		}
38053
38054		p = p.next;
38055
38056	} while ( p !== outerNode );
38057
38058	if ( ! m ) return null;
38059
38060	// look for points inside the triangle of hole point, segment intersection and endpoint;
38061	// if there are no points found, we have a valid connection;
38062	// otherwise choose the point of the minimum angle with the ray as connection point
38063
38064	const stop = m,
38065		mx = m.x,
38066		my = m.y;
38067	let tanMin = Infinity, tan;
38068
38069	p = m;
38070
38071	do {
38072
38073		if ( hx >= p.x && p.x >= mx && hx !== p.x &&
38074				pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
38075
38076			tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
38077
38078			if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
38079
38080				m = p;
38081				tanMin = tan;
38082
38083			}
38084
38085		}
38086
38087		p = p.next;
38088
38089	} while ( p !== stop );
38090
38091	return m;
38092
38093}
38094
38095// whether sector in vertex m contains sector in vertex p in the same coordinates
38096function sectorContainsSector( m, p ) {
38097
38098	return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
38099
38100}
38101
38102// interlink polygon nodes in z-order
38103function indexCurve( start, minX, minY, invSize ) {
38104
38105	let p = start;
38106	do {
38107
38108		if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
38109		p.prevZ = p.prev;
38110		p.nextZ = p.next;
38111		p = p.next;
38112
38113	} while ( p !== start );
38114
38115	p.prevZ.nextZ = null;
38116	p.prevZ = null;
38117
38118	sortLinked( p );
38119
38120}
38121
38122// Simon Tatham's linked list merge sort algorithm
38123// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
38124function sortLinked( list ) {
38125
38126	let i, p, q, e, tail, numMerges, pSize, qSize,
38127		inSize = 1;
38128
38129	do {
38130
38131		p = list;
38132		list = null;
38133		tail = null;
38134		numMerges = 0;
38135
38136		while ( p ) {
38137
38138			numMerges ++;
38139			q = p;
38140			pSize = 0;
38141			for ( i = 0; i < inSize; i ++ ) {
38142
38143				pSize ++;
38144				q = q.nextZ;
38145				if ( ! q ) break;
38146
38147			}
38148
38149			qSize = inSize;
38150
38151			while ( pSize > 0 || ( qSize > 0 && q ) ) {
38152
38153				if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
38154
38155					e = p;
38156					p = p.nextZ;
38157					pSize --;
38158
38159				} else {
38160
38161					e = q;
38162					q = q.nextZ;
38163					qSize --;
38164
38165				}
38166
38167				if ( tail ) tail.nextZ = e;
38168				else list = e;
38169
38170				e.prevZ = tail;
38171				tail = e;
38172
38173			}
38174
vendor: 9,707 bytes, lines 38175-38602
38175			p = q;
38176
38177		}
38178
38179		tail.nextZ = null;
38180		inSize *= 2;
38181
38182	} while ( numMerges > 1 );
38183
38184	return list;
38185
38186}
38187
38188// z-order of a point given coords and inverse of the longer side of data bbox
38189function zOrder( x, y, minX, minY, invSize ) {
38190
38191	// coords are transformed into non-negative 15-bit integer range
38192	x = ( x - minX ) * invSize | 0;
38193	y = ( y - minY ) * invSize | 0;
38194
38195	x = ( x | ( x << 8 ) ) & 0x00FF00FF;
38196	x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
38197	x = ( x | ( x << 2 ) ) & 0x33333333;
38198	x = ( x | ( x << 1 ) ) & 0x55555555;
38199
38200	y = ( y | ( y << 8 ) ) & 0x00FF00FF;
38201	y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
38202	y = ( y | ( y << 2 ) ) & 0x33333333;
38203	y = ( y | ( y << 1 ) ) & 0x55555555;
38204
38205	return x | ( y << 1 );
38206
38207}
38208
38209// find the leftmost node of a polygon ring
38210function getLeftmost( start ) {
38211
38212	let p = start,
38213		leftmost = start;
38214	do {
38215
38216		if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
38217		p = p.next;
38218
38219	} while ( p !== start );
38220
38221	return leftmost;
38222
38223}
38224
38225// check if a point lies within a convex triangle
38226function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
38227
38228	return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&
38229           ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&
38230           ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );
38231
38232}
38233
38234// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
38235function isValidDiagonal( a, b ) {
38236
38237	return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
38238           ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
38239            ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
38240            equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
38241
38242}
38243
38244// signed area of a triangle
38245function area( p, q, r ) {
38246
38247	return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
38248
38249}
38250
38251// check if two points are equal
38252function equals( p1, p2 ) {
38253
38254	return p1.x === p2.x && p1.y === p2.y;
38255
38256}
38257
38258// check if two segments intersect
38259function intersects( p1, q1, p2, q2 ) {
38260
38261	const o1 = sign( area( p1, q1, p2 ) );
38262	const o2 = sign( area( p1, q1, q2 ) );
38263	const o3 = sign( area( p2, q2, p1 ) );
38264	const o4 = sign( area( p2, q2, q1 ) );
38265
38266	if ( o1 !== o2 && o3 !== o4 ) return true; // general case
38267
38268	if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
38269	if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
38270	if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
38271	if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
38272
38273	return false;
38274
38275}
38276
38277// for collinear points p, q, r, check if point q lies on segment pr
38278function onSegment( p, q, r ) {
38279
38280	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 );
38281
38282}
38283
38284function sign( num ) {
38285
38286	return num > 0 ? 1 : num < 0 ? - 1 : 0;
38287
38288}
38289
38290// check if a polygon diagonal intersects any polygon segments
38291function intersectsPolygon( a, b ) {
38292
38293	let p = a;
38294	do {
38295
38296		if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
38297			intersects( p, p.next, a, b ) ) return true;
38298		p = p.next;
38299
38300	} while ( p !== a );
38301
38302	return false;
38303
38304}
38305
38306// check if a polygon diagonal is locally inside the polygon
38307function locallyInside( a, b ) {
38308
38309	return area( a.prev, a, a.next ) < 0 ?
38310		area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
38311		area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
38312
38313}
38314
38315// check if the middle point of a polygon diagonal is inside the polygon
38316function middleInside( a, b ) {
38317
38318	let p = a,
38319		inside = false;
38320	const px = ( a.x + b.x ) / 2,
38321		py = ( a.y + b.y ) / 2;
38322	do {
38323
38324		if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
38325			( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
38326			inside = ! inside;
38327		p = p.next;
38328
38329	} while ( p !== a );
38330
38331	return inside;
38332
38333}
38334
38335// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
38336// if one belongs to the outer ring and another to a hole, it merges it into a single ring
38337function splitPolygon( a, b ) {
38338
38339	const a2 = new Node( a.i, a.x, a.y ),
38340		b2 = new Node( b.i, b.x, b.y ),
38341		an = a.next,
38342		bp = b.prev;
38343
38344	a.next = b;
38345	b.prev = a;
38346
38347	a2.next = an;
38348	an.prev = a2;
38349
38350	b2.next = a2;
38351	a2.prev = b2;
38352
38353	bp.next = b2;
38354	b2.prev = bp;
38355
38356	return b2;
38357
38358}
38359
38360// create a node and optionally link it with previous one (in a circular doubly linked list)
38361function insertNode( i, x, y, last ) {
38362
38363	const p = new Node( i, x, y );
38364
38365	if ( ! last ) {
38366
38367		p.prev = p;
38368		p.next = p;
38369
38370	} else {
38371
38372		p.next = last.next;
38373		p.prev = last;
38374		last.next.prev = p;
38375		last.next = p;
38376
38377	}
38378
38379	return p;
38380
38381}
38382
38383function removeNode( p ) {
38384
38385	p.next.prev = p.prev;
38386	p.prev.next = p.next;
38387
38388	if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
38389	if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
38390
38391}
38392
38393function Node( i, x, y ) {
38394
38395	// vertex index in coordinates array
38396	this.i = i;
38397
38398	// vertex coordinates
38399	this.x = x;
38400	this.y = y;
38401
38402	// previous and next vertex nodes in a polygon ring
38403	this.prev = null;
38404	this.next = null;
38405
38406	// z-order curve value
38407	this.z = 0;
38408
38409	// previous and next nodes in z-order
38410	this.prevZ = null;
38411	this.nextZ = null;
38412
38413	// indicates whether this is a steiner point
38414	this.steiner = false;
38415
38416}
38417
38418function signedArea( data, start, end, dim ) {
38419
38420	let sum = 0;
38421	for ( let i = start, j = end - dim; i < end; i += dim ) {
38422
38423		sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
38424		j = i;
38425
38426	}
38427
38428	return sum;
38429
38430}
38431
38432class ShapeUtils {
38433
38434	// calculate area of the contour polygon
38435
38436	static area( contour ) {
38437
38438		const n = contour.length;
38439		let a = 0.0;
38440
38441		for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
38442
38443			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
38444
38445		}
38446
38447		return a * 0.5;
38448
38449	}
38450
38451	static isClockWise( pts ) {
38452
38453		return ShapeUtils.area( pts ) < 0;
38454
38455	}
38456
38457	static triangulateShape( contour, holes ) {
38458
38459		const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
38460		const holeIndices = []; // array of hole indices
38461		const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
38462
38463		removeDupEndPts( contour );
38464		addContour( vertices, contour );
38465
38466		//
38467
38468		let holeIndex = contour.length;
38469
38470		holes.forEach( removeDupEndPts );
38471
38472		for ( let i = 0; i < holes.length; i ++ ) {
38473
38474			holeIndices.push( holeIndex );
38475			holeIndex += holes[ i ].length;
38476			addContour( vertices, holes[ i ] );
38477
38478		}
38479
38480		//
38481
38482		const triangles = Earcut.triangulate( vertices, holeIndices );
38483
38484		//
38485
38486		for ( let i = 0; i < triangles.length; i += 3 ) {
38487
38488			faces.push( triangles.slice( i, i + 3 ) );
38489
38490		}
38491
38492		return faces;
38493
38494	}
38495
38496}
38497
38498function removeDupEndPts( points ) {
38499
38500	const l = points.length;
38501
38502	if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
38503
38504		points.pop();
38505
38506	}
38507
38508}
38509
38510function addContour( vertices, contour ) {
38511
38512	for ( let i = 0; i < contour.length; i ++ ) {
38513
38514		vertices.push( contour[ i ].x );
38515		vertices.push( contour[ i ].y );
38516
38517	}
38518
38519}
38520
38521/**
38522 * Creates extruded geometry from a path shape.
38523 *
38524 * parameters = {
38525 *
38526 *  curveSegments: <int>, // number of points on the curves
38527 *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
38528 *  depth: <float>, // Depth to extrude the shape
38529 *
38530 *  bevelEnabled: <bool>, // turn on bevel
38531 *  bevelThickness: <float>, // how deep into the original shape bevel goes
38532 *  bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
38533 *  bevelOffset: <float>, // how far from shape outline does bevel start
38534 *  bevelSegments: <int>, // number of bevel layers
38535 *
38536 *  extrudePath: <THREE.Curve> // curve to extrude shape along
38537 *
38538 *  UVGenerator: <Object> // object that provides UV generator functions
38539 *
38540 * }
38541 */
38542
38543
38544class ExtrudeGeometry extends BufferGeometry {
38545
38546	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 = {} ) {
38547
38548		super();
38549
38550		this.type = 'ExtrudeGeometry';
38551
38552		this.parameters = {
38553			shapes: shapes,
38554			options: options
38555		};
38556
38557		shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
38558
38559		const scope = this;
38560
38561		const verticesArray = [];
38562		const uvArray = [];
38563
38564		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
38565
38566			const shape = shapes[ i ];
38567			addShape( shape );
38568
38569		}
38570
38571		// build geometry
38572
38573		this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
38574		this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
38575
38576		this.computeVertexNormals();
38577
38578		// functions
38579
38580		function addShape( shape ) {
38581
38582			const placeholder = [];
38583
38584			// options
38585
38586			const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
38587			const steps = options.steps !== undefined ? options.steps : 1;
38588			const depth = options.depth !== undefined ? options.depth : 1;
38589
38590			let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
38591			let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;
38592			let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;
38593			let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
38594			let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
38595
38596			const extrudePath = options.extrudePath;
38597
38598			const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
38599
38600			//
38601
38602			let extrudePts, extrudeByPath = false;
vendor: 2,791 bytes, lines 38603-38716
38603			let splineTube, binormal, normal, position2;
38604
38605			if ( extrudePath ) {
38606
38607				extrudePts = extrudePath.getSpacedPoints( steps );
38608
38609				extrudeByPath = true;
38610				bevelEnabled = false; // bevels not supported for path extrusion
38611
38612				// SETUP TNB variables
38613
38614				// TODO1 - have a .isClosed in spline?
38615
38616				splineTube = extrudePath.computeFrenetFrames( steps, false );
38617
38618				// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
38619
38620				binormal = new Vector3();
38621				normal = new Vector3();
38622				position2 = new Vector3();
38623
38624			}
38625
38626			// Safeguards if bevels are not enabled
38627
38628			if ( ! bevelEnabled ) {
38629
38630				bevelSegments = 0;
38631				bevelThickness = 0;
38632				bevelSize = 0;
38633				bevelOffset = 0;
38634
38635			}
38636
38637			// Variables initialization
38638
38639			const shapePoints = shape.extractPoints( curveSegments );
38640
38641			let vertices = shapePoints.shape;
38642			const holes = shapePoints.holes;
38643
38644			const reverse = ! ShapeUtils.isClockWise( vertices );
38645
38646			if ( reverse ) {
38647
38648				vertices = vertices.reverse();
38649
38650				// Maybe we should also check if holes are in the opposite direction, just to be safe ...
38651
38652				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38653
38654					const ahole = holes[ h ];
38655
38656					if ( ShapeUtils.isClockWise( ahole ) ) {
38657
38658						holes[ h ] = ahole.reverse();
38659
38660					}
38661
38662				}
38663
38664			}
38665
38666
38667			const faces = ShapeUtils.triangulateShape( vertices, holes );
38668
38669			/* Vertices */
38670
38671			const contour = vertices; // vertices has all points but contour has only points of circumference
38672
38673			for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38674
38675				const ahole = holes[ h ];
38676
38677				vertices = vertices.concat( ahole );
38678
38679			}
38680
38681
38682			function scalePt2( pt, vec, size ) {
38683
38684				if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
38685
38686				return pt.clone().addScaledVector( vec, size );
38687
38688			}
38689
38690			const vlen = vertices.length, flen = faces.length;
38691
38692
38693			// Find directions for point movement
38694
38695
38696			function getBevelVec( inPt, inPrev, inNext ) {
38697
38698				// computes for inPt the corresponding point inPt' on a new contour
38699				//   shifted by 1 unit (length of normalized vector) to the left
38700				// if we walk along contour clockwise, this new contour is outside the old one
38701				//
38702				// inPt' is the intersection of the two lines parallel to the two
38703				//  adjacent edges of inPt at a distance of 1 unit on the left side.
38704
38705				let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
38706
38707				// good reading for geometry algorithms (here: line-line intersection)
38708				// http://geomalgorithms.com/a05-_intersect-1.html
38709
38710				const v_prev_x = inPt.x - inPrev.x,
38711					v_prev_y = inPt.y - inPrev.y;
38712				const v_next_x = inNext.x - inPt.x,
38713					v_next_y = inNext.y - inPt.y;
38714
38715				const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
38716
vendor: 17,452 bytes, lines 38717-39568
38717				// check for collinear edges
38718				const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
38719
38720				if ( Math.abs( collinear0 ) > Number.EPSILON ) {
38721
38722					// not collinear
38723
38724					// length of vectors for normalizing
38725
38726					const v_prev_len = Math.sqrt( v_prev_lensq );
38727					const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
38728
38729					// shift adjacent points by unit vectors to the left
38730
38731					const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
38732					const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
38733
38734					const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
38735					const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
38736
38737					// scaling factor for v_prev to intersection point
38738
38739					const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
38740							( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
38741						( v_prev_x * v_next_y - v_prev_y * v_next_x );
38742
38743					// vector from inPt to intersection point
38744
38745					v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
38746					v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
38747
38748					// Don't normalize!, otherwise sharp corners become ugly
38749					//  but prevent crazy spikes
38750					const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
38751					if ( v_trans_lensq <= 2 ) {
38752
38753						return new Vector2( v_trans_x, v_trans_y );
38754
38755					} else {
38756
38757						shrink_by = Math.sqrt( v_trans_lensq / 2 );
38758
38759					}
38760
38761				} else {
38762
38763					// handle special case of collinear edges
38764
38765					let direction_eq = false; // assumes: opposite
38766
38767					if ( v_prev_x > Number.EPSILON ) {
38768
38769						if ( v_next_x > Number.EPSILON ) {
38770
38771							direction_eq = true;
38772
38773						}
38774
38775					} else {
38776
38777						if ( v_prev_x < - Number.EPSILON ) {
38778
38779							if ( v_next_x < - Number.EPSILON ) {
38780
38781								direction_eq = true;
38782
38783							}
38784
38785						} else {
38786
38787							if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
38788
38789								direction_eq = true;
38790
38791							}
38792
38793						}
38794
38795					}
38796
38797					if ( direction_eq ) {
38798
38799						// console.log("Warning: lines are a straight sequence");
38800						v_trans_x = - v_prev_y;
38801						v_trans_y = v_prev_x;
38802						shrink_by = Math.sqrt( v_prev_lensq );
38803
38804					} else {
38805
38806						// console.log("Warning: lines are a straight spike");
38807						v_trans_x = v_prev_x;
38808						v_trans_y = v_prev_y;
38809						shrink_by = Math.sqrt( v_prev_lensq / 2 );
38810
38811					}
38812
38813				}
38814
38815				return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
38816
38817			}
38818
38819
38820			const contourMovements = [];
38821
38822			for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38823
38824				if ( j === il ) j = 0;
38825				if ( k === il ) k = 0;
38826
38827				//  (j)---(i)---(k)
38828				// console.log('i,j,k', i, j , k)
38829
38830				contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
38831
38832			}
38833
38834			const holesMovements = [];
38835			let oneHoleMovements, verticesMovements = contourMovements.concat();
38836
38837			for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38838
38839				const ahole = holes[ h ];
38840
38841				oneHoleMovements = [];
38842
38843				for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38844
38845					if ( j === il ) j = 0;
38846					if ( k === il ) k = 0;
38847
38848					//  (j)---(i)---(k)
38849					oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
38850
38851				}
38852
38853				holesMovements.push( oneHoleMovements );
38854				verticesMovements = verticesMovements.concat( oneHoleMovements );
38855
38856			}
38857
38858
38859			// Loop bevelSegments, 1 for the front, 1 for the back
38860
38861			for ( let b = 0; b < bevelSegments; b ++ ) {
38862
38863				//for ( b = bevelSegments; b > 0; b -- ) {
38864
38865				const t = b / bevelSegments;
38866				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38867				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38868
38869				// contract shape
38870
38871				for ( let i = 0, il = contour.length; i < il; i ++ ) {
38872
38873					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38874
38875					v( vert.x, vert.y, - z );
38876
38877				}
38878
38879				// expand holes
38880
38881				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38882
38883					const ahole = holes[ h ];
38884					oneHoleMovements = holesMovements[ h ];
38885
38886					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38887
38888						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38889
38890						v( vert.x, vert.y, - z );
38891
38892					}
38893
38894				}
38895
38896			}
38897
38898			const bs = bevelSize + bevelOffset;
38899
38900			// Back facing vertices
38901
38902			for ( let i = 0; i < vlen; i ++ ) {
38903
38904				const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38905
38906				if ( ! extrudeByPath ) {
38907
38908					v( vert.x, vert.y, 0 );
38909
38910				} else {
38911
38912					// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
38913
38914					normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
38915					binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
38916
38917					position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
38918
38919					v( position2.x, position2.y, position2.z );
38920
38921				}
38922
38923			}
38924
38925			// Add stepped vertices...
38926			// Including front facing vertices
38927
38928			for ( let s = 1; s <= steps; s ++ ) {
38929
38930				for ( let i = 0; i < vlen; i ++ ) {
38931
38932					const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38933
38934					if ( ! extrudeByPath ) {
38935
38936						v( vert.x, vert.y, depth / steps * s );
38937
38938					} else {
38939
38940						// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
38941
38942						normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
38943						binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
38944
38945						position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
38946
38947						v( position2.x, position2.y, position2.z );
38948
38949					}
38950
38951				}
38952
38953			}
38954
38955
38956			// Add bevel segments planes
38957
38958			//for ( b = 1; b <= bevelSegments; b ++ ) {
38959			for ( let b = bevelSegments - 1; b >= 0; b -- ) {
38960
38961				const t = b / bevelSegments;
38962				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38963				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38964
38965				// contract shape
38966
38967				for ( let i = 0, il = contour.length; i < il; i ++ ) {
38968
38969					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38970					v( vert.x, vert.y, depth + z );
38971
38972				}
38973
38974				// expand holes
38975
38976				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38977
38978					const ahole = holes[ h ];
38979					oneHoleMovements = holesMovements[ h ];
38980
38981					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38982
38983						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38984
38985						if ( ! extrudeByPath ) {
38986
38987							v( vert.x, vert.y, depth + z );
38988
38989						} else {
38990
38991							v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
38992
38993						}
38994
38995					}
38996
38997				}
38998
38999			}
39000
39001			/* Faces */
39002
39003			// Top and bottom faces
39004
39005			buildLidFaces();
39006
39007			// Sides faces
39008
39009			buildSideFaces();
39010
39011
39012			/////  Internal functions
39013
39014			function buildLidFaces() {
39015
39016				const start = verticesArray.length / 3;
39017
39018				if ( bevelEnabled ) {
39019
39020					let layer = 0; // steps + 1
39021					let offset = vlen * layer;
39022
39023					// Bottom faces
39024
39025					for ( let i = 0; i < flen; i ++ ) {
39026
39027						const face = faces[ i ];
39028						f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
39029
39030					}
39031
39032					layer = steps + bevelSegments * 2;
39033					offset = vlen * layer;
39034
39035					// Top faces
39036
39037					for ( let i = 0; i < flen; i ++ ) {
39038
39039						const face = faces[ i ];
39040						f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
39041
39042					}
39043
39044				} else {
39045
39046					// Bottom faces
39047
39048					for ( let i = 0; i < flen; i ++ ) {
39049
39050						const face = faces[ i ];
39051						f3( face[ 2 ], face[ 1 ], face[ 0 ] );
39052
39053					}
39054
39055					// Top faces
39056
39057					for ( let i = 0; i < flen; i ++ ) {
39058
39059						const face = faces[ i ];
39060						f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
39061
39062					}
39063
39064				}
39065
39066				scope.addGroup( start, verticesArray.length / 3 - start, 0 );
39067
39068			}
39069
39070			// Create faces for the z-sides of the shape
39071
39072			function buildSideFaces() {
39073
39074				const start = verticesArray.length / 3;
39075				let layeroffset = 0;
39076				sidewalls( contour, layeroffset );
39077				layeroffset += contour.length;
39078
39079				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
39080
39081					const ahole = holes[ h ];
39082					sidewalls( ahole, layeroffset );
39083
39084					//, true
39085					layeroffset += ahole.length;
39086
39087				}
39088
39089
39090				scope.addGroup( start, verticesArray.length / 3 - start, 1 );
39091
39092
39093			}
39094
39095			function sidewalls( contour, layeroffset ) {
39096
39097				let i = contour.length;
39098
39099				while ( -- i >= 0 ) {
39100
39101					const j = i;
39102					let k = i - 1;
39103					if ( k < 0 ) k = contour.length - 1;
39104
39105					//console.log('b', i,j, i-1, k,vertices.length);
39106
39107					for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
39108
39109						const slen1 = vlen * s;
39110						const slen2 = vlen * ( s + 1 );
39111
39112						const a = layeroffset + j + slen1,
39113							b = layeroffset + k + slen1,
39114							c = layeroffset + k + slen2,
39115							d = layeroffset + j + slen2;
39116
39117						f4( a, b, c, d );
39118
39119					}
39120
39121				}
39122
39123			}
39124
39125			function v( x, y, z ) {
39126
39127				placeholder.push( x );
39128				placeholder.push( y );
39129				placeholder.push( z );
39130
39131			}
39132
39133
39134			function f3( a, b, c ) {
39135
39136				addVertex( a );
39137				addVertex( b );
39138				addVertex( c );
39139
39140				const nextIndex = verticesArray.length / 3;
39141				const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39142
39143				addUV( uvs[ 0 ] );
39144				addUV( uvs[ 1 ] );
39145				addUV( uvs[ 2 ] );
39146
39147			}
39148
39149			function f4( a, b, c, d ) {
39150
39151				addVertex( a );
39152				addVertex( b );
39153				addVertex( d );
39154
39155				addVertex( b );
39156				addVertex( c );
39157				addVertex( d );
39158
39159
39160				const nextIndex = verticesArray.length / 3;
39161				const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39162
39163				addUV( uvs[ 0 ] );
39164				addUV( uvs[ 1 ] );
39165				addUV( uvs[ 3 ] );
39166
39167				addUV( uvs[ 1 ] );
39168				addUV( uvs[ 2 ] );
39169				addUV( uvs[ 3 ] );
39170
39171			}
39172
39173			function addVertex( index ) {
39174
39175				verticesArray.push( placeholder[ index * 3 + 0 ] );
39176				verticesArray.push( placeholder[ index * 3 + 1 ] );
39177				verticesArray.push( placeholder[ index * 3 + 2 ] );
39178
39179			}
39180
39181
39182			function addUV( vector2 ) {
39183
39184				uvArray.push( vector2.x );
39185				uvArray.push( vector2.y );
39186
39187			}
39188
39189		}
39190
39191	}
39192
39193	copy( source ) {
39194
39195		super.copy( source );
39196
39197		this.parameters = Object.assign( {}, source.parameters );
39198
39199		return this;
39200
39201	}
39202
39203	toJSON() {
39204
39205		const data = super.toJSON();
39206
39207		const shapes = this.parameters.shapes;
39208		const options = this.parameters.options;
39209
39210		return toJSON$1( shapes, options, data );
39211
39212	}
39213
39214	static fromJSON( data, shapes ) {
39215
39216		const geometryShapes = [];
39217
39218		for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39219
39220			const shape = shapes[ data.shapes[ j ] ];
39221
39222			geometryShapes.push( shape );
39223
39224		}
39225
39226		const extrudePath = data.options.extrudePath;
39227
39228		if ( extrudePath !== undefined ) {
39229
39230			data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
39231
39232		}
39233
39234		return new ExtrudeGeometry( geometryShapes, data.options );
39235
39236	}
39237
39238}
39239
39240const WorldUVGenerator = {
39241
39242	generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
39243
39244		const a_x = vertices[ indexA * 3 ];
39245		const a_y = vertices[ indexA * 3 + 1 ];
39246		const b_x = vertices[ indexB * 3 ];
39247		const b_y = vertices[ indexB * 3 + 1 ];
39248		const c_x = vertices[ indexC * 3 ];
39249		const c_y = vertices[ indexC * 3 + 1 ];
39250
39251		return [
39252			new Vector2( a_x, a_y ),
39253			new Vector2( b_x, b_y ),
39254			new Vector2( c_x, c_y )
39255		];
39256
39257	},
39258
39259	generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
39260
39261		const a_x = vertices[ indexA * 3 ];
39262		const a_y = vertices[ indexA * 3 + 1 ];
39263		const a_z = vertices[ indexA * 3 + 2 ];
39264		const b_x = vertices[ indexB * 3 ];
39265		const b_y = vertices[ indexB * 3 + 1 ];
39266		const b_z = vertices[ indexB * 3 + 2 ];
39267		const c_x = vertices[ indexC * 3 ];
39268		const c_y = vertices[ indexC * 3 + 1 ];
39269		const c_z = vertices[ indexC * 3 + 2 ];
39270		const d_x = vertices[ indexD * 3 ];
39271		const d_y = vertices[ indexD * 3 + 1 ];
39272		const d_z = vertices[ indexD * 3 + 2 ];
39273
39274		if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {
39275
39276			return [
39277				new Vector2( a_x, 1 - a_z ),
39278				new Vector2( b_x, 1 - b_z ),
39279				new Vector2( c_x, 1 - c_z ),
39280				new Vector2( d_x, 1 - d_z )
39281			];
39282
39283		} else {
39284
39285			return [
39286				new Vector2( a_y, 1 - a_z ),
39287				new Vector2( b_y, 1 - b_z ),
39288				new Vector2( c_y, 1 - c_z ),
39289				new Vector2( d_y, 1 - d_z )
39290			];
39291
39292		}
39293
39294	}
39295
39296};
39297
39298function toJSON$1( shapes, options, data ) {
39299
39300	data.shapes = [];
39301
39302	if ( Array.isArray( shapes ) ) {
39303
39304		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39305
39306			const shape = shapes[ i ];
39307
39308			data.shapes.push( shape.uuid );
39309
39310		}
39311
39312	} else {
39313
39314		data.shapes.push( shapes.uuid );
39315
39316	}
39317
39318	data.options = Object.assign( {}, options );
39319
39320	if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
39321
39322	return data;
39323
39324}
39325
39326class IcosahedronGeometry extends PolyhedronGeometry {
39327
39328	constructor( radius = 1, detail = 0 ) {
39329
39330		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
39331
39332		const vertices = [
39333			- 1, t, 0, 	1, t, 0, 	- 1, - t, 0, 	1, - t, 0,
39334			0, - 1, t, 	0, 1, t,	0, - 1, - t, 	0, 1, - t,
39335			t, 0, - 1, 	t, 0, 1, 	- t, 0, - 1, 	- t, 0, 1
39336		];
39337
39338		const indices = [
39339			0, 11, 5, 	0, 5, 1, 	0, 1, 7, 	0, 7, 10, 	0, 10, 11,
39340			1, 5, 9, 	5, 11, 4,	11, 10, 2,	10, 7, 6,	7, 1, 8,
39341			3, 9, 4, 	3, 4, 2,	3, 2, 6,	3, 6, 8,	3, 8, 9,
39342			4, 9, 5, 	2, 4, 11,	6, 2, 10,	8, 6, 7,	9, 8, 1
39343		];
39344
39345		super( vertices, indices, radius, detail );
39346
39347		this.type = 'IcosahedronGeometry';
39348
39349		this.parameters = {
39350			radius: radius,
39351			detail: detail
39352		};
39353
39354	}
39355
39356	static fromJSON( data ) {
39357
39358		return new IcosahedronGeometry( data.radius, data.detail );
39359
39360	}
39361
39362}
39363
39364class OctahedronGeometry extends PolyhedronGeometry {
39365
39366	constructor( radius = 1, detail = 0 ) {
39367
39368		const vertices = [
39369			1, 0, 0, 	- 1, 0, 0,	0, 1, 0,
39370			0, - 1, 0, 	0, 0, 1,	0, 0, - 1
39371		];
39372
39373		const indices = [
39374			0, 2, 4,	0, 4, 3,	0, 3, 5,
39375			0, 5, 2,	1, 2, 5,	1, 5, 3,
39376			1, 3, 4,	1, 4, 2
39377		];
39378
39379		super( vertices, indices, radius, detail );
39380
39381		this.type = 'OctahedronGeometry';
39382
39383		this.parameters = {
39384			radius: radius,
39385			detail: detail
39386		};
39387
39388	}
39389
39390	static fromJSON( data ) {
39391
39392		return new OctahedronGeometry( data.radius, data.detail );
39393
39394	}
39395
39396}
39397
39398class RingGeometry extends BufferGeometry {
39399
39400	constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
39401
39402		super();
39403
39404		this.type = 'RingGeometry';
39405
39406		this.parameters = {
39407			innerRadius: innerRadius,
39408			outerRadius: outerRadius,
39409			thetaSegments: thetaSegments,
39410			phiSegments: phiSegments,
39411			thetaStart: thetaStart,
39412			thetaLength: thetaLength
39413		};
39414
39415		thetaSegments = Math.max( 3, thetaSegments );
39416		phiSegments = Math.max( 1, phiSegments );
39417
39418		// buffers
39419
39420		const indices = [];
39421		const vertices = [];
39422		const normals = [];
39423		const uvs = [];
39424
39425		// some helper variables
39426
39427		let radius = innerRadius;
39428		const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
39429		const vertex = new Vector3();
39430		const uv = new Vector2();
39431
39432		// generate vertices, normals and uvs
39433
39434		for ( let j = 0; j <= phiSegments; j ++ ) {
39435
39436			for ( let i = 0; i <= thetaSegments; i ++ ) {
39437
39438				// values are generate from the inside of the ring to the outside
39439
39440				const segment = thetaStart + i / thetaSegments * thetaLength;
39441
39442				// vertex
39443
39444				vertex.x = radius * Math.cos( segment );
39445				vertex.y = radius * Math.sin( segment );
39446
39447				vertices.push( vertex.x, vertex.y, vertex.z );
39448
39449				// normal
39450
39451				normals.push( 0, 0, 1 );
39452
39453				// uv
39454
39455				uv.x = ( vertex.x / outerRadius + 1 ) / 2;
39456				uv.y = ( vertex.y / outerRadius + 1 ) / 2;
39457
39458				uvs.push( uv.x, uv.y );
39459
39460			}
39461
39462			// increase the radius for next row of vertices
39463
39464			radius += radiusStep;
39465
39466		}
39467
39468		// indices
39469
39470		for ( let j = 0; j < phiSegments; j ++ ) {
39471
39472			const thetaSegmentLevel = j * ( thetaSegments + 1 );
39473
39474			for ( let i = 0; i < thetaSegments; i ++ ) {
39475
39476				const segment = i + thetaSegmentLevel;
39477
39478				const a = segment;
39479				const b = segment + thetaSegments + 1;
39480				const c = segment + thetaSegments + 2;
39481				const d = segment + 1;
39482
39483				// faces
39484
39485				indices.push( a, b, d );
39486				indices.push( b, c, d );
39487
39488			}
39489
39490		}
39491
39492		// build geometry
39493
39494		this.setIndex( indices );
39495		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39496		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39497		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39498
39499	}
39500
39501	copy( source ) {
39502
39503		super.copy( source );
39504
39505		this.parameters = Object.assign( {}, source.parameters );
39506
39507		return this;
39508
39509	}
39510
39511	static fromJSON( data ) {
39512
39513		return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength );
39514
39515	}
39516
39517}
39518
39519class ShapeGeometry extends BufferGeometry {
39520
39521	constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {
39522
39523		super();
39524
39525		this.type = 'ShapeGeometry';
39526
39527		this.parameters = {
39528			shapes: shapes,
39529			curveSegments: curveSegments
39530		};
39531
39532		// buffers
39533
39534		const indices = [];
39535		const vertices = [];
39536		const normals = [];
39537		const uvs = [];
39538
39539		// helper variables
39540
39541		let groupStart = 0;
39542		let groupCount = 0;
39543
39544		// allow single and array values for "shapes" parameter
39545
39546		if ( Array.isArray( shapes ) === false ) {
39547
39548			addShape( shapes );
39549
39550		} else {
39551
39552			for ( let i = 0; i < shapes.length; i ++ ) {
39553
39554				addShape( shapes[ i ] );
39555
39556				this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
39557
39558				groupStart += groupCount;
39559				groupCount = 0;
39560
39561			}
39562
39563		}
39564
39565		// build geometry
39566
39567		this.setIndex( indices );
39568		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,878 bytes, lines 39569-39815
39569		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39570		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39571
39572
39573		// helper functions
39574
39575		function addShape( shape ) {
39576
39577			const indexOffset = vertices.length / 3;
39578			const points = shape.extractPoints( curveSegments );
39579
39580			let shapeVertices = points.shape;
39581			const shapeHoles = points.holes;
39582
39583			// check direction of vertices
39584
39585			if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
39586
39587				shapeVertices = shapeVertices.reverse();
39588
39589			}
39590
39591			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39592
39593				const shapeHole = shapeHoles[ i ];
39594
39595				if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
39596
39597					shapeHoles[ i ] = shapeHole.reverse();
39598
39599				}
39600
39601			}
39602
39603			const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
39604
39605			// join vertices of inner and outer paths to a single array
39606
39607			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39608
39609				const shapeHole = shapeHoles[ i ];
39610				shapeVertices = shapeVertices.concat( shapeHole );
39611
39612			}
39613
39614			// vertices, normals, uvs
39615
39616			for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
39617
39618				const vertex = shapeVertices[ i ];
39619
39620				vertices.push( vertex.x, vertex.y, 0 );
39621				normals.push( 0, 0, 1 );
39622				uvs.push( vertex.x, vertex.y ); // world uvs
39623
39624			}
39625
39626			// indices
39627
39628			for ( let i = 0, l = faces.length; i < l; i ++ ) {
39629
39630				const face = faces[ i ];
39631
39632				const a = face[ 0 ] + indexOffset;
39633				const b = face[ 1 ] + indexOffset;
39634				const c = face[ 2 ] + indexOffset;
39635
39636				indices.push( a, b, c );
39637				groupCount += 3;
39638
39639			}
39640
39641		}
39642
39643	}
39644
39645	copy( source ) {
39646
39647		super.copy( source );
39648
39649		this.parameters = Object.assign( {}, source.parameters );
39650
39651		return this;
39652
39653	}
39654
39655	toJSON() {
39656
39657		const data = super.toJSON();
39658
39659		const shapes = this.parameters.shapes;
39660
39661		return toJSON( shapes, data );
39662
39663	}
39664
39665	static fromJSON( data, shapes ) {
39666
39667		const geometryShapes = [];
39668
39669		for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39670
39671			const shape = shapes[ data.shapes[ j ] ];
39672
39673			geometryShapes.push( shape );
39674
39675		}
39676
39677		return new ShapeGeometry( geometryShapes, data.curveSegments );
39678
39679	}
39680
39681}
39682
39683function toJSON( shapes, data ) {
39684
39685	data.shapes = [];
39686
39687	if ( Array.isArray( shapes ) ) {
39688
39689		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39690
39691			const shape = shapes[ i ];
39692
39693			data.shapes.push( shape.uuid );
39694
39695		}
39696
39697	} else {
39698
39699		data.shapes.push( shapes.uuid );
39700
39701	}
39702
39703	return data;
39704
39705}
39706
39707class SphereGeometry extends BufferGeometry {
39708
39709	constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
39710
39711		super();
39712
39713		this.type = 'SphereGeometry';
39714
39715		this.parameters = {
39716			radius: radius,
39717			widthSegments: widthSegments,
39718			heightSegments: heightSegments,
39719			phiStart: phiStart,
39720			phiLength: phiLength,
39721			thetaStart: thetaStart,
39722			thetaLength: thetaLength
39723		};
39724
39725		widthSegments = Math.max( 3, Math.floor( widthSegments ) );
39726		heightSegments = Math.max( 2, Math.floor( heightSegments ) );
39727
39728		const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
39729
39730		let index = 0;
39731		const grid = [];
39732
39733		const vertex = new Vector3();
39734		const normal = new Vector3();
39735
39736		// buffers
39737
39738		const indices = [];
39739		const vertices = [];
39740		const normals = [];
39741		const uvs = [];
39742
39743		// generate vertices, normals and uvs
39744
39745		for ( let iy = 0; iy <= heightSegments; iy ++ ) {
39746
39747			const verticesRow = [];
39748
39749			const v = iy / heightSegments;
39750
39751			// special case for the poles
39752
39753			let uOffset = 0;
39754
39755			if ( iy === 0 && thetaStart === 0 ) {
39756
39757				uOffset = 0.5 / widthSegments;
39758
39759			} else if ( iy === heightSegments && thetaEnd === Math.PI ) {
39760
39761				uOffset = - 0.5 / widthSegments;
39762
39763			}
39764
39765			for ( let ix = 0; ix <= widthSegments; ix ++ ) {
39766
39767				const u = ix / widthSegments;
39768
39769				// vertex
39770
39771				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
39772				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
39773				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
39774
39775				vertices.push( vertex.x, vertex.y, vertex.z );
39776
39777				// normal
39778
39779				normal.copy( vertex ).normalize();
39780				normals.push( normal.x, normal.y, normal.z );
39781
39782				// uv
39783
39784				uvs.push( u + uOffset, 1 - v );
39785
39786				verticesRow.push( index ++ );
39787
39788			}
39789
39790			grid.push( verticesRow );
39791
39792		}
39793
39794		// indices
39795
39796		for ( let iy = 0; iy < heightSegments; iy ++ ) {
39797
39798			for ( let ix = 0; ix < widthSegments; ix ++ ) {
39799
39800				const a = grid[ iy ][ ix + 1 ];
39801				const b = grid[ iy ][ ix ];
39802				const c = grid[ iy + 1 ][ ix ];
39803				const d = grid[ iy + 1 ][ ix + 1 ];
39804
39805				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
39806				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
39807
39808			}
39809
39810		}
39811
39812		// build geometry
39813
39814		this.setIndex( indices );
39815		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 6,566 bytes, lines 39816-40108
39816		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39817		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39818
39819	}
39820
39821	copy( source ) {
39822
39823		super.copy( source );
39824
39825		this.parameters = Object.assign( {}, source.parameters );
39826
39827		return this;
39828
39829	}
39830
39831	static fromJSON( data ) {
39832
39833		return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );
39834
39835	}
39836
39837}
39838
39839class TetrahedronGeometry extends PolyhedronGeometry {
39840
39841	constructor( radius = 1, detail = 0 ) {
39842
39843		const vertices = [
39844			1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
39845		];
39846
39847		const indices = [
39848			2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
39849		];
39850
39851		super( vertices, indices, radius, detail );
39852
39853		this.type = 'TetrahedronGeometry';
39854
39855		this.parameters = {
39856			radius: radius,
39857			detail: detail
39858		};
39859
39860	}
39861
39862	static fromJSON( data ) {
39863
39864		return new TetrahedronGeometry( data.radius, data.detail );
39865
39866	}
39867
39868}
39869
39870class TorusGeometry extends BufferGeometry {
39871
39872	constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) {
39873
39874		super();
39875
39876		this.type = 'TorusGeometry';
39877
39878		this.parameters = {
39879			radius: radius,
39880			tube: tube,
39881			radialSegments: radialSegments,
39882			tubularSegments: tubularSegments,
39883			arc: arc
39884		};
39885
39886		radialSegments = Math.floor( radialSegments );
39887		tubularSegments = Math.floor( tubularSegments );
39888
39889		// buffers
39890
39891		const indices = [];
39892		const vertices = [];
39893		const normals = [];
39894		const uvs = [];
39895
39896		// helper variables
39897
39898		const center = new Vector3();
39899		const vertex = new Vector3();
39900		const normal = new Vector3();
39901
39902		// generate vertices, normals and uvs
39903
39904		for ( let j = 0; j <= radialSegments; j ++ ) {
39905
39906			for ( let i = 0; i <= tubularSegments; i ++ ) {
39907
39908				const u = i / tubularSegments * arc;
39909				const v = j / radialSegments * Math.PI * 2;
39910
39911				// vertex
39912
39913				vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
39914				vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
39915				vertex.z = tube * Math.sin( v );
39916
39917				vertices.push( vertex.x, vertex.y, vertex.z );
39918
39919				// normal
39920
39921				center.x = radius * Math.cos( u );
39922				center.y = radius * Math.sin( u );
39923				normal.subVectors( vertex, center ).normalize();
39924
39925				normals.push( normal.x, normal.y, normal.z );
39926
39927				// uv
39928
39929				uvs.push( i / tubularSegments );
39930				uvs.push( j / radialSegments );
39931
39932			}
39933
39934		}
39935
39936		// generate indices
39937
39938		for ( let j = 1; j <= radialSegments; j ++ ) {
39939
39940			for ( let i = 1; i <= tubularSegments; i ++ ) {
39941
39942				// indices
39943
39944				const a = ( tubularSegments + 1 ) * j + i - 1;
39945				const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
39946				const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
39947				const d = ( tubularSegments + 1 ) * j + i;
39948
39949				// faces
39950
39951				indices.push( a, b, d );
39952				indices.push( b, c, d );
39953
39954			}
39955
39956		}
39957
39958		// build geometry
39959
39960		this.setIndex( indices );
39961		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39962		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39963		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39964
39965	}
39966
39967	copy( source ) {
39968
39969		super.copy( source );
39970
39971		this.parameters = Object.assign( {}, source.parameters );
39972
39973		return this;
39974
39975	}
39976
39977	static fromJSON( data ) {
39978
39979		return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc );
39980
39981	}
39982
39983}
39984
39985class TorusKnotGeometry extends BufferGeometry {
39986
39987	constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
39988
39989		super();
39990
39991		this.type = 'TorusKnotGeometry';
39992
39993		this.parameters = {
39994			radius: radius,
39995			tube: tube,
39996			tubularSegments: tubularSegments,
39997			radialSegments: radialSegments,
39998			p: p,
39999			q: q
40000		};
40001
40002		tubularSegments = Math.floor( tubularSegments );
40003		radialSegments = Math.floor( radialSegments );
40004
40005		// buffers
40006
40007		const indices = [];
40008		const vertices = [];
40009		const normals = [];
40010		const uvs = [];
40011
40012		// helper variables
40013
40014		const vertex = new Vector3();
40015		const normal = new Vector3();
40016
40017		const P1 = new Vector3();
40018		const P2 = new Vector3();
40019
40020		const B = new Vector3();
40021		const T = new Vector3();
40022		const N = new Vector3();
40023
40024		// generate vertices, normals and uvs
40025
40026		for ( let i = 0; i <= tubularSegments; ++ i ) {
40027
40028			// the radian "u" is used to calculate the position on the torus curve of the current tubular segment
40029
40030			const u = i / tubularSegments * p * Math.PI * 2;
40031
40032			// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
40033			// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
40034
40035			calculatePositionOnCurve( u, p, q, radius, P1 );
40036			calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
40037
40038			// calculate orthonormal basis
40039
40040			T.subVectors( P2, P1 );
40041			N.addVectors( P2, P1 );
40042			B.crossVectors( T, N );
40043			N.crossVectors( B, T );
40044
40045			// normalize B, N. T can be ignored, we don't use it
40046
40047			B.normalize();
40048			N.normalize();
40049
40050			for ( let j = 0; j <= radialSegments; ++ j ) {
40051
40052				// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
40053				// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
40054
40055				const v = j / radialSegments * Math.PI * 2;
40056				const cx = - tube * Math.cos( v );
40057				const cy = tube * Math.sin( v );
40058
40059				// now calculate the final vertex position.
40060				// first we orient the extrusion with our basis vectors, then we add it to the current position on the curve
40061
40062				vertex.x = P1.x + ( cx * N.x + cy * B.x );
40063				vertex.y = P1.y + ( cx * N.y + cy * B.y );
40064				vertex.z = P1.z + ( cx * N.z + cy * B.z );
40065
40066				vertices.push( vertex.x, vertex.y, vertex.z );
40067
40068				// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
40069
40070				normal.subVectors( vertex, P1 ).normalize();
40071
40072				normals.push( normal.x, normal.y, normal.z );
40073
40074				// uv
40075
40076				uvs.push( i / tubularSegments );
40077				uvs.push( j / radialSegments );
40078
40079			}
40080
40081		}
40082
40083		// generate indices
40084
40085		for ( let j = 1; j <= tubularSegments; j ++ ) {
40086
40087			for ( let i = 1; i <= radialSegments; i ++ ) {
40088
40089				// indices
40090
40091				const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40092				const b = ( radialSegments + 1 ) * j + ( i - 1 );
40093				const c = ( radialSegments + 1 ) * j + i;
40094				const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40095
40096				// faces
40097
40098				indices.push( a, b, d );
40099				indices.push( b, c, d );
40100
40101			}
40102
40103		}
40104
40105		// build geometry
40106
40107		this.setIndex( indices );
40108		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 7,450 bytes, lines 40109-40467
40109		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40110		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40111
40112		// this function calculates the current position on the torus curve
40113
40114		function calculatePositionOnCurve( u, p, q, radius, position ) {
40115
40116			const cu = Math.cos( u );
40117			const su = Math.sin( u );
40118			const quOverP = q / p * u;
40119			const cs = Math.cos( quOverP );
40120
40121			position.x = radius * ( 2 + cs ) * 0.5 * cu;
40122			position.y = radius * ( 2 + cs ) * su * 0.5;
40123			position.z = radius * Math.sin( quOverP ) * 0.5;
40124
40125		}
40126
40127	}
40128
40129	copy( source ) {
40130
40131		super.copy( source );
40132
40133		this.parameters = Object.assign( {}, source.parameters );
40134
40135		return this;
40136
40137	}
40138
40139	static fromJSON( data ) {
40140
40141		return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q );
40142
40143	}
40144
40145}
40146
40147class TubeGeometry extends BufferGeometry {
40148
40149	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 ) {
40150
40151		super();
40152
40153		this.type = 'TubeGeometry';
40154
40155		this.parameters = {
40156			path: path,
40157			tubularSegments: tubularSegments,
40158			radius: radius,
40159			radialSegments: radialSegments,
40160			closed: closed
40161		};
40162
40163		const frames = path.computeFrenetFrames( tubularSegments, closed );
40164
40165		// expose internals
40166
40167		this.tangents = frames.tangents;
40168		this.normals = frames.normals;
40169		this.binormals = frames.binormals;
40170
40171		// helper variables
40172
40173		const vertex = new Vector3();
40174		const normal = new Vector3();
40175		const uv = new Vector2();
40176		let P = new Vector3();
40177
40178		// buffer
40179
40180		const vertices = [];
40181		const normals = [];
40182		const uvs = [];
40183		const indices = [];
40184
40185		// create buffer data
40186
40187		generateBufferData();
40188
40189		// build geometry
40190
40191		this.setIndex( indices );
40192		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40193		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40194		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40195
40196		// functions
40197
40198		function generateBufferData() {
40199
40200			for ( let i = 0; i < tubularSegments; i ++ ) {
40201
40202				generateSegment( i );
40203
40204			}
40205
40206			// if the geometry is not closed, generate the last row of vertices and normals
40207			// at the regular position on the given path
40208			//
40209			// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
40210
40211			generateSegment( ( closed === false ) ? tubularSegments : 0 );
40212
40213			// uvs are generated in a separate function.
40214			// this makes it easy compute correct values for closed geometries
40215
40216			generateUVs();
40217
40218			// finally create faces
40219
40220			generateIndices();
40221
40222		}
40223
40224		function generateSegment( i ) {
40225
40226			// we use getPointAt to sample evenly distributed points from the given path
40227
40228			P = path.getPointAt( i / tubularSegments, P );
40229
40230			// retrieve corresponding normal and binormal
40231
40232			const N = frames.normals[ i ];
40233			const B = frames.binormals[ i ];
40234
40235			// generate normals and vertices for the current segment
40236
40237			for ( let j = 0; j <= radialSegments; j ++ ) {
40238
40239				const v = j / radialSegments * Math.PI * 2;
40240
40241				const sin = Math.sin( v );
40242				const cos = - Math.cos( v );
40243
40244				// normal
40245
40246				normal.x = ( cos * N.x + sin * B.x );
40247				normal.y = ( cos * N.y + sin * B.y );
40248				normal.z = ( cos * N.z + sin * B.z );
40249				normal.normalize();
40250
40251				normals.push( normal.x, normal.y, normal.z );
40252
40253				// vertex
40254
40255				vertex.x = P.x + radius * normal.x;
40256				vertex.y = P.y + radius * normal.y;
40257				vertex.z = P.z + radius * normal.z;
40258
40259				vertices.push( vertex.x, vertex.y, vertex.z );
40260
40261			}
40262
40263		}
40264
40265		function generateIndices() {
40266
40267			for ( let j = 1; j <= tubularSegments; j ++ ) {
40268
40269				for ( let i = 1; i <= radialSegments; i ++ ) {
40270
40271					const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40272					const b = ( radialSegments + 1 ) * j + ( i - 1 );
40273					const c = ( radialSegments + 1 ) * j + i;
40274					const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40275
40276					// faces
40277
40278					indices.push( a, b, d );
40279					indices.push( b, c, d );
40280
40281				}
40282
40283			}
40284
40285		}
40286
40287		function generateUVs() {
40288
40289			for ( let i = 0; i <= tubularSegments; i ++ ) {
40290
40291				for ( let j = 0; j <= radialSegments; j ++ ) {
40292
40293					uv.x = i / tubularSegments;
40294					uv.y = j / radialSegments;
40295
40296					uvs.push( uv.x, uv.y );
40297
40298				}
40299
40300			}
40301
40302		}
40303
40304	}
40305
40306	copy( source ) {
40307
40308		super.copy( source );
40309
40310		this.parameters = Object.assign( {}, source.parameters );
40311
40312		return this;
40313
40314	}
40315
40316	toJSON() {
40317
40318		const data = super.toJSON();
40319
40320		data.path = this.parameters.path.toJSON();
40321
40322		return data;
40323
40324	}
40325
40326	static fromJSON( data ) {
40327
40328		// This only works for built-in curves (e.g. CatmullRomCurve3).
40329		// User defined curves or instances of CurvePath will not be deserialized.
40330		return new TubeGeometry(
40331			new Curves[ data.path.type ]().fromJSON( data.path ),
40332			data.tubularSegments,
40333			data.radius,
40334			data.radialSegments,
40335			data.closed
40336		);
40337
40338	}
40339
40340}
40341
40342class WireframeGeometry extends BufferGeometry {
40343
40344	constructor( geometry = null ) {
40345
40346		super();
40347
40348		this.type = 'WireframeGeometry';
40349
40350		this.parameters = {
40351			geometry: geometry
40352		};
40353
40354		if ( geometry !== null ) {
40355
40356			// buffer
40357
40358			const vertices = [];
40359			const edges = new Set();
40360
40361			// helper variables
40362
40363			const start = new Vector3();
40364			const end = new Vector3();
40365
40366			if ( geometry.index !== null ) {
40367
40368				// indexed BufferGeometry
40369
40370				const position = geometry.attributes.position;
40371				const indices = geometry.index;
40372				let groups = geometry.groups;
40373
40374				if ( groups.length === 0 ) {
40375
40376					groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
40377
40378				}
40379
40380				// create a data structure that contains all edges without duplicates
40381
40382				for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
40383
40384					const group = groups[ o ];
40385
40386					const groupStart = group.start;
40387					const groupCount = group.count;
40388
40389					for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {
40390
40391						for ( let j = 0; j < 3; j ++ ) {
40392
40393							const index1 = indices.getX( i + j );
40394							const index2 = indices.getX( i + ( j + 1 ) % 3 );
40395
40396							start.fromBufferAttribute( position, index1 );
40397							end.fromBufferAttribute( position, index2 );
40398
40399							if ( isUniqueEdge( start, end, edges ) === true ) {
40400
40401								vertices.push( start.x, start.y, start.z );
40402								vertices.push( end.x, end.y, end.z );
40403
40404							}
40405
40406						}
40407
40408					}
40409
40410				}
40411
40412			} else {
40413
40414				// non-indexed BufferGeometry
40415
40416				const position = geometry.attributes.position;
40417
40418				for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
40419
40420					for ( let j = 0; j < 3; j ++ ) {
40421
40422						// three edges per triangle, an edge is represented as (index1, index2)
40423						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
40424
40425						const index1 = 3 * i + j;
40426						const index2 = 3 * i + ( ( j + 1 ) % 3 );
40427
40428						start.fromBufferAttribute( position, index1 );
40429						end.fromBufferAttribute( position, index2 );
40430
40431						if ( isUniqueEdge( start, end, edges ) === true ) {
40432
40433							vertices.push( start.x, start.y, start.z );
40434							vertices.push( end.x, end.y, end.z );
40435
40436						}
40437
40438					}
40439
40440				}
40441
40442			}
40443
40444			// build geometry
40445
40446			this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40447
40448		}
40449
40450	}
40451
40452	copy( source ) {
40453
40454		super.copy( source );
40455
40456		this.parameters = Object.assign( {}, source.parameters );
40457
40458		return this;
40459
40460	}
40461
40462}
40463
40464function isUniqueEdge( start, end, edges ) {
40465
40466	const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;
40467	const hash2 = `${end.x}
40467,${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge
40468
40469	if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {
40470
40471		return false;
40472
40473	} else {
40474
40475		edges.add( hash1 );
40476		edges.add( hash2 );
40477		return true;
40478
40479	}
40480
40481}
40482
40483var Geometries = /*#__PURE__*/Object.freeze({
40484	__proto__: null,
40485	BoxGeometry: BoxGeometry,
40486	CapsuleGeometry: CapsuleGeometry,
40487	CircleGeometry: CircleGeometry,
40488	ConeGeometry: ConeGeometry,
40489	CylinderGeometry: CylinderGeometry,
40490	DodecahedronGeometry: DodecahedronGeometry,
40491	EdgesGeometry: EdgesGeometry,
40492	ExtrudeGeometry: ExtrudeGeometry,
40493	IcosahedronGeometry: IcosahedronGeometry,
40494	LatheGeometry: LatheGeometry,
40495	OctahedronGeometry: OctahedronGeometry,
40496	PlaneGeometry: PlaneGeometry,
40497	PolyhedronGeometry: PolyhedronGeometry,
40498	RingGeometry: RingGeometry,
40499	ShapeGeometry: ShapeGeometry,
40500	SphereGeometry: SphereGeometry,
40501	TetrahedronGeometry: TetrahedronGeometry,
40502	TorusGeometry: TorusGeometry,
40503	TorusKnotGeometry: TorusKnotGeometry,
40504	TubeGeometry: TubeGeometry,
40505	WireframeGeometry: WireframeGeometry
40506});
40507
40508class ShadowMaterial extends Material {
40509
40510	constructor( parameters ) {
40511
40512		super();
40513
40514		this.isShadowMaterial = true;
40515
40516		this.type = 'ShadowMaterial';
40517
40518		this.color = new Color( 0x000000 );
40519		this.transparent = true;
40520
40521		this.fog = true;
40522
40523		this.setValues( parameters );
40524
40525	}
40526
40527	copy( source ) {
40528
40529		super.copy( source );
40530
40531		this.color.copy( source.color );
40532
40533		this.fog = source.fog;
40534
40535		return this;
40536
40537	}
40538
40539}
40540
40541class RawShaderMaterial extends ShaderMaterial {
40542
40543	constructor( parameters ) {
40544
40545		super( parameters );
40546
40547		this.isRawShaderMaterial = true;
40548
40549		this.type = 'RawShaderMaterial';
40550
40551	}
40552
40553}
40554
40555class MeshStandardMaterial extends Material {
40556
40557	constructor( parameters ) {
40558
40559		super();
40560
40561		this.isMeshStandardMaterial = true;
40562
40563		this.defines = { 'STANDARD': '' };
40564
40565		this.type = 'MeshStandardMaterial';
40566
40567		this.color = new Color( 0xffffff ); // diffuse
40568		this.roughness = 1.0;
40569		this.metalness = 0.0;
40570
40571		this.map = null;
40572
40573		this.lightMap = null;
40574		this.lightMapIntensity = 1.0;
40575
40576		this.aoMap = null;
40577		this.aoMapIntensity = 1.0;
40578
40579		this.emissive = new Color( 0x000000 );
40580		this.emissiveIntensity = 1.0;
40581		this.emissiveMap = null;
40582
40583		this.bumpMap = null;
40584		this.bumpScale = 1;
40585
40586		this.normalMap = null;
40587		this.normalMapType = TangentSpaceNormalMap;
40588		this.normalScale = new Vector2( 1, 1 );
40589
40590		this.displacementMap = null;
40591		this.displacementScale = 1;
40592		this.displacementBias = 0;
40593
40594		this.roughnessMap = null;
40595
40596		this.metalnessMap = null;
40597
40598		this.alphaMap = null;
40599
40600		this.envMap = null;
40601		this.envMapIntensity = 1.0;
40602
40603		this.wireframe = false;
40604		this.wireframeLinewidth = 1;
40605		this.wireframeLinecap = 'round';
40606		this.wireframeLinejoin = 'round';
40607
40608		this.flatShading = false;
40609
40610		this.fog = true;
40611
40612		this.setValues( parameters );
40613
40614	}
40615
40616	copy( source ) {
40617
40618		super.copy( source );
40619
40620		this.defines = { 'STANDARD': '' };
40621
40622		this.color.copy( source.color );
40623		this.roughness = source.roughness;
40624		this.metalness = source.metalness;
40625
40626		this.map = source.map;
40627
40628		this.lightMap = source.lightMap;
40629		this.lightMapIntensity = source.lightMapIntensity;
40630
40631		this.aoMap = source.aoMap;
40632		this.aoMapIntensity = source.aoMapIntensity;
40633
40634		this.emissive.copy( source.emissive );
40635		this.emissiveMap = source.emissiveMap;
40636		this.emissiveIntensity = source.emissiveIntensity;
40637
40638		this.bumpMap = source.bumpMap;
40639		this.bumpScale = source.bumpScale;
40640
40641		this.normalMap = source.normalMap;
40642		this.normalMapType = source.normalMapType;
40643		this.normalScale.copy( source.normalScale );
40644
40645		this.displacementMap = source.displacementMap;
40646		this.displacementScale = source.displacementScale;
40647		this.displacementBias = source.displacementBias;
40648
40649		this.roughnessMap = source.roughnessMap;
40650
40651		this.metalnessMap = source.metalnessMap;
40652
40653		this.alphaMap = source.alphaMap;
40654
40655		this.envMap = source.envMap;
40656		this.envMapIntensity = source.envMapIntensity;
40657
40658		this.wireframe = source.wireframe;
40659		this.wireframeLinewidth = source.wireframeLinewidth;
40660		this.wireframeLinecap = source.wireframeLinecap;
40661		this.wireframeLinejoin = source.wireframeLinejoin;
40662
40663		this.flatShading = source.flatShading;
40664
40665		this.fog = source.fog;
40666
40667		return this;
40668
40669	}
40670
40671}
40672
40673class MeshPhysicalMaterial extends MeshStandardMaterial {
40674
40675	constructor( parameters ) {
40676
40677		super();
40678
40679		this.isMeshPhysicalMaterial = true;
40680
40681		this.defines = {
40682
40683			'STANDARD': '',
40684			'PHYSICAL': ''
40685
40686		};
40687
40688		this.type = 'MeshPhysicalMaterial';
40689
40690		this.anisotropyRotation = 0;
40691		this.anisotropyMap = null;
40692
40693		this.clearcoatMap = null;
40694		this.clearcoatRoughness = 0.0;
40695		this.clearcoatRoughnessMap = null;
40696		this.clearcoatNormalScale = new Vector2( 1, 1 );
40697		this.clearcoatNormalMap = null;
40698
40699		this.ior = 1.5;
40700
40701		Object.defineProperty( this, 'reflectivity', {
40702			get: function () {
40703
40704				return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );
40705
40706			},
vendor: 29,008 bytes, lines 40707-42164
40707			set: function ( reflectivity ) {
40708
40709				this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );
40710
40711			}
40712		} );
40713
40714		this.iridescenceMap = null;
40715		this.iridescenceIOR = 1.3;
40716		this.iridescenceThicknessRange = [ 100, 400 ];
40717		this.iridescenceThicknessMap = null;
40718
40719		this.sheenColor = new Color( 0x000000 );
40720		this.sheenColorMap = null;
40721		this.sheenRoughness = 1.0;
40722		this.sheenRoughnessMap = null;
40723
40724		this.transmissionMap = null;
40725
40726		this.thickness = 0;
40727		this.thicknessMap = null;
40728		this.attenuationDistance = Infinity;
40729		this.attenuationColor = new Color( 1, 1, 1 );
40730
40731		this.specularIntensity = 1.0;
40732		this.specularIntensityMap = null;
40733		this.specularColor = new Color( 1, 1, 1 );
40734		this.specularColorMap = null;
40735
40736		this._anisotropy = 0;
40737		this._clearcoat = 0;
40738		this._iridescence = 0;
40739		this._sheen = 0.0;
40740		this._transmission = 0;
40741
40742		this.setValues( parameters );
40743
40744	}
40745
40746	get anisotropy() {
40747
40748		return this._anisotropy;
40749
40750	}
40751
40752	set anisotropy( value ) {
40753
40754		if ( this._anisotropy > 0 !== value > 0 ) {
40755
40756			this.version ++;
40757
40758		}
40759
40760		this._anisotropy = value;
40761
40762	}
40763
40764	get clearcoat() {
40765
40766		return this._clearcoat;
40767
40768	}
40769
40770	set clearcoat( value ) {
40771
40772		if ( this._clearcoat > 0 !== value > 0 ) {
40773
40774			this.version ++;
40775
40776		}
40777
40778		this._clearcoat = value;
40779
40780	}
40781
40782	get iridescence() {
40783
40784		return this._iridescence;
40785
40786	}
40787
40788	set iridescence( value ) {
40789
40790		if ( this._iridescence > 0 !== value > 0 ) {
40791
40792			this.version ++;
40793
40794		}
40795
40796		this._iridescence = value;
40797
40798	}
40799
40800	get sheen() {
40801
40802		return this._sheen;
40803
40804	}
40805
40806	set sheen( value ) {
40807
40808		if ( this._sheen > 0 !== value > 0 ) {
40809
40810			this.version ++;
40811
40812		}
40813
40814		this._sheen = value;
40815
40816	}
40817
40818	get transmission() {
40819
40820		return this._transmission;
40821
40822	}
40823
40824	set transmission( value ) {
40825
40826		if ( this._transmission > 0 !== value > 0 ) {
40827
40828			this.version ++;
40829
40830		}
40831
40832		this._transmission = value;
40833
40834	}
40835
40836	copy( source ) {
40837
40838		super.copy( source );
40839
40840		this.defines = {
40841
40842			'STANDARD': '',
40843			'PHYSICAL': ''
40844
40845		};
40846
40847		this.anisotropy = source.anisotropy;
40848		this.anisotropyRotation = source.anisotropyRotation;
40849		this.anisotropyMap = source.anisotropyMap;
40850
40851		this.clearcoat = source.clearcoat;
40852		this.clearcoatMap = source.clearcoatMap;
40853		this.clearcoatRoughness = source.clearcoatRoughness;
40854		this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
40855		this.clearcoatNormalMap = source.clearcoatNormalMap;
40856		this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
40857
40858		this.ior = source.ior;
40859
40860		this.iridescence = source.iridescence;
40861		this.iridescenceMap = source.iridescenceMap;
40862		this.iridescenceIOR = source.iridescenceIOR;
40863		this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];
40864		this.iridescenceThicknessMap = source.iridescenceThicknessMap;
40865
40866		this.sheen = source.sheen;
40867		this.sheenColor.copy( source.sheenColor );
40868		this.sheenColorMap = source.sheenColorMap;
40869		this.sheenRoughness = source.sheenRoughness;
40870		this.sheenRoughnessMap = source.sheenRoughnessMap;
40871
40872		this.transmission = source.transmission;
40873		this.transmissionMap = source.transmissionMap;
40874
40875		this.thickness = source.thickness;
40876		this.thicknessMap = source.thicknessMap;
40877		this.attenuationDistance = source.attenuationDistance;
40878		this.attenuationColor.copy( source.attenuationColor );
40879
40880		this.specularIntensity = source.specularIntensity;
40881		this.specularIntensityMap = source.specularIntensityMap;
40882		this.specularColor.copy( source.specularColor );
40883		this.specularColorMap = source.specularColorMap;
40884
40885		return this;
40886
40887	}
40888
40889}
40890
40891class MeshPhongMaterial extends Material {
40892
40893	constructor( parameters ) {
40894
40895		super();
40896
40897		this.isMeshPhongMaterial = true;
40898
40899		this.type = 'MeshPhongMaterial';
40900
40901		this.color = new Color( 0xffffff ); // diffuse
40902		this.specular = new Color( 0x111111 );
40903		this.shininess = 30;
40904
40905		this.map = null;
40906
40907		this.lightMap = null;
40908		this.lightMapIntensity = 1.0;
40909
40910		this.aoMap = null;
40911		this.aoMapIntensity = 1.0;
40912
40913		this.emissive = new Color( 0x000000 );
40914		this.emissiveIntensity = 1.0;
40915		this.emissiveMap = null;
40916
40917		this.bumpMap = null;
40918		this.bumpScale = 1;
40919
40920		this.normalMap = null;
40921		this.normalMapType = TangentSpaceNormalMap;
40922		this.normalScale = new Vector2( 1, 1 );
40923
40924		this.displacementMap = null;
40925		this.displacementScale = 1;
40926		this.displacementBias = 0;
40927
40928		this.specularMap = null;
40929
40930		this.alphaMap = null;
40931
40932		this.envMap = null;
40933		this.combine = MultiplyOperation;
40934		this.reflectivity = 1;
40935		this.refractionRatio = 0.98;
40936
40937		this.wireframe = false;
40938		this.wireframeLinewidth = 1;
40939		this.wireframeLinecap = 'round';
40940		this.wireframeLinejoin = 'round';
40941
40942		this.flatShading = false;
40943
40944		this.fog = true;
40945
40946		this.setValues( parameters );
40947
40948	}
40949
40950	copy( source ) {
40951
40952		super.copy( source );
40953
40954		this.color.copy( source.color );
40955		this.specular.copy( source.specular );
40956		this.shininess = source.shininess;
40957
40958		this.map = source.map;
40959
40960		this.lightMap = source.lightMap;
40961		this.lightMapIntensity = source.lightMapIntensity;
40962
40963		this.aoMap = source.aoMap;
40964		this.aoMapIntensity = source.aoMapIntensity;
40965
40966		this.emissive.copy( source.emissive );
40967		this.emissiveMap = source.emissiveMap;
40968		this.emissiveIntensity = source.emissiveIntensity;
40969
40970		this.bumpMap = source.bumpMap;
40971		this.bumpScale = source.bumpScale;
40972
40973		this.normalMap = source.normalMap;
40974		this.normalMapType = source.normalMapType;
40975		this.normalScale.copy( source.normalScale );
40976
40977		this.displacementMap = source.displacementMap;
40978		this.displacementScale = source.displacementScale;
40979		this.displacementBias = source.displacementBias;
40980
40981		this.specularMap = source.specularMap;
40982
40983		this.alphaMap = source.alphaMap;
40984
40985		this.envMap = source.envMap;
40986		this.combine = source.combine;
40987		this.reflectivity = source.reflectivity;
40988		this.refractionRatio = source.refractionRatio;
40989
40990		this.wireframe = source.wireframe;
40991		this.wireframeLinewidth = source.wireframeLinewidth;
40992		this.wireframeLinecap = source.wireframeLinecap;
40993		this.wireframeLinejoin = source.wireframeLinejoin;
40994
40995		this.flatShading = source.flatShading;
40996
40997		this.fog = source.fog;
40998
40999		return this;
41000
41001	}
41002
41003}
41004
41005class MeshToonMaterial extends Material {
41006
41007	constructor( parameters ) {
41008
41009		super();
41010
41011		this.isMeshToonMaterial = true;
41012
41013		this.defines = { 'TOON': '' };
41014
41015		this.type = 'MeshToonMaterial';
41016
41017		this.color = new Color( 0xffffff );
41018
41019		this.map = null;
41020		this.gradientMap = null;
41021
41022		this.lightMap = null;
41023		this.lightMapIntensity = 1.0;
41024
41025		this.aoMap = null;
41026		this.aoMapIntensity = 1.0;
41027
41028		this.emissive = new Color( 0x000000 );
41029		this.emissiveIntensity = 1.0;
41030		this.emissiveMap = null;
41031
41032		this.bumpMap = null;
41033		this.bumpScale = 1;
41034
41035		this.normalMap = null;
41036		this.normalMapType = TangentSpaceNormalMap;
41037		this.normalScale = new Vector2( 1, 1 );
41038
41039		this.displacementMap = null;
41040		this.displacementScale = 1;
41041		this.displacementBias = 0;
41042
41043		this.alphaMap = null;
41044
41045		this.wireframe = false;
41046		this.wireframeLinewidth = 1;
41047		this.wireframeLinecap = 'round';
41048		this.wireframeLinejoin = 'round';
41049
41050		this.fog = true;
41051
41052		this.setValues( parameters );
41053
41054	}
41055
41056	copy( source ) {
41057
41058		super.copy( source );
41059
41060		this.color.copy( source.color );
41061
41062		this.map = source.map;
41063		this.gradientMap = source.gradientMap;
41064
41065		this.lightMap = source.lightMap;
41066		this.lightMapIntensity = source.lightMapIntensity;
41067
41068		this.aoMap = source.aoMap;
41069		this.aoMapIntensity = source.aoMapIntensity;
41070
41071		this.emissive.copy( source.emissive );
41072		this.emissiveMap = source.emissiveMap;
41073		this.emissiveIntensity = source.emissiveIntensity;
41074
41075		this.bumpMap = source.bumpMap;
41076		this.bumpScale = source.bumpScale;
41077
41078		this.normalMap = source.normalMap;
41079		this.normalMapType = source.normalMapType;
41080		this.normalScale.copy( source.normalScale );
41081
41082		this.displacementMap = source.displacementMap;
41083		this.displacementScale = source.displacementScale;
41084		this.displacementBias = source.displacementBias;
41085
41086		this.alphaMap = source.alphaMap;
41087
41088		this.wireframe = source.wireframe;
41089		this.wireframeLinewidth = source.wireframeLinewidth;
41090		this.wireframeLinecap = source.wireframeLinecap;
41091		this.wireframeLinejoin = source.wireframeLinejoin;
41092
41093		this.fog = source.fog;
41094
41095		return this;
41096
41097	}
41098
41099}
41100
41101class MeshNormalMaterial extends Material {
41102
41103	constructor( parameters ) {
41104
41105		super();
41106
41107		this.isMeshNormalMaterial = true;
41108
41109		this.type = 'MeshNormalMaterial';
41110
41111		this.bumpMap = null;
41112		this.bumpScale = 1;
41113
41114		this.normalMap = null;
41115		this.normalMapType = TangentSpaceNormalMap;
41116		this.normalScale = new Vector2( 1, 1 );
41117
41118		this.displacementMap = null;
41119		this.displacementScale = 1;
41120		this.displacementBias = 0;
41121
41122		this.wireframe = false;
41123		this.wireframeLinewidth = 1;
41124
41125		this.flatShading = false;
41126
41127		this.setValues( parameters );
41128
41129	}
41130
41131	copy( source ) {
41132
41133		super.copy( source );
41134
41135		this.bumpMap = source.bumpMap;
41136		this.bumpScale = source.bumpScale;
41137
41138		this.normalMap = source.normalMap;
41139		this.normalMapType = source.normalMapType;
41140		this.normalScale.copy( source.normalScale );
41141
41142		this.displacementMap = source.displacementMap;
41143		this.displacementScale = source.displacementScale;
41144		this.displacementBias = source.displacementBias;
41145
41146		this.wireframe = source.wireframe;
41147		this.wireframeLinewidth = source.wireframeLinewidth;
41148
41149		this.flatShading = source.flatShading;
41150
41151		return this;
41152
41153	}
41154
41155}
41156
41157class MeshLambertMaterial extends Material {
41158
41159	constructor( parameters ) {
41160
41161		super();
41162
41163		this.isMeshLambertMaterial = true;
41164
41165		this.type = 'MeshLambertMaterial';
41166
41167		this.color = new Color( 0xffffff ); // diffuse
41168
41169		this.map = null;
41170
41171		this.lightMap = null;
41172		this.lightMapIntensity = 1.0;
41173
41174		this.aoMap = null;
41175		this.aoMapIntensity = 1.0;
41176
41177		this.emissive = new Color( 0x000000 );
41178		this.emissiveIntensity = 1.0;
41179		this.emissiveMap = null;
41180
41181		this.bumpMap = null;
41182		this.bumpScale = 1;
41183
41184		this.normalMap = null;
41185		this.normalMapType = TangentSpaceNormalMap;
41186		this.normalScale = new Vector2( 1, 1 );
41187
41188		this.displacementMap = null;
41189		this.displacementScale = 1;
41190		this.displacementBias = 0;
41191
41192		this.specularMap = null;
41193
41194		this.alphaMap = null;
41195
41196		this.envMap = null;
41197		this.combine = MultiplyOperation;
41198		this.reflectivity = 1;
41199		this.refractionRatio = 0.98;
41200
41201		this.wireframe = false;
41202		this.wireframeLinewidth = 1;
41203		this.wireframeLinecap = 'round';
41204		this.wireframeLinejoin = 'round';
41205
41206		this.flatShading = false;
41207
41208		this.fog = true;
41209
41210		this.setValues( parameters );
41211
41212	}
41213
41214	copy( source ) {
41215
41216		super.copy( source );
41217
41218		this.color.copy( source.color );
41219
41220		this.map = source.map;
41221
41222		this.lightMap = source.lightMap;
41223		this.lightMapIntensity = source.lightMapIntensity;
41224
41225		this.aoMap = source.aoMap;
41226		this.aoMapIntensity = source.aoMapIntensity;
41227
41228		this.emissive.copy( source.emissive );
41229		this.emissiveMap = source.emissiveMap;
41230		this.emissiveIntensity = source.emissiveIntensity;
41231
41232		this.bumpMap = source.bumpMap;
41233		this.bumpScale = source.bumpScale;
41234
41235		this.normalMap = source.normalMap;
41236		this.normalMapType = source.normalMapType;
41237		this.normalScale.copy( source.normalScale );
41238
41239		this.displacementMap = source.displacementMap;
41240		this.displacementScale = source.displacementScale;
41241		this.displacementBias = source.displacementBias;
41242
41243		this.specularMap = source.specularMap;
41244
41245		this.alphaMap = source.alphaMap;
41246
41247		this.envMap = source.envMap;
41248		this.combine = source.combine;
41249		this.reflectivity = source.reflectivity;
41250		this.refractionRatio = source.refractionRatio;
41251
41252		this.wireframe = source.wireframe;
41253		this.wireframeLinewidth = source.wireframeLinewidth;
41254		this.wireframeLinecap = source.wireframeLinecap;
41255		this.wireframeLinejoin = source.wireframeLinejoin;
41256
41257		this.flatShading = source.flatShading;
41258
41259		this.fog = source.fog;
41260
41261		return this;
41262
41263	}
41264
41265}
41266
41267class MeshMatcapMaterial extends Material {
41268
41269	constructor( parameters ) {
41270
41271		super();
41272
41273		this.isMeshMatcapMaterial = true;
41274
41275		this.defines = { 'MATCAP': '' };
41276
41277		this.type = 'MeshMatcapMaterial';
41278
41279		this.color = new Color( 0xffffff ); // diffuse
41280
41281		this.matcap = null;
41282
41283		this.map = null;
41284
41285		this.bumpMap = null;
41286		this.bumpScale = 1;
41287
41288		this.normalMap = null;
41289		this.normalMapType = TangentSpaceNormalMap;
41290		this.normalScale = new Vector2( 1, 1 );
41291
41292		this.displacementMap = null;
41293		this.displacementScale = 1;
41294		this.displacementBias = 0;
41295
41296		this.alphaMap = null;
41297
41298		this.flatShading = false;
41299
41300		this.fog = true;
41301
41302		this.setValues( parameters );
41303
41304	}
41305
41306
41307	copy( source ) {
41308
41309		super.copy( source );
41310
41311		this.defines = { 'MATCAP': '' };
41312
41313		this.color.copy( source.color );
41314
41315		this.matcap = source.matcap;
41316
41317		this.map = source.map;
41318
41319		this.bumpMap = source.bumpMap;
41320		this.bumpScale = source.bumpScale;
41321
41322		this.normalMap = source.normalMap;
41323		this.normalMapType = source.normalMapType;
41324		this.normalScale.copy( source.normalScale );
41325
41326		this.displacementMap = source.displacementMap;
41327		this.displacementScale = source.displacementScale;
41328		this.displacementBias = source.displacementBias;
41329
41330		this.alphaMap = source.alphaMap;
41331
41332		this.flatShading = source.flatShading;
41333
41334		this.fog = source.fog;
41335
41336		return this;
41337
41338	}
41339
41340}
41341
41342class LineDashedMaterial extends LineBasicMaterial {
41343
41344	constructor( parameters ) {
41345
41346		super();
41347
41348		this.isLineDashedMaterial = true;
41349
41350		this.type = 'LineDashedMaterial';
41351
41352		this.scale = 1;
41353		this.dashSize = 3;
41354		this.gapSize = 1;
41355
41356		this.setValues( parameters );
41357
41358	}
41359
41360	copy( source ) {
41361
41362		super.copy( source );
41363
41364		this.scale = source.scale;
41365		this.dashSize = source.dashSize;
41366		this.gapSize = source.gapSize;
41367
41368		return this;
41369
41370	}
41371
41372}
41373
41374// converts an array to a specific type
41375function convertArray( array, type, forceClone ) {
41376
41377	if ( ! array || // let 'undefined' and 'null' pass
41378		! forceClone && array.constructor === type ) return array;
41379
41380	if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
41381
41382		return new type( array ); // create typed array
41383
41384	}
41385
41386	return Array.prototype.slice.call( array ); // create Array
41387
41388}
41389
41390function isTypedArray( object ) {
41391
41392	return ArrayBuffer.isView( object ) &&
41393		! ( object instanceof DataView );
41394
41395}
41396
41397// returns an array by which times and values can be sorted
41398function getKeyframeOrder( times ) {
41399
41400	function compareTime( i, j ) {
41401
41402		return times[ i ] - times[ j ];
41403
41404	}
41405
41406	const n = times.length;
41407	const result = new Array( n );
41408	for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
41409
41410	result.sort( compareTime );
41411
41412	return result;
41413
41414}
41415
41416// uses the array previously returned by 'getKeyframeOrder' to sort data
41417function sortedArray( values, stride, order ) {
41418
41419	const nValues = values.length;
41420	const result = new values.constructor( nValues );
41421
41422	for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
41423
41424		const srcOffset = order[ i ] * stride;
41425
41426		for ( let j = 0; j !== stride; ++ j ) {
41427
41428			result[ dstOffset ++ ] = values[ srcOffset + j ];
41429
41430		}
41431
41432	}
41433
41434	return result;
41435
41436}
41437
41438// function for parsing AOS keyframe formats
41439function flattenJSON( jsonKeys, times, values, valuePropertyName ) {
41440
41441	let i = 1, key = jsonKeys[ 0 ];
41442
41443	while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
41444
41445		key = jsonKeys[ i ++ ];
41446
41447	}
41448
41449	if ( key === undefined ) return; // no data
41450
41451	let value = key[ valuePropertyName ];
41452	if ( value === undefined ) return; // no data
41453
41454	if ( Array.isArray( value ) ) {
41455
41456		do {
41457
41458			value = key[ valuePropertyName ];
41459
41460			if ( value !== undefined ) {
41461
41462				times.push( key.time );
41463				values.push.apply( values, value ); // push all elements
41464
41465			}
41466
41467			key = jsonKeys[ i ++ ];
41468
41469		} while ( key !== undefined );
41470
41471	} else if ( value.toArray !== undefined ) {
41472
41473		// ...assume THREE.Math-ish
41474
41475		do {
41476
41477			value = key[ valuePropertyName ];
41478
41479			if ( value !== undefined ) {
41480
41481				times.push( key.time );
41482				value.toArray( values, values.length );
41483
41484			}
41485
41486			key = jsonKeys[ i ++ ];
41487
41488		} while ( key !== undefined );
41489
41490	} else {
41491
41492		// otherwise push as-is
41493
41494		do {
41495
41496			value = key[ valuePropertyName ];
41497
41498			if ( value !== undefined ) {
41499
41500				times.push( key.time );
41501				values.push( value );
41502
41503			}
41504
41505			key = jsonKeys[ i ++ ];
41506
41507		} while ( key !== undefined );
41508
41509	}
41510
41511}
41512
41513function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {
41514
41515	const clip = sourceClip.clone();
41516
41517	clip.name = name;
41518
41519	const tracks = [];
41520
41521	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41522
41523		const track = clip.tracks[ i ];
41524		const valueSize = track.getValueSize();
41525
41526		const times = [];
41527		const values = [];
41528
41529		for ( let j = 0; j < track.times.length; ++ j ) {
41530
41531			const frame = track.times[ j ] * fps;
41532
41533			if ( frame < startFrame || frame >= endFrame ) continue;
41534
41535			times.push( track.times[ j ] );
41536
41537			for ( let k = 0; k < valueSize; ++ k ) {
41538
41539				values.push( track.values[ j * valueSize + k ] );
41540
41541			}
41542
41543		}
41544
41545		if ( times.length === 0 ) continue;
41546
41547		track.times = convertArray( times, track.times.constructor );
41548		track.values = convertArray( values, track.values.constructor );
41549
41550		tracks.push( track );
41551
41552	}
41553
41554	clip.tracks = tracks;
41555
41556	// find minimum .times value across all tracks in the trimmed clip
41557
41558	let minStartTime = Infinity;
41559
41560	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41561
41562		if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
41563
41564			minStartTime = clip.tracks[ i ].times[ 0 ];
41565
41566		}
41567
41568	}
41569
41570	// shift all tracks such that clip begins at t=0
41571
41572	for ( let i = 0; i < clip.tracks.length; ++ i ) {
41573
41574		clip.tracks[ i ].shift( - 1 * minStartTime );
41575
41576	}
41577
41578	clip.resetDuration();
41579
41580	return clip;
41581
41582}
41583
41584function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
41585
41586	if ( fps <= 0 ) fps = 30;
41587
41588	const numTracks = referenceClip.tracks.length;
41589	const referenceTime = referenceFrame / fps;
41590
41591	// Make each track's values relative to the values at the reference frame
41592	for ( let i = 0; i < numTracks; ++ i ) {
41593
41594		const referenceTrack = referenceClip.tracks[ i ];
41595		const referenceTrackType = referenceTrack.ValueTypeName;
41596
41597		// Skip this track if it's non-numeric
41598		if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
41599
41600		// Find the track in the target clip whose name and type matches the reference track
41601		const targetTrack = targetClip.tracks.find( function ( track ) {
41602
41603			return track.name === referenceTrack.name
41604				&& track.ValueTypeName === referenceTrackType;
41605
41606		} );
41607
41608		if ( targetTrack === undefined ) continue;
41609
41610		let referenceOffset = 0;
41611		const referenceValueSize = referenceTrack.getValueSize();
41612
41613		if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41614
41615			referenceOffset = referenceValueSize / 3;
41616
41617		}
41618
41619		let targetOffset = 0;
41620		const targetValueSize = targetTrack.getValueSize();
41621
41622		if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41623
41624			targetOffset = targetValueSize / 3;
41625
41626		}
41627
41628		const lastIndex = referenceTrack.times.length - 1;
41629		let referenceValue;
41630
41631		// Find the value to subtract out of the track
41632		if ( referenceTime <= referenceTrack.times[ 0 ] ) {
41633
41634			// Reference frame is earlier than the first keyframe, so just use the first keyframe
41635			const startIndex = referenceOffset;
41636			const endIndex = referenceValueSize - referenceOffset;
41637			referenceValue = referenceTrack.values.slice( startIndex, endIndex );
41638
41639		} else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
41640
41641			// Reference frame is after the last keyframe, so just use the last keyframe
41642			const startIndex = lastIndex * referenceValueSize + referenceOffset;
41643			const endIndex = startIndex + referenceValueSize - referenceOffset;
41644			referenceValue = referenceTrack.values.slice( startIndex, endIndex );
41645
41646		} else {
41647
41648			// Interpolate to the reference value
41649			const interpolant = referenceTrack.createInterpolant();
41650			const startIndex = referenceOffset;
41651			const endIndex = referenceValueSize - referenceOffset;
41652			interpolant.evaluate( referenceTime );
41653			referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );
41654
41655		}
41656
41657		// Conjugate the quaternion
41658		if ( referenceTrackType === 'quaternion' ) {
41659
41660			const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
41661			referenceQuat.toArray( referenceValue );
41662
41663		}
41664
41665		// Subtract the reference value from all of the track values
41666
41667		const numTimes = targetTrack.times.length;
41668		for ( let j = 0; j < numTimes; ++ j ) {
41669
41670			const valueStart = j * targetValueSize + targetOffset;
41671
41672			if ( referenceTrackType === 'quaternion' ) {
41673
41674				// Multiply the conjugate for quaternion track types
41675				Quaternion.multiplyQuaternionsFlat(
41676					targetTrack.values,
41677					valueStart,
41678					referenceValue,
41679					0,
41680					targetTrack.values,
41681					valueStart
41682				);
41683
41684			} else {
41685
41686				const valueEnd = targetValueSize - targetOffset * 2;
41687
41688				// Subtract each value for all other numeric track types
41689				for ( let k = 0; k < valueEnd; ++ k ) {
41690
41691					targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
41692
41693				}
41694
41695			}
41696
41697		}
41698
41699	}
41700
41701	targetClip.blendMode = AdditiveAnimationBlendMode;
41702
41703	return targetClip;
41704
41705}
41706
41707const AnimationUtils = {
41708	convertArray: convertArray,
41709	isTypedArray: isTypedArray,
41710	getKeyframeOrder: getKeyframeOrder,
41711	sortedArray: sortedArray,
41712	flattenJSON: flattenJSON,
41713	subclip: subclip,
41714	makeClipAdditive: makeClipAdditive
41715};
41716
41717/**
41718 * Abstract base class of interpolants over parametric samples.
41719 *
41720 * The parameter domain is one dimensional, typically the time or a path
41721 * along a curve defined by the data.
41722 *
41723 * The sample values can have any dimensionality and derived classes may
41724 * apply special interpretations to the data.
41725 *
41726 * This class provides the interval seek in a Template Method, deferring
41727 * the actual interpolation to derived classes.
41728 *
41729 * Time complexity is O(1) for linear access crossing at most two points
41730 * and O(log N) for random access, where N is the number of positions.
41731 *
41732 * References:
41733 *
41734 * 		http://www.oodesign.com/template-method-pattern.html
41735 *
41736 */
41737
41738class Interpolant {
41739
41740	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
41741
41742		this.parameterPositions = parameterPositions;
41743		this._cachedIndex = 0;
41744
41745		this.resultBuffer = resultBuffer !== undefined ?
41746			resultBuffer : new sampleValues.constructor( sampleSize );
41747		this.sampleValues = sampleValues;
41748		this.valueSize = sampleSize;
41749
41750		this.settings = null;
41751		this.DefaultSettings_ = {};
41752
41753	}
41754
41755	evaluate( t ) {
41756
41757		const pp = this.parameterPositions;
41758		let i1 = this._cachedIndex,
41759			t1 = pp[ i1 ],
41760			t0 = pp[ i1 - 1 ];
41761
41762		validate_interval: {
41763
41764			seek: {
41765
41766				let right;
41767
41768				linear_scan: {
41769
41770					//- See http://jsperf.com/comparison-to-undefined/3
41771					//- slower code:
41772					//-
41773					//- 				if ( t >= t1 || t1 === undefined ) {
41774					forward_scan: if ( ! ( t < t1 ) ) {
41775
41776						for ( let giveUpAt = i1 + 2; ; ) {
41777
41778							if ( t1 === undefined ) {
41779
41780								if ( t < t0 ) break forward_scan;
41781
41782								// after end
41783
41784								i1 = pp.length;
41785								this._cachedIndex = i1;
41786								return this.copySampleValue_( i1 - 1 );
41787
41788							}
41789
41790							if ( i1 === giveUpAt ) break; // this loop
41791
41792							t0 = t1;
41793							t1 = pp[ ++ i1 ];
41794
41795							if ( t < t1 ) {
41796
41797								// we have arrived at the sought interval
41798								break seek;
41799
41800							}
41801
41802						}
41803
41804						// prepare binary search on the right side of the index
41805						right = pp.length;
41806						break linear_scan;
41807
41808					}
41809
41810					//- slower code:
41811					//-					if ( t < t0 || t0 === undefined ) {
41812					if ( ! ( t >= t0 ) ) {
41813
41814						// looping?
41815
41816						const t1global = pp[ 1 ];
41817
41818						if ( t < t1global ) {
41819
41820							i1 = 2; // + 1, using the scan for the details
41821							t0 = t1global;
41822
41823						}
41824
41825						// linear reverse scan
41826
41827						for ( let giveUpAt = i1 - 2; ; ) {
41828
41829							if ( t0 === undefined ) {
41830
41831								// before start
41832
41833								this._cachedIndex = 0;
41834								return this.copySampleValue_( 0 );
41835
41836							}
41837
41838							if ( i1 === giveUpAt ) break; // this loop
41839
41840							t1 = t0;
41841							t0 = pp[ -- i1 - 1 ];
41842
41843							if ( t >= t0 ) {
41844
41845								// we have arrived at the sought interval
41846								break seek;
41847
41848							}
41849
41850						}
41851
41852						// prepare binary search on the left side of the index
41853						right = i1;
41854						i1 = 0;
41855						break linear_scan;
41856
41857					}
41858
41859					// the interval is valid
41860
41861					break validate_interval;
41862
41863				} // linear scan
41864
41865				// binary search
41866
41867				while ( i1 < right ) {
41868
41869					const mid = ( i1 + right ) >>> 1;
41870
41871					if ( t < pp[ mid ] ) {
41872
41873						right = mid;
41874
41875					} else {
41876
41877						i1 = mid + 1;
41878
41879					}
41880
41881				}
41882
41883				t1 = pp[ i1 ];
41884				t0 = pp[ i1 - 1 ];
41885
41886				// check boundary cases, again
41887
41888				if ( t0 === undefined ) {
41889
41890					this._cachedIndex = 0;
41891					return this.copySampleValue_( 0 );
41892
41893				}
41894
41895				if ( t1 === undefined ) {
41896
41897					i1 = pp.length;
41898					this._cachedIndex = i1;
41899					return this.copySampleValue_( i1 - 1 );
41900
41901				}
41902
41903			} // seek
41904
41905			this._cachedIndex = i1;
41906
41907			this.intervalChanged_( i1, t0, t1 );
41908
41909		} // validate_interval
41910
41911		return this.interpolate_( i1, t0, t, t1 );
41912
41913	}
41914
41915	getSettings_() {
41916
41917		return this.settings || this.DefaultSettings_;
41918
41919	}
41920
41921	copySampleValue_( index ) {
41922
41923		// copies a sample value to the result buffer
41924
41925		const result = this.resultBuffer,
41926			values = this.sampleValues,
41927			stride = this.valueSize,
41928			offset = index * stride;
41929
41930		for ( let i = 0; i !== stride; ++ i ) {
41931
41932			result[ i ] = values[ offset + i ];
41933
41934		}
41935
41936		return result;
41937
41938	}
41939
41940	// Template methods for derived classes:
41941
41942	interpolate_( /* i1, t0, t, t1 */ ) {
41943
41944		throw new Error( 'call to abstract method' );
41945		// implementations shall return this.resultBuffer
41946
41947	}
41948
41949	intervalChanged_( /* i1, t0, t1 */ ) {
41950
41951		// empty
41952
41953	}
41954
41955}
41956
41957/**
41958 * Fast and simple cubic spline interpolant.
41959 *
41960 * It was derived from a Hermitian construction setting the first derivative
41961 * at each sample position to the linear slope between neighboring positions
41962 * over their parameter interval.
41963 */
41964
41965class CubicInterpolant extends Interpolant {
41966
41967	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
41968
41969		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
41970
41971		this._weightPrev = - 0;
41972		this._offsetPrev = - 0;
41973		this._weightNext = - 0;
41974		this._offsetNext = - 0;
41975
41976		this.DefaultSettings_ = {
41977
41978			endingStart: ZeroCurvatureEnding,
41979			endingEnd: ZeroCurvatureEnding
41980
41981		};
41982
41983	}
41984
41985	intervalChanged_( i1, t0, t1 ) {
41986
41987		const pp = this.parameterPositions;
41988		let iPrev = i1 - 2,
41989			iNext = i1 + 1,
41990
41991			tPrev = pp[ iPrev ],
41992			tNext = pp[ iNext ];
41993
41994		if ( tPrev === undefined ) {
41995
41996			switch ( this.getSettings_().endingStart ) {
41997
41998				case ZeroSlopeEnding:
41999
42000					// f'(t0) = 0
42001					iPrev = i1;
42002					tPrev = 2 * t0 - t1;
42003
42004					break;
42005
42006				case WrapAroundEnding:
42007
42008					// use the other end of the curve
42009					iPrev = pp.length - 2;
42010					tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
42011
42012					break;
42013
42014				default: // ZeroCurvatureEnding
42015
42016					// f''(t0) = 0 a.k.a. Natural Spline
42017					iPrev = i1;
42018					tPrev = t1;
42019
42020			}
42021
42022		}
42023
42024		if ( tNext === undefined ) {
42025
42026			switch ( this.getSettings_().endingEnd ) {
42027
42028				case ZeroSlopeEnding:
42029
42030					// f'(tN) = 0
42031					iNext = i1;
42032					tNext = 2 * t1 - t0;
42033
42034					break;
42035
42036				case WrapAroundEnding:
42037
42038					// use the other end of the curve
42039					iNext = 1;
42040					tNext = t1 + pp[ 1 ] - pp[ 0 ];
42041
42042					break;
42043
42044				default: // ZeroCurvatureEnding
42045
42046					// f''(tN) = 0, a.k.a. Natural Spline
42047					iNext = i1 - 1;
42048					tNext = t0;
42049
42050			}
42051
42052		}
42053
42054		const halfDt = ( t1 - t0 ) * 0.5,
42055			stride = this.valueSize;
42056
42057		this._weightPrev = halfDt / ( t0 - tPrev );
42058		this._weightNext = halfDt / ( tNext - t1 );
42059		this._offsetPrev = iPrev * stride;
42060		this._offsetNext = iNext * stride;
42061
42062	}
42063
42064	interpolate_( i1, t0, t, t1 ) {
42065
42066		const result = this.resultBuffer,
42067			values = this.sampleValues,
42068			stride = this.valueSize,
42069
42070			o1 = i1 * stride,		o0 = o1 - stride,
42071			oP = this._offsetPrev, 	oN = this._offsetNext,
42072			wP = this._weightPrev,	wN = this._weightNext,
42073
42074			p = ( t - t0 ) / ( t1 - t0 ),
42075			pp = p * p,
42076			ppp = pp * p;
42077
42078		// evaluate polynomials
42079
42080		const sP = - wP * ppp + 2 * wP * pp - wP * p;
42081		const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
42082		const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
42083		const sN = wN * ppp - wN * pp;
42084
42085		// combine data linearly
42086
42087		for ( let i = 0; i !== stride; ++ i ) {
42088
42089			result[ i ] =
42090					sP * values[ oP + i ] +
42091					s0 * values[ o0 + i ] +
42092					s1 * values[ o1 + i ] +
42093					sN * values[ oN + i ];
42094
42095		}
42096
42097		return result;
42098
42099	}
42100
42101}
42102
42103class LinearInterpolant extends Interpolant {
42104
42105	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42106
42107		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42108
42109	}
42110
42111	interpolate_( i1, t0, t, t1 ) {
42112
42113		const result = this.resultBuffer,
42114			values = this.sampleValues,
42115			stride = this.valueSize,
42116
42117			offset1 = i1 * stride,
42118			offset0 = offset1 - stride,
42119
42120			weight1 = ( t - t0 ) / ( t1 - t0 ),
42121			weight0 = 1 - weight1;
42122
42123		for ( let i = 0; i !== stride; ++ i ) {
42124
42125			result[ i ] =
42126					values[ offset0 + i ] * weight0 +
42127					values[ offset1 + i ] * weight1;
42128
42129		}
42130
42131		return result;
42132
42133	}
42134
42135}
42136
42137/**
42138 *
42139 * Interpolant that evaluates to the sample value at the position preceding
42140 * the parameter.
42141 */
42142
42143class DiscreteInterpolant extends Interpolant {
42144
42145	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42146
42147		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42148
42149	}
42150
42151	interpolate_( i1 /*, t0, t, t1 */ ) {
42152
42153		return this.copySampleValue_( i1 - 1 );
42154
42155	}
42156
42157}
42158
42159class KeyframeTrack {
42160
42161	constructor( name, times, values, interpolation ) {
42162
42163		if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
42164		if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + n
vendor: 22,243 bytes, lines 42164-43354
42164ame );
42165
42166		this.name = name;
42167
42168		this.times = convertArray( times, this.TimeBufferType );
42169		this.values = convertArray( values, this.ValueBufferType );
42170
42171		this.setInterpolation( interpolation || this.DefaultInterpolation );
42172
42173	}
42174
42175	// Serialization (in static context, because of constructor invocation
42176	// and automatic invocation of .toJSON):
42177
42178	static toJSON( track ) {
42179
42180		const trackType = track.constructor;
42181
42182		let json;
42183
42184		// derived classes can define a static toJSON method
42185		if ( trackType.toJSON !== this.toJSON ) {
42186
42187			json = trackType.toJSON( track );
42188
42189		} else {
42190
42191			// by default, we assume the data can be serialized as-is
42192			json = {
42193
42194				'name': track.name,
42195				'times': convertArray( track.times, Array ),
42196				'values': convertArray( track.values, Array )
42197
42198			};
42199
42200			const interpolation = track.getInterpolation();
42201
42202			if ( interpolation !== track.DefaultInterpolation ) {
42203
42204				json.interpolation = interpolation;
42205
42206			}
42207
42208		}
42209
42210		json.type = track.ValueTypeName; // mandatory
42211
42212		return json;
42213
42214	}
42215
42216	InterpolantFactoryMethodDiscrete( result ) {
42217
42218		return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
42219
42220	}
42221
42222	InterpolantFactoryMethodLinear( result ) {
42223
42224		return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
42225
42226	}
42227
42228	InterpolantFactoryMethodSmooth( result ) {
42229
42230		return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
42231
42232	}
42233
42234	setInterpolation( interpolation ) {
42235
42236		let factoryMethod;
42237
42238		switch ( interpolation ) {
42239
42240			case InterpolateDiscrete:
42241
42242				factoryMethod = this.InterpolantFactoryMethodDiscrete;
42243
42244				break;
42245
42246			case InterpolateLinear:
42247
42248				factoryMethod = this.InterpolantFactoryMethodLinear;
42249
42250				break;
42251
42252			case InterpolateSmooth:
42253
42254				factoryMethod = this.InterpolantFactoryMethodSmooth;
42255
42256				break;
42257
42258		}
42259
42260		if ( factoryMethod === undefined ) {
42261
42262			const message = 'unsupported interpolation for ' +
42263				this.ValueTypeName + ' keyframe track named ' + this.name;
42264
42265			if ( this.createInterpolant === undefined ) {
42266
42267				// fall back to default, unless the default itself is messed up
42268				if ( interpolation !== this.DefaultInterpolation ) {
42269
42270					this.setInterpolation( this.DefaultInterpolation );
42271
42272				} else {
42273
42274					throw new Error( message ); // fatal, in this case
42275
42276				}
42277
42278			}
42279
42280			console.warn( 'THREE.KeyframeTrack:', message );
42281			return this;
42282
42283		}
42284
42285		this.createInterpolant = factoryMethod;
42286
42287		return this;
42288
42289	}
42290
42291	getInterpolation() {
42292
42293		switch ( this.createInterpolant ) {
42294
42295			case this.InterpolantFactoryMethodDiscrete:
42296
42297				return InterpolateDiscrete;
42298
42299			case this.InterpolantFactoryMethodLinear:
42300
42301				return InterpolateLinear;
42302
42303			case this.InterpolantFactoryMethodSmooth:
42304
42305				return InterpolateSmooth;
42306
42307		}
42308
42309	}
42310
42311	getValueSize() {
42312
42313		return this.values.length / this.times.length;
42314
42315	}
42316
42317	// move all keyframes either forwards or backwards in time
42318	shift( timeOffset ) {
42319
42320		if ( timeOffset !== 0.0 ) {
42321
42322			const times = this.times;
42323
42324			for ( let i = 0, n = times.length; i !== n; ++ i ) {
42325
42326				times[ i ] += timeOffset;
42327
42328			}
42329
42330		}
42331
42332		return this;
42333
42334	}
42335
42336	// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
42337	scale( timeScale ) {
42338
42339		if ( timeScale !== 1.0 ) {
42340
42341			const times = this.times;
42342
42343			for ( let i = 0, n = times.length; i !== n; ++ i ) {
42344
42345				times[ i ] *= timeScale;
42346
42347			}
42348
42349		}
42350
42351		return this;
42352
42353	}
42354
42355	// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
42356	// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
42357	trim( startTime, endTime ) {
42358
42359		const times = this.times,
42360			nKeys = times.length;
42361
42362		let from = 0,
42363			to = nKeys - 1;
42364
42365		while ( from !== nKeys && times[ from ] < startTime ) {
42366
42367			++ from;
42368
42369		}
42370
42371		while ( to !== - 1 && times[ to ] > endTime ) {
42372
42373			-- to;
42374
42375		}
42376
42377		++ to; // inclusive -> exclusive bound
42378
42379		if ( from !== 0 || to !== nKeys ) {
42380
42381			// empty tracks are forbidden, so keep at least one keyframe
42382			if ( from >= to ) {
42383
42384				to = Math.max( to, 1 );
42385				from = to - 1;
42386
42387			}
42388
42389			const stride = this.getValueSize();
42390			this.times = times.slice( from, to );
42391			this.values = this.values.slice( from * stride, to * stride );
42392
42393		}
42394
42395		return this;
42396
42397	}
42398
42399	// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
42400	validate() {
42401
42402		let valid = true;
42403
42404		const valueSize = this.getValueSize();
42405		if ( valueSize - Math.floor( valueSize ) !== 0 ) {
42406
42407			console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
42408			valid = false;
42409
42410		}
42411
42412		const times = this.times,
42413			values = this.values,
42414
42415			nKeys = times.length;
42416
42417		if ( nKeys === 0 ) {
42418
42419			console.error( 'THREE.KeyframeTrack: Track is empty.', this );
42420			valid = false;
42421
42422		}
42423
42424		let prevTime = null;
42425
42426		for ( let i = 0; i !== nKeys; i ++ ) {
42427
42428			const currTime = times[ i ];
42429
42430			if ( typeof currTime === 'number' && isNaN( currTime ) ) {
42431
42432				console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
42433				valid = false;
42434				break;
42435
42436			}
42437
42438			if ( prevTime !== null && prevTime > currTime ) {
42439
42440				console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
42441				valid = false;
42442				break;
42443
42444			}
42445
42446			prevTime = currTime;
42447
42448		}
42449
42450		if ( values !== undefined ) {
42451
42452			if ( isTypedArray( values ) ) {
42453
42454				for ( let i = 0, n = values.length; i !== n; ++ i ) {
42455
42456					const value = values[ i ];
42457
42458					if ( isNaN( value ) ) {
42459
42460						console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
42461						valid = false;
42462						break;
42463
42464					}
42465
42466				}
42467
42468			}
42469
42470		}
42471
42472		return valid;
42473
42474	}
42475
42476	// removes equivalent sequential keys as common in morph target sequences
42477	// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
42478	optimize() {
42479
42480		// times or values may be shared with other tracks, so overwriting is unsafe
42481		const times = this.times.slice(),
42482			values = this.values.slice(),
42483			stride = this.getValueSize(),
42484
42485			smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
42486
42487			lastIndex = times.length - 1;
42488
42489		let writeIndex = 1;
42490
42491		for ( let i = 1; i < lastIndex; ++ i ) {
42492
42493			let keep = false;
42494
42495			const time = times[ i ];
42496			const timeNext = times[ i + 1 ];
42497
42498			// remove adjacent keyframes scheduled at the same time
42499
42500			if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
42501
42502				if ( ! smoothInterpolation ) {
42503
42504					// remove unnecessary keyframes same as their neighbors
42505
42506					const offset = i * stride,
42507						offsetP = offset - stride,
42508						offsetN = offset + stride;
42509
42510					for ( let j = 0; j !== stride; ++ j ) {
42511
42512						const value = values[ offset + j ];
42513
42514						if ( value !== values[ offsetP + j ] ||
42515							value !== values[ offsetN + j ] ) {
42516
42517							keep = true;
42518							break;
42519
42520						}
42521
42522					}
42523
42524				} else {
42525
42526					keep = true;
42527
42528				}
42529
42530			}
42531
42532			// in-place compaction
42533
42534			if ( keep ) {
42535
42536				if ( i !== writeIndex ) {
42537
42538					times[ writeIndex ] = times[ i ];
42539
42540					const readOffset = i * stride,
42541						writeOffset = writeIndex * stride;
42542
42543					for ( let j = 0; j !== stride; ++ j ) {
42544
42545						values[ writeOffset + j ] = values[ readOffset + j ];
42546
42547					}
42548
42549				}
42550
42551				++ writeIndex;
42552
42553			}
42554
42555		}
42556
42557		// flush last keyframe (compaction looks ahead)
42558
42559		if ( lastIndex > 0 ) {
42560
42561			times[ writeIndex ] = times[ lastIndex ];
42562
42563			for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
42564
42565				values[ writeOffset + j ] = values[ readOffset + j ];
42566
42567			}
42568
42569			++ writeIndex;
42570
42571		}
42572
42573		if ( writeIndex !== times.length ) {
42574
42575			this.times = times.slice( 0, writeIndex );
42576			this.values = values.slice( 0, writeIndex * stride );
42577
42578		} else {
42579
42580			this.times = times;
42581			this.values = values;
42582
42583		}
42584
42585		return this;
42586
42587	}
42588
42589	clone() {
42590
42591		const times = this.times.slice();
42592		const values = this.values.slice();
42593
42594		const TypedKeyframeTrack = this.constructor;
42595		const track = new TypedKeyframeTrack( this.name, times, values );
42596
42597		// Interpolant argument to constructor is not saved, so copy the factory method directly.
42598		track.createInterpolant = this.createInterpolant;
42599
42600		return track;
42601
42602	}
42603
42604}
42605
42606KeyframeTrack.prototype.TimeBufferType = Float32Array;
42607KeyframeTrack.prototype.ValueBufferType = Float32Array;
42608KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42609
42610/**
42611 * A Track of Boolean keyframe values.
42612 */
42613class BooleanKeyframeTrack extends KeyframeTrack {}
42614
42615BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';
42616BooleanKeyframeTrack.prototype.ValueBufferType = Array;
42617BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42618BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42619BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42620
42621/**
42622 * A Track of keyframe values that represent color.
42623 */
42624class ColorKeyframeTrack extends KeyframeTrack {}
42625
42626ColorKeyframeTrack.prototype.ValueTypeName = 'color';
42627
42628/**
42629 * A Track of numeric keyframe values.
42630 */
42631class NumberKeyframeTrack extends KeyframeTrack {}
42632
42633NumberKeyframeTrack.prototype.ValueTypeName = 'number';
42634
42635/**
42636 * Spherical linear unit quaternion interpolant.
42637 */
42638
42639class QuaternionLinearInterpolant extends Interpolant {
42640
42641	constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
42642
42643		super( parameterPositions, sampleValues, sampleSize, resultBuffer );
42644
42645	}
42646
42647	interpolate_( i1, t0, t, t1 ) {
42648
42649		const result = this.resultBuffer,
42650			values = this.sampleValues,
42651			stride = this.valueSize,
42652
42653			alpha = ( t - t0 ) / ( t1 - t0 );
42654
42655		let offset = i1 * stride;
42656
42657		for ( let end = offset + stride; offset !== end; offset += 4 ) {
42658
42659			Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
42660
42661		}
42662
42663		return result;
42664
42665	}
42666
42667}
42668
42669/**
42670 * A Track of quaternion keyframe values.
42671 */
42672class QuaternionKeyframeTrack extends KeyframeTrack {
42673
42674	InterpolantFactoryMethodLinear( result ) {
42675
42676		return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
42677
42678	}
42679
42680}
42681
42682QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';
42683// ValueBufferType is inherited
42684QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42685QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42686
42687/**
42688 * A Track that interpolates Strings
42689 */
42690class StringKeyframeTrack extends KeyframeTrack {}
42691
42692StringKeyframeTrack.prototype.ValueTypeName = 'string';
42693StringKeyframeTrack.prototype.ValueBufferType = Array;
42694StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42695StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42696StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42697
42698/**
42699 * A Track of vectored keyframe values.
42700 */
42701class VectorKeyframeTrack extends KeyframeTrack {}
42702
42703VectorKeyframeTrack.prototype.ValueTypeName = 'vector';
42704
42705class AnimationClip {
42706
42707	constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
42708
42709		this.name = name;
42710		this.tracks = tracks;
42711		this.duration = duration;
42712		this.blendMode = blendMode;
42713
42714		this.uuid = generateUUID();
42715
42716		// this means it should figure out its duration by scanning the tracks
42717		if ( this.duration < 0 ) {
42718
42719			this.resetDuration();
42720
42721		}
42722
42723	}
42724
42725
42726	static parse( json ) {
42727
42728		const tracks = [],
42729			jsonTracks = json.tracks,
42730			frameTime = 1.0 / ( json.fps || 1.0 );
42731
42732		for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
42733
42734			tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
42735
42736		}
42737
42738		const clip = new this( json.name, json.duration, tracks, json.blendMode );
42739		clip.uuid = json.uuid;
42740
42741		return clip;
42742
42743	}
42744
42745	static toJSON( clip ) {
42746
42747		const tracks = [],
42748			clipTracks = clip.tracks;
42749
42750		const json = {
42751
42752			'name': clip.name,
42753			'duration': clip.duration,
42754			'tracks': tracks,
42755			'uuid': clip.uuid,
42756			'blendMode': clip.blendMode
42757
42758		};
42759
42760		for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
42761
42762			tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
42763
42764		}
42765
42766		return json;
42767
42768	}
42769
42770	static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {
42771
42772		const numMorphTargets = morphTargetSequence.length;
42773		const tracks = [];
42774
42775		for ( let i = 0; i < numMorphTargets; i ++ ) {
42776
42777			let times = [];
42778			let values = [];
42779
42780			times.push(
42781				( i + numMorphTargets - 1 ) % numMorphTargets,
42782				i,
42783				( i + 1 ) % numMorphTargets );
42784
42785			values.push( 0, 1, 0 );
42786
42787			const order = getKeyframeOrder( times );
42788			times = sortedArray( times, 1, order );
42789			values = sortedArray( values, 1, order );
42790
42791			// if there is a key at the first frame, duplicate it as the
42792			// last frame as well for perfect loop.
42793			if ( ! noLoop && times[ 0 ] === 0 ) {
42794
42795				times.push( numMorphTargets );
42796				values.push( values[ 0 ] );
42797
42798			}
42799
42800			tracks.push(
42801				new NumberKeyframeTrack(
42802					'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
42803					times, values
42804				).scale( 1.0 / fps ) );
42805
42806		}
42807
42808		return new this( name, - 1, tracks );
42809
42810	}
42811
42812	static findByName( objectOrClipArray, name ) {
42813
42814		let clipArray = objectOrClipArray;
42815
42816		if ( ! Array.isArray( objectOrClipArray ) ) {
42817
42818			const o = objectOrClipArray;
42819			clipArray = o.geometry && o.geometry.animations || o.animations;
42820
42821		}
42822
42823		for ( let i = 0; i < clipArray.length; i ++ ) {
42824
42825			if ( clipArray[ i ].name === name ) {
42826
42827				return clipArray[ i ];
42828
42829			}
42830
42831		}
42832
42833		return null;
42834
42835	}
42836
42837	static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {
42838
42839		const animationToMorphTargets = {};
42840
42841		// tested with https://regex101.com/ on trick sequences
42842		// such flamingo_flyA_003, flamingo_run1_003, crdeath0059
42843		const pattern = /^([\w-]*?)([\d]+)$/;
42844
42845		// sort morph target names into animation groups based
42846		// patterns like Walk_001, Walk_002, Run_001, Run_002
42847		for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
42848
42849			const morphTarget = morphTargets[ i ];
42850			const parts = morphTarget.name.match( pattern );
42851
42852			if ( parts && parts.length > 1 ) {
42853
42854				const name = parts[ 1 ];
42855
42856				let animationMorphTargets = animationToMorphTargets[ name ];
42857
42858				if ( ! animationMorphTargets ) {
42859
42860					animationToMorphTargets[ name ] = animationMorphTargets = [];
42861
42862				}
42863
42864				animationMorphTargets.push( morphTarget );
42865
42866			}
42867
42868		}
42869
42870		const clips = [];
42871
42872		for ( const name in animationToMorphTargets ) {
42873
42874			clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
42875
42876		}
42877
42878		return clips;
42879
42880	}
42881
42882	// parse the animation.hierarchy format
42883	static parseAnimation( animation, bones ) {
42884
42885		if ( ! animation ) {
42886
42887			console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
42888			return null;
42889
42890		}
42891
42892		const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
42893
42894			// only return track if there are actually keys.
42895			if ( animationKeys.length !== 0 ) {
42896
42897				const times = [];
42898				const values = [];
42899
42900				flattenJSON( animationKeys, times, values, propertyName );
42901
42902				// empty keys are filtered out, so check again
42903				if ( times.length !== 0 ) {
42904
42905					destTracks.push( new trackType( trackName, times, values ) );
42906
42907				}
42908
42909			}
42910
42911		};
42912
42913		const tracks = [];
42914
42915		const clipName = animation.name || 'default';
42916		const fps = animation.fps || 30;
42917		const blendMode = animation.blendMode;
42918
42919		// automatic length determination in AnimationClip.
42920		let duration = animation.length || - 1;
42921
42922		const hierarchyTracks = animation.hierarchy || [];
42923
42924		for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
42925
42926			const animationKeys = hierarchyTracks[ h ].keys;
42927
42928			// skip empty tracks
42929			if ( ! animationKeys || animationKeys.length === 0 ) continue;
42930
42931			// process morph targets
42932			if ( animationKeys[ 0 ].morphTargets ) {
42933
42934				// figure out all morph targets used in this track
42935				const morphTargetNames = {};
42936
42937				let k;
42938
42939				for ( k = 0; k < animationKeys.length; k ++ ) {
42940
42941					if ( animationKeys[ k ].morphTargets ) {
42942
42943						for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
42944
42945							morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
42946
42947						}
42948
42949					}
42950
42951				}
42952
42953				// create a track for each morph target with all zero
42954				// morphTargetInfluences except for the keys in which
42955				// the morphTarget is named.
42956				for ( const morphTargetName in morphTargetNames ) {
42957
42958					const times = [];
42959					const values = [];
42960
42961					for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
42962
42963						const animationKey = animationKeys[ k ];
42964
42965						times.push( animationKey.time );
42966						values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
42967
42968					}
42969
42970					tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
42971
42972				}
42973
42974				duration = morphTargetNames.length * fps;
42975
42976			} else {
42977
42978				// ...assume skeletal animation
42979
42980				const boneName = '.bones[' + bones[ h ].name + ']';
42981
42982				addNonemptyTrack(
42983					VectorKeyframeTrack, boneName + '.position',
42984					animationKeys, 'pos', tracks );
42985
42986				addNonemptyTrack(
42987					QuaternionKeyframeTrack, boneName + '.quaternion',
42988					animationKeys, 'rot', tracks );
42989
42990				addNonemptyTrack(
42991					VectorKeyframeTrack, boneName + '.scale',
42992					animationKeys, 'scl', tracks );
42993
42994			}
42995
42996		}
42997
42998		if ( tracks.length === 0 ) {
42999
43000			return null;
43001
43002		}
43003
43004		const clip = new this( clipName, duration, tracks, blendMode );
43005
43006		return clip;
43007
43008	}
43009
43010	resetDuration() {
43011
43012		const tracks = this.tracks;
43013		let duration = 0;
43014
43015		for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
43016
43017			const track = this.tracks[ i ];
43018
43019			duration = Math.max( duration, track.times[ track.times.length - 1 ] );
43020
43021		}
43022
43023		this.duration = duration;
43024
43025		return this;
43026
43027	}
43028
43029	trim() {
43030
43031		for ( let i = 0; i < this.tracks.length; i ++ ) {
43032
43033			this.tracks[ i ].trim( 0, this.duration );
43034
43035		}
43036
43037		return this;
43038
43039	}
43040
43041	validate() {
43042
43043		let valid = true;
43044
43045		for ( let i = 0; i < this.tracks.length; i ++ ) {
43046
43047			valid = valid && this.tracks[ i ].validate();
43048
43049		}
43050
43051		return valid;
43052
43053	}
43054
43055	optimize() {
43056
43057		for ( let i = 0; i < this.tracks.length; i ++ ) {
43058
43059			this.tracks[ i ].optimize();
43060
43061		}
43062
43063		return this;
43064
43065	}
43066
43067	clone() {
43068
43069		const tracks = [];
43070
43071		for ( let i = 0; i < this.tracks.length; i ++ ) {
43072
43073			tracks.push( this.tracks[ i ].clone() );
43074
43075		}
43076
43077		return new this.constructor( this.name, this.duration, tracks, this.blendMode );
43078
43079	}
43080
43081	toJSON() {
43082
43083		return this.constructor.toJSON( this );
43084
43085	}
43086
43087}
43088
43089function getTrackTypeForValueTypeName( typeName ) {
43090
43091	switch ( typeName.toLowerCase() ) {
43092
43093		case 'scalar':
43094		case 'double':
43095		case 'float':
43096		case 'number':
43097		case 'integer':
43098
43099			return NumberKeyframeTrack;
43100
43101		case 'vector':
43102		case 'vector2':
43103		case 'vector3':
43104		case 'vector4':
43105
43106			return VectorKeyframeTrack;
43107
43108		case 'color':
43109
43110			return ColorKeyframeTrack;
43111
43112		case 'quaternion':
43113
43114			return QuaternionKeyframeTrack;
43115
43116		case 'bool':
43117		case 'boolean':
43118
43119			return BooleanKeyframeTrack;
43120
43121		case 'string':
43122
43123			return StringKeyframeTrack;
43124
43125	}
43126
43127	throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
43128
43129}
43130
43131function parseKeyframeTrack( json ) {
43132
43133	if ( json.type === undefined ) {
43134
43135		throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
43136
43137	}
43138
43139	const trackType = getTrackTypeForValueTypeName( json.type );
43140
43141	if ( json.times === undefined ) {
43142
43143		const times = [], values = [];
43144
43145		flattenJSON( json.keys, times, values, 'value' );
43146
43147		json.times = times;
43148		json.values = values;
43149
43150	}
43151
43152	// derived classes can define a static parse method
43153	if ( trackType.parse !== undefined ) {
43154
43155		return trackType.parse( json );
43156
43157	} else {
43158
43159		// by default, we assume a constructor compatible with the base
43160		return new trackType( json.name, json.times, json.values, json.interpolation );
43161
43162	}
43163
43164}
43165
43166const Cache = {
43167
43168	enabled: false,
43169
43170	files: {},
43171
43172	add: function ( key, file ) {
43173
43174		if ( this.enabled === false ) return;
43175
43176		// console.log( 'THREE.Cache', 'Adding key:', key );
43177
43178		this.files[ key ] = file;
43179
43180	},
43181
43182	get: function ( key ) {
43183
43184		if ( this.enabled === false ) return;
43185
43186		// console.log( 'THREE.Cache', 'Checking key:', key );
43187
43188		return this.files[ key ];
43189
43190	},
43191
43192	remove: function ( key ) {
43193
43194		delete this.files[ key ];
43195
43196	},
43197
43198	clear: function () {
43199
43200		this.files = {};
43201
43202	}
43203
43204};
43205
43206class LoadingManager {
43207
43208	constructor( onLoad, onProgress, onError ) {
43209
43210		const scope = this;
43211
43212		let isLoading = false;
43213		let itemsLoaded = 0;
43214		let itemsTotal = 0;
43215		let urlModifier = undefined;
43216		const handlers = [];
43217
43218		// Refer to #5689 for the reason why we don't set .onStart
43219		// in the constructor
43220
43221		this.onStart = undefined;
43222		this.onLoad = onLoad;
43223		this.onProgress = onProgress;
43224		this.onError = onError;
43225
43226		this.itemStart = function ( url ) {
43227
43228			itemsTotal ++;
43229
43230			if ( isLoading === false ) {
43231
43232				if ( scope.onStart !== undefined ) {
43233
43234					scope.onStart( url, itemsLoaded, itemsTotal );
43235
43236				}
43237
43238			}
43239
43240			isLoading = true;
43241
43242		};
43243
43244		this.itemEnd = function ( url ) {
43245
43246			itemsLoaded ++;
43247
43248			if ( scope.onProgress !== undefined ) {
43249
43250				scope.onProgress( url, itemsLoaded, itemsTotal );
43251
43252			}
43253
43254			if ( itemsLoaded === itemsTotal ) {
43255
43256				isLoading = false;
43257
43258				if ( scope.onLoad !== undefined ) {
43259
43260					scope.onLoad();
43261
43262				}
43263
43264			}
43265
43266		};
43267
43268		this.itemError = function ( url ) {
43269
43270			if ( scope.onError !== undefined ) {
43271
43272				scope.onError( url );
43273
43274			}
43275
43276		};
43277
43278		this.resolveURL = function ( url ) {
43279
43280			if ( urlModifier ) {
43281
43282				return urlModifier( url );
43283
43284			}
43285
43286			return url;
43287
43288		};
43289
43290		this.setURLModifier = function ( transform ) {
43291
43292			urlModifier = transform;
43293
43294			return this;
43295
43296		};
43297
43298		this.addHandler = function ( regex, loader ) {
43299
43300			handlers.push( regex, loader );
43301
43302			return this;
43303
43304		};
43305
43306		this.removeHandler = function ( regex ) {
43307
43308			const index = handlers.indexOf( regex );
43309
43310			if ( index !== - 1 ) {
43311
43312				handlers.splice( index, 2 );
43313
43314			}
43315
43316			return this;
43317
43318		};
43319
43320		this.getHandler = function ( file ) {
43321
43322			for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
43323
43324				const regex = handlers[ i ];
43325				const loader = handlers[ i + 1 ];
43326
43327				if ( regex.global ) regex.lastIndex = 0; // see #17920
43328
43329				if ( regex.test( file ) ) {
43330
43331					return loader;
43332
43333				}
43334
43335			}
43336
43337			return null;
43338
43339		};
43340
43341	}
43342
43343}
43344
43345const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();
43346
43347class Loader {
43348
43349	constructor( manager ) {
43350
43351		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
43352
43353		this.crossOrigin = 'anonymous';
43354		this.withCredentials = false;
vendor: 12,888 bytes, lines 43355-44080
43355		this.path = '';
43356		this.resourcePath = '';
43357		this.requestHeader = {};
43358
43359	}
43360
43361	load( /* url, onLoad, onProgress, onError */ ) {}
43362
43363	loadAsync( url, onProgress ) {
43364
43365		const scope = this;
43366
43367		return new Promise( function ( resolve, reject ) {
43368
43369			scope.load( url, resolve, onProgress, reject );
43370
43371		} );
43372
43373	}
43374
43375	parse( /* data */ ) {}
43376
43377	setCrossOrigin( crossOrigin ) {
43378
43379		this.crossOrigin = crossOrigin;
43380		return this;
43381
43382	}
43383
43384	setWithCredentials( value ) {
43385
43386		this.withCredentials = value;
43387		return this;
43388
43389	}
43390
43391	setPath( path ) {
43392
43393		this.path = path;
43394		return this;
43395
43396	}
43397
43398	setResourcePath( resourcePath ) {
43399
43400		this.resourcePath = resourcePath;
43401		return this;
43402
43403	}
43404
43405	setRequestHeader( requestHeader ) {
43406
43407		this.requestHeader = requestHeader;
43408		return this;
43409
43410	}
43411
43412}
43413
43414Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
43415
43416const loading = {};
43417
43418class HttpError extends Error {
43419
43420	constructor( message, response ) {
43421
43422		super( message );
43423		this.response = response;
43424
43425	}
43426
43427}
43428
43429class FileLoader extends Loader {
43430
43431	constructor( manager ) {
43432
43433		super( manager );
43434
43435	}
43436
43437	load( url, onLoad, onProgress, onError ) {
43438
43439		if ( url === undefined ) url = '';
43440
43441		if ( this.path !== undefined ) url = this.path + url;
43442
43443		url = this.manager.resolveURL( url );
43444
43445		const cached = Cache.get( url );
43446
43447		if ( cached !== undefined ) {
43448
43449			this.manager.itemStart( url );
43450
43451			setTimeout( () => {
43452
43453				if ( onLoad ) onLoad( cached );
43454
43455				this.manager.itemEnd( url );
43456
43457			}, 0 );
43458
43459			return cached;
43460
43461		}
43462
43463		// Check if request is duplicate
43464
43465		if ( loading[ url ] !== undefined ) {
43466
43467			loading[ url ].push( {
43468
43469				onLoad: onLoad,
43470				onProgress: onProgress,
43471				onError: onError
43472
43473			} );
43474
43475			return;
43476
43477		}
43478
43479		// Initialise array for duplicate requests
43480		loading[ url ] = [];
43481
43482		loading[ url ].push( {
43483			onLoad: onLoad,
43484			onProgress: onProgress,
43485			onError: onError,
43486		} );
43487
43488		// create request
43489		const req = new Request( url, {
43490			headers: new Headers( this.requestHeader ),
43491			credentials: this.withCredentials ? 'include' : 'same-origin',
43492			// An abort controller could be added within a future PR
43493		} );
43494
43495		// record states ( avoid data race )
43496		const mimeType = this.mimeType;
43497		const responseType = this.responseType;
43498
43499		// start the fetch
43500		fetch( req )
43501			.then( response => {
43502
43503				if ( response.status === 200 || response.status === 0 ) {
43504
43505					// Some browsers return HTTP Status 0 when using non-http protocol
43506					// e.g. 'file://' or 'data://'. Handle as success.
43507
43508					if ( response.status === 0 ) {
43509
43510						console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
43511
43512					}
43513
43514					// Workaround: Checking if response.body === undefined for Alipay browser #23548
43515
43516					if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) {
43517
43518						return response;
43519
43520					}
43521
43522					const callbacks = loading[ url ];
43523					const reader = response.body.getReader();
43524
43525					// Nginx needs X-File-Size check
43526					// https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content
43527					const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' );
43528					const total = contentLength ? parseInt( contentLength ) : 0;
43529					const lengthComputable = total !== 0;
43530					let loaded = 0;
43531
43532					// periodically read data into the new stream tracking while download progress
43533					const stream = new ReadableStream( {
43534						start( controller ) {
43535
43536							readData();
43537
43538							function readData() {
43539
43540								reader.read().then( ( { done, value } ) => {
43541
43542									if ( done ) {
43543
43544										controller.close();
43545
43546									} else {
43547
43548										loaded += value.byteLength;
43549
43550										const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );
43551										for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43552
43553											const callback = callbacks[ i ];
43554											if ( callback.onProgress ) callback.onProgress( event );
43555
43556										}
43557
43558										controller.enqueue( value );
43559										readData();
43560
43561									}
43562
43563								} );
43564
43565							}
43566
43567						}
43568
43569					} );
43570
43571					return new Response( stream );
43572
43573				} else {
43574
43575					throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response );
43576
43577				}
43578
43579			} )
43580			.then( response => {
43581
43582				switch ( responseType ) {
43583
43584					case 'arraybuffer':
43585
43586						return response.arrayBuffer();
43587
43588					case 'blob':
43589
43590						return response.blob();
43591
43592					case 'document':
43593
43594						return response.text()
43595							.then( text => {
43596
43597								const parser = new DOMParser();
43598								return parser.parseFromString( text, mimeType );
43599
43600							} );
43601
43602					case 'json':
43603
43604						return response.json();
43605
43606					default:
43607
43608						if ( mimeType === undefined ) {
43609
43610							return response.text();
43611
43612						} else {
43613
43614							// sniff encoding
43615							const re = /charset="?([^;"\s]*)"?/i;
43616							const exec = re.exec( mimeType );
43617							const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined;
43618							const decoder = new TextDecoder( label );
43619							return response.arrayBuffer().then( ab => decoder.decode( ab ) );
43620
43621						}
43622
43623				}
43624
43625			} )
43626			.then( data => {
43627
43628				// Add to cache only on HTTP success, so that we do not cache
43629				// error response bodies as proper responses to requests.
43630				Cache.add( url, data );
43631
43632				const callbacks = loading[ url ];
43633				delete loading[ url ];
43634
43635				for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43636
43637					const callback = callbacks[ i ];
43638					if ( callback.onLoad ) callback.onLoad( data );
43639
43640				}
43641
43642			} )
43643			.catch( err => {
43644
43645				// Abort errors and other errors are handled the same
43646
43647				const callbacks = loading[ url ];
43648
43649				if ( callbacks === undefined ) {
43650
43651					// When onLoad was called and url was deleted in `loading`
43652					this.manager.itemError( url );
43653					throw err;
43654
43655				}
43656
43657				delete loading[ url ];
43658
43659				for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43660
43661					const callback = callbacks[ i ];
43662					if ( callback.onError ) callback.onError( err );
43663
43664				}
43665
43666				this.manager.itemError( url );
43667
43668			} )
43669			.finally( () => {
43670
43671				this.manager.itemEnd( url );
43672
43673			} );
43674
43675		this.manager.itemStart( url );
43676
43677	}
43678
43679	setResponseType( value ) {
43680
43681		this.responseType = value;
43682		return this;
43683
43684	}
43685
43686	setMimeType( value ) {
43687
43688		this.mimeType = value;
43689		return this;
43690
43691	}
43692
43693}
43694
43695class AnimationLoader extends Loader {
43696
43697	constructor( manager ) {
43698
43699		super( manager );
43700
43701	}
43702
43703	load( url, onLoad, onProgress, onError ) {
43704
43705		const scope = this;
43706
43707		const loader = new FileLoader( this.manager );
43708		loader.setPath( this.path );
43709		loader.setRequestHeader( this.requestHeader );
43710		loader.setWithCredentials( this.withCredentials );
43711		loader.load( url, function ( text ) {
43712
43713			try {
43714
43715				onLoad( scope.parse( JSON.parse( text ) ) );
43716
43717			} catch ( e ) {
43718
43719				if ( onError ) {
43720
43721					onError( e );
43722
43723				} else {
43724
43725					console.error( e );
43726
43727				}
43728
43729				scope.manager.itemError( url );
43730
43731			}
43732
43733		}, onProgress, onError );
43734
43735	}
43736
43737	parse( json ) {
43738
43739		const animations = [];
43740
43741		for ( let i = 0; i < json.length; i ++ ) {
43742
43743			const clip = AnimationClip.parse( json[ i ] );
43744
43745			animations.push( clip );
43746
43747		}
43748
43749		return animations;
43750
43751	}
43752
43753}
43754
43755/**
43756 * Abstract Base class to block based textures loader (dds, pvr, ...)
43757 *
43758 * Sub classes have to implement the parse() method which will be used in load().
43759 */
43760
43761class CompressedTextureLoader extends Loader {
43762
43763	constructor( manager ) {
43764
43765		super( manager );
43766
43767	}
43768
43769	load( url, onLoad, onProgress, onError ) {
43770
43771		const scope = this;
43772
43773		const images = [];
43774
43775		const texture = new CompressedTexture();
43776
43777		const loader = new FileLoader( this.manager );
43778		loader.setPath( this.path );
43779		loader.setResponseType( 'arraybuffer' );
43780		loader.setRequestHeader( this.requestHeader );
43781		loader.setWithCredentials( scope.withCredentials );
43782
43783		let loaded = 0;
43784
43785		function loadTexture( i ) {
43786
43787			loader.load( url[ i ], function ( buffer ) {
43788
43789				const texDatas = scope.parse( buffer, true );
43790
43791				images[ i ] = {
43792					width: texDatas.width,
43793					height: texDatas.height,
43794					format: texDatas.format,
43795					mipmaps: texDatas.mipmaps
43796				};
43797
43798				loaded += 1;
43799
43800				if ( loaded === 6 ) {
43801
43802					if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
43803
43804					texture.image = images;
43805					texture.format = texDatas.format;
43806					texture.needsUpdate = true;
43807
43808					if ( onLoad ) onLoad( texture );
43809
43810				}
43811
43812			}, onProgress, onError );
43813
43814		}
43815
43816		if ( Array.isArray( url ) ) {
43817
43818			for ( let i = 0, il = url.length; i < il; ++ i ) {
43819
43820				loadTexture( i );
43821
43822			}
43823
43824		} else {
43825
43826			// compressed cubemap texture stored in a single DDS file
43827
43828			loader.load( url, function ( buffer ) {
43829
43830				const texDatas = scope.parse( buffer, true );
43831
43832				if ( texDatas.isCubemap ) {
43833
43834					const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
43835
43836					for ( let f = 0; f < faces; f ++ ) {
43837
43838						images[ f ] = { mipmaps: [] };
43839
43840						for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
43841
43842							images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
43843							images[ f ].format = texDatas.format;
43844							images[ f ].width = texDatas.width;
43845							images[ f ].height = texDatas.height;
43846
43847						}
43848
43849					}
43850
43851					texture.image = images;
43852
43853				} else {
43854
43855					texture.image.width = texDatas.width;
43856					texture.image.height = texDatas.height;
43857					texture.mipmaps = texDatas.mipmaps;
43858
43859				}
43860
43861				if ( texDatas.mipmapCount === 1 ) {
43862
43863					texture.minFilter = LinearFilter;
43864
43865				}
43866
43867				texture.format = texDatas.format;
43868				texture.needsUpdate = true;
43869
43870				if ( onLoad ) onLoad( texture );
43871
43872			}, onProgress, onError );
43873
43874		}
43875
43876		return texture;
43877
43878	}
43879
43880}
43881
43882class ImageLoader extends Loader {
43883
43884	constructor( manager ) {
43885
43886		super( manager );
43887
43888	}
43889
43890	load( url, onLoad, onProgress, onError ) {
43891
43892		if ( this.path !== undefined ) url = this.path + url;
43893
43894		url = this.manager.resolveURL( url );
43895
43896		const scope = this;
43897
43898		const cached = Cache.get( url );
43899
43900		if ( cached !== undefined ) {
43901
43902			scope.manager.itemStart( url );
43903
43904			setTimeout( function () {
43905
43906				if ( onLoad ) onLoad( cached );
43907
43908				scope.manager.itemEnd( url );
43909
43910			}, 0 );
43911
43912			return cached;
43913
43914		}
43915
43916		const image = createElementNS( 'img' );
43917
43918		function onImageLoad() {
43919
43920			removeEventListeners();
43921
43922			Cache.add( url, this );
43923
43924			if ( onLoad ) onLoad( this );
43925
43926			scope.manager.itemEnd( url );
43927
43928		}
43929
43930		function onImageError( event ) {
43931
43932			removeEventListeners();
43933
43934			if ( onError ) onError( event );
43935
43936			scope.manager.itemError( url );
43937			scope.manager.itemEnd( url );
43938
43939		}
43940
43941		function removeEventListeners() {
43942
43943			image.removeEventListener( 'load', onImageLoad, false );
43944			image.removeEventListener( 'error', onImageError, false );
43945
43946		}
43947
43948		image.addEventListener( 'load', onImageLoad, false );
43949		image.addEventListener( 'error', onImageError, false );
43950
43951		if ( url.slice( 0, 5 ) !== 'data:' ) {
43952
43953			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
43954
43955		}
43956
43957		scope.manager.itemStart( url );
43958
43959		image.src = url;
43960
43961		return image;
43962
43963	}
43964
43965}
43966
43967class CubeTextureLoader extends Loader {
43968
43969	constructor( manager ) {
43970
43971		super( manager );
43972
43973	}
43974
43975	load( urls, onLoad, onProgress, onError ) {
43976
43977		const texture = new CubeTexture();
43978		texture.colorSpace = SRGBColorSpace;
43979
43980		const loader = new ImageLoader( this.manager );
43981		loader.setCrossOrigin( this.crossOrigin );
43982		loader.setPath( this.path );
43983
43984		let loaded = 0;
43985
43986		function loadTexture( i ) {
43987
43988			loader.load( urls[ i ], function ( image ) {
43989
43990				texture.images[ i ] = image;
43991
43992				loaded ++;
43993
43994				if ( loaded === 6 ) {
43995
43996					texture.needsUpdate = true;
43997
43998					if ( onLoad ) onLoad( texture );
43999
44000				}
44001
44002			}, undefined, onError );
44003
44004		}
44005
44006		for ( let i = 0; i < urls.length; ++ i ) {
44007
44008			loadTexture( i );
44009
44010		}
44011
44012		return texture;
44013
44014	}
44015
44016}
44017
44018/**
44019 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
44020 *
44021 * Sub classes have to implement the parse() method which will be used in load().
44022 */
44023
44024class DataTextureLoader extends Loader {
44025
44026	constructor( manager ) {
44027
44028		super( manager );
44029
44030	}
44031
44032	load( url, onLoad, onProgress, onError ) {
44033
44034		const scope = this;
44035
44036		const texture = new DataTexture();
44037
44038		const loader = new FileLoader( this.manager );
44039		loader.setResponseType( 'arraybuffer' );
44040		loader.setRequestHeader( this.requestHeader );
44041		loader.setPath( this.path );
44042		loader.setWithCredentials( scope.withCredentials );
44043		loader.load( url, function ( buffer ) {
44044
44045			let texData;
44046
44047			try {
44048
44049				texData = scope.parse( buffer );
44050
44051			} catch ( error ) {
44052
44053				if ( onError !== undefined ) {
44054
44055					onError( error );
44056
44057				} else {
44058
44059					console.error( error );
44060					return;
44061
44062				}
44063
44064			}
44065
44066			if ( texData.image !== undefined ) {
44067
44068				texture.image = texData.image;
44069
44070			} else if ( texData.data !== undefined ) {
44071
44072				texture.image.width = texData.width;
44073				texture.image.height = texData.height;
44074				texture.image.data = texData.data;
44075
44076			}
44077
44078			texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
44079			texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
44080
vendor: 5,067 bytes, lines 44081-44371
44081			texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
44082			texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
44083
44084			texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
44085
44086			if ( texData.colorSpace !== undefined ) {
44087
44088				texture.colorSpace = texData.colorSpace;
44089
44090			} else if ( texData.encoding !== undefined ) { // @deprecated, r152
44091
44092				texture.encoding = texData.encoding;
44093
44094			}
44095
44096			if ( texData.flipY !== undefined ) {
44097
44098				texture.flipY = texData.flipY;
44099
44100			}
44101
44102			if ( texData.format !== undefined ) {
44103
44104				texture.format = texData.format;
44105
44106			}
44107
44108			if ( texData.type !== undefined ) {
44109
44110				texture.type = texData.type;
44111
44112			}
44113
44114			if ( texData.mipmaps !== undefined ) {
44115
44116				texture.mipmaps = texData.mipmaps;
44117				texture.minFilter = LinearMipmapLinearFilter; // presumably...
44118
44119			}
44120
44121			if ( texData.mipmapCount === 1 ) {
44122
44123				texture.minFilter = LinearFilter;
44124
44125			}
44126
44127			if ( texData.generateMipmaps !== undefined ) {
44128
44129				texture.generateMipmaps = texData.generateMipmaps;
44130
44131			}
44132
44133			texture.needsUpdate = true;
44134
44135			if ( onLoad ) onLoad( texture, texData );
44136
44137		}, onProgress, onError );
44138
44139
44140		return texture;
44141
44142	}
44143
44144}
44145
44146class TextureLoader extends Loader {
44147
44148	constructor( manager ) {
44149
44150		super( manager );
44151
44152	}
44153
44154	load( url, onLoad, onProgress, onError ) {
44155
44156		const texture = new Texture();
44157
44158		const loader = new ImageLoader( this.manager );
44159		loader.setCrossOrigin( this.crossOrigin );
44160		loader.setPath( this.path );
44161
44162		loader.load( url, function ( image ) {
44163
44164			texture.image = image;
44165			texture.needsUpdate = true;
44166
44167			if ( onLoad !== undefined ) {
44168
44169				onLoad( texture );
44170
44171			}
44172
44173		}, onProgress, onError );
44174
44175		return texture;
44176
44177	}
44178
44179}
44180
44181class Light extends Object3D {
44182
44183	constructor( color, intensity = 1 ) {
44184
44185		super();
44186
44187		this.isLight = true;
44188
44189		this.type = 'Light';
44190
44191		this.color = new Color( color );
44192		this.intensity = intensity;
44193
44194	}
44195
44196	dispose() {
44197
44198		// Empty here in base class; some subclasses override.
44199
44200	}
44201
44202	copy( source, recursive ) {
44203
44204		super.copy( source, recursive );
44205
44206		this.color.copy( source.color );
44207		this.intensity = source.intensity;
44208
44209		return this;
44210
44211	}
44212
44213	toJSON( meta ) {
44214
44215		const data = super.toJSON( meta );
44216
44217		data.object.color = this.color.getHex();
44218		data.object.intensity = this.intensity;
44219
44220		if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
44221
44222		if ( this.distance !== undefined ) data.object.distance = this.distance;
44223		if ( this.angle !== undefined ) data.object.angle = this.angle;
44224		if ( this.decay !== undefined ) data.object.decay = this.decay;
44225		if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
44226
44227		if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
44228
44229		return data;
44230
44231	}
44232
44233}
44234
44235class HemisphereLight extends Light {
44236
44237	constructor( skyColor, groundColor, intensity ) {
44238
44239		super( skyColor, intensity );
44240
44241		this.isHemisphereLight = true;
44242
44243		this.type = 'HemisphereLight';
44244
44245		this.position.copy( Object3D.DEFAULT_UP );
44246		this.updateMatrix();
44247
44248		this.groundColor = new Color( groundColor );
44249
44250	}
44251
44252	copy( source, recursive ) {
44253
44254		super.copy( source, recursive );
44255
44256		this.groundColor.copy( source.groundColor );
44257
44258		return this;
44259
44260	}
44261
44262}
44263
44264const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();
44265const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();
44266const _lookTarget$1 = /*@__PURE__*/ new Vector3();
44267
44268class LightShadow {
44269
44270	constructor( camera ) {
44271
44272		this.camera = camera;
44273
44274		this.bias = 0;
44275		this.normalBias = 0;
44276		this.radius = 1;
44277		this.blurSamples = 8;
44278
44279		this.mapSize = new Vector2( 512, 512 );
44280
44281		this.map = null;
44282		this.mapPass = null;
44283		this.matrix = new Matrix4();
44284
44285		this.autoUpdate = true;
44286		this.needsUpdate = false;
44287
44288		this._frustum = new Frustum();
44289		this._frameExtents = new Vector2( 1, 1 );
44290
44291		this._viewportCount = 1;
44292
44293		this._viewports = [
44294
44295			new Vector4( 0, 0, 1, 1 )
44296
44297		];
44298
44299	}
44300
44301	getViewportCount() {
44302
44303		return this._viewportCount;
44304
44305	}
44306
44307	getFrustum() {
44308
44309		return this._frustum;
44310
44311	}
44312
44313	updateMatrices( light ) {
44314
44315		const shadowCamera = this.camera;
44316		const shadowMatrix = this.matrix;
44317
44318		_lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );
44319		shadowCamera.position.copy( _lightPositionWorld$1 );
44320
44321		_lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );
44322		shadowCamera.lookAt( _lookTarget$1 );
44323		shadowCamera.updateMatrixWorld();
44324
44325		_projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
44326		this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );
44327
44328		shadowMatrix.set(
44329			0.5, 0.0, 0.0, 0.5,
44330			0.0, 0.5, 0.0, 0.5,
44331			0.0, 0.0, 0.5, 0.5,
44332			0.0, 0.0, 0.0, 1.0
44333		);
44334
44335		shadowMatrix.multiply( _projScreenMatrix$1 );
44336
44337	}
44338
44339	getViewport( viewportIndex ) {
44340
44341		return this._viewports[ viewportIndex ];
44342
44343	}
44344
44345	getFrameExtents() {
44346
44347		return this._frameExtents;
44348
44349	}
44350
44351	dispose() {
44352
44353		if ( this.map ) {
44354
44355			this.map.dispose();
44356
44357		}
44358
44359		if ( this.mapPass ) {
44360
44361			this.mapPass.dispose();
44362
44363		}
44364
44365	}
44366
44367	copy( source ) {
44368
44369		this.camera = source.camera.clone();
44370
44371		this.bias = source.bias;
vendor: 5,709 bytes, lines 44372-44659
44372		this.radius = source.radius;
44373
44374		this.mapSize.copy( source.mapSize );
44375
44376		return this;
44377
44378	}
44379
44380	clone() {
44381
44382		return new this.constructor().copy( this );
44383
44384	}
44385
44386	toJSON() {
44387
44388		const object = {};
44389
44390		if ( this.bias !== 0 ) object.bias = this.bias;
44391		if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
44392		if ( this.radius !== 1 ) object.radius = this.radius;
44393		if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
44394
44395		object.camera = this.camera.toJSON( false ).object;
44396		delete object.camera.matrix;
44397
44398		return object;
44399
44400	}
44401
44402}
44403
44404class SpotLightShadow extends LightShadow {
44405
44406	constructor() {
44407
44408		super( new PerspectiveCamera( 50, 1, 0.5, 500 ) );
44409
44410		this.isSpotLightShadow = true;
44411
44412		this.focus = 1;
44413
44414	}
44415
44416	updateMatrices( light ) {
44417
44418		const camera = this.camera;
44419
44420		const fov = RAD2DEG * 2 * light.angle * this.focus;
44421		const aspect = this.mapSize.width / this.mapSize.height;
44422		const far = light.distance || camera.far;
44423
44424		if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
44425
44426			camera.fov = fov;
44427			camera.aspect = aspect;
44428			camera.far = far;
44429			camera.updateProjectionMatrix();
44430
44431		}
44432
44433		super.updateMatrices( light );
44434
44435	}
44436
44437	copy( source ) {
44438
44439		super.copy( source );
44440
44441		this.focus = source.focus;
44442
44443		return this;
44444
44445	}
44446
44447}
44448
44449class SpotLight extends Light {
44450
44451	constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) {
44452
44453		super( color, intensity );
44454
44455		this.isSpotLight = true;
44456
44457		this.type = 'SpotLight';
44458
44459		this.position.copy( Object3D.DEFAULT_UP );
44460		this.updateMatrix();
44461
44462		this.target = new Object3D();
44463
44464		this.distance = distance;
44465		this.angle = angle;
44466		this.penumbra = penumbra;
44467		this.decay = decay;
44468
44469		this.map = null;
44470
44471		this.shadow = new SpotLightShadow();
44472
44473	}
44474
44475	get power() {
44476
44477		// compute the light's luminous power (in lumens) from its intensity (in candela)
44478		// by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)
44479		return this.intensity * Math.PI;
44480
44481	}
44482
44483	set power( power ) {
44484
44485		// set the light's intensity (in candela) from the desired luminous power (in lumens)
44486		this.intensity = power / Math.PI;
44487
44488	}
44489
44490	dispose() {
44491
44492		this.shadow.dispose();
44493
44494	}
44495
44496	copy( source, recursive ) {
44497
44498		super.copy( source, recursive );
44499
44500		this.distance = source.distance;
44501		this.angle = source.angle;
44502		this.penumbra = source.penumbra;
44503		this.decay = source.decay;
44504
44505		this.target = source.target.clone();
44506
44507		this.shadow = source.shadow.clone();
44508
44509		return this;
44510
44511	}
44512
44513}
44514
44515const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
44516const _lightPositionWorld = /*@__PURE__*/ new Vector3();
44517const _lookTarget = /*@__PURE__*/ new Vector3();
44518
44519class PointLightShadow extends LightShadow {
44520
44521	constructor() {
44522
44523		super( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
44524
44525		this.isPointLightShadow = true;
44526
44527		this._frameExtents = new Vector2( 4, 2 );
44528
44529		this._viewportCount = 6;
44530
44531		this._viewports = [
44532			// These viewports map a cube-map onto a 2D texture with the
44533			// following orientation:
44534			//
44535			//  xzXZ
44536			//   y Y
44537			//
44538			// X - Positive x direction
44539			// x - Negative x direction
44540			// Y - Positive y direction
44541			// y - Negative y direction
44542			// Z - Positive z direction
44543			// z - Negative z direction
44544
44545			// positive X
44546			new Vector4( 2, 1, 1, 1 ),
44547			// negative X
44548			new Vector4( 0, 1, 1, 1 ),
44549			// positive Z
44550			new Vector4( 3, 1, 1, 1 ),
44551			// negative Z
44552			new Vector4( 1, 1, 1, 1 ),
44553			// positive Y
44554			new Vector4( 3, 0, 1, 1 ),
44555			// negative Y
44556			new Vector4( 1, 0, 1, 1 )
44557		];
44558
44559		this._cubeDirections = [
44560			new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
44561			new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
44562		];
44563
44564		this._cubeUps = [
44565			new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
44566			new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
44567		];
44568
44569	}
44570
44571	updateMatrices( light, viewportIndex = 0 ) {
44572
44573		const camera = this.camera;
44574		const shadowMatrix = this.matrix;
44575
44576		const far = light.distance || camera.far;
44577
44578		if ( far !== camera.far ) {
44579
44580			camera.far = far;
44581			camera.updateProjectionMatrix();
44582
44583		}
44584
44585		_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
44586		camera.position.copy( _lightPositionWorld );
44587
44588		_lookTarget.copy( camera.position );
44589		_lookTarget.add( this._cubeDirections[ viewportIndex ] );
44590		camera.up.copy( this._cubeUps[ viewportIndex ] );
44591		camera.lookAt( _lookTarget );
44592		camera.updateMatrixWorld();
44593
44594		shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
44595
44596		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
44597		this._frustum.setFromProjectionMatrix( _projScreenMatrix );
44598
44599	}
44600
44601}
44602
44603class PointLight extends Light {
44604
44605	constructor( color, intensity, distance = 0, decay = 2 ) {
44606
44607		super( color, intensity );
44608
44609		this.isPointLight = true;
44610
44611		this.type = 'PointLight';
44612
44613		this.distance = distance;
44614		this.decay = decay;
44615
44616		this.shadow = new PointLightShadow();
44617
44618	}
44619
44620	get power() {
44621
44622		// compute the light's luminous power (in lumens) from its intensity (in candela)
44623		// for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)
44624		return this.intensity * 4 * Math.PI;
44625
44626	}
44627
44628	set power( power ) {
44629
44630		// set the light's intensity (in candela) from the desired luminous power (in lumens)
44631		this.intensity = power / ( 4 * Math.PI );
44632
44633	}
44634
44635	dispose() {
44636
44637		this.shadow.dispose();
44638
44639	}
44640
44641	copy( source, recursive ) {
44642
44643		super.copy( source, recursive );
44644
44645		this.distance = source.distance;
44646		this.decay = source.decay;
44647
44648		this.shadow = source.shadow.clone();
44649
44650		return this;
44651
44652	}
44653
44654}
44655
44656class DirectionalLightShadow extends LightShadow {
44657
44658	constructor() {
44659
vendor: 4,273 bytes, lines 44660-44881
44660		super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
44661
44662		this.isDirectionalLightShadow = true;
44663
44664	}
44665
44666}
44667
44668class DirectionalLight extends Light {
44669
44670	constructor( color, intensity ) {
44671
44672		super( color, intensity );
44673
44674		this.isDirectionalLight = true;
44675
44676		this.type = 'DirectionalLight';
44677
44678		this.position.copy( Object3D.DEFAULT_UP );
44679		this.updateMatrix();
44680
44681		this.target = new Object3D();
44682
44683		this.shadow = new DirectionalLightShadow();
44684
44685	}
44686
44687	dispose() {
44688
44689		this.shadow.dispose();
44690
44691	}
44692
44693	copy( source ) {
44694
44695		super.copy( source );
44696
44697		this.target = source.target.clone();
44698		this.shadow = source.shadow.clone();
44699
44700		return this;
44701
44702	}
44703
44704}
44705
44706class AmbientLight extends Light {
44707
44708	constructor( color, intensity ) {
44709
44710		super( color, intensity );
44711
44712		this.isAmbientLight = true;
44713
44714		this.type = 'AmbientLight';
44715
44716	}
44717
44718}
44719
44720class RectAreaLight extends Light {
44721
44722	constructor( color, intensity, width = 10, height = 10 ) {
44723
44724		super( color, intensity );
44725
44726		this.isRectAreaLight = true;
44727
44728		this.type = 'RectAreaLight';
44729
44730		this.width = width;
44731		this.height = height;
44732
44733	}
44734
44735	get power() {
44736
44737		// compute the light's luminous power (in lumens) from its intensity (in nits)
44738		return this.intensity * this.width * this.height * Math.PI;
44739
44740	}
44741
44742	set power( power ) {
44743
44744		// set the light's intensity (in nits) from the desired luminous power (in lumens)
44745		this.intensity = power / ( this.width * this.height * Math.PI );
44746
44747	}
44748
44749	copy( source ) {
44750
44751		super.copy( source );
44752
44753		this.width = source.width;
44754		this.height = source.height;
44755
44756		return this;
44757
44758	}
44759
44760	toJSON( meta ) {
44761
44762		const data = super.toJSON( meta );
44763
44764		data.object.width = this.width;
44765		data.object.height = this.height;
44766
44767		return data;
44768
44769	}
44770
44771}
44772
44773/**
44774 * Primary reference:
44775 *   https://graphics.stanford.edu/papers/envmap/envmap.pdf
44776 *
44777 * Secondary reference:
44778 *   https://www.ppsloan.org/publications/StupidSH36.pdf
44779 */
44780
44781// 3-band SH defined by 9 coefficients
44782
44783class SphericalHarmonics3 {
44784
44785	constructor() {
44786
44787		this.isSphericalHarmonics3 = true;
44788
44789		this.coefficients = [];
44790
44791		for ( let i = 0; i < 9; i ++ ) {
44792
44793			this.coefficients.push( new Vector3() );
44794
44795		}
44796
44797	}
44798
44799	set( coefficients ) {
44800
44801		for ( let i = 0; i < 9; i ++ ) {
44802
44803			this.coefficients[ i ].copy( coefficients[ i ] );
44804
44805		}
44806
44807		return this;
44808
44809	}
44810
44811	zero() {
44812
44813		for ( let i = 0; i < 9; i ++ ) {
44814
44815			this.coefficients[ i ].set( 0, 0, 0 );
44816
44817		}
44818
44819		return this;
44820
44821	}
44822
44823	// get the radiance in the direction of the normal
44824	// target is a Vector3
44825	getAt( normal, target ) {
44826
44827		// normal is assumed to be unit length
44828
44829		const x = normal.x, y = normal.y, z = normal.z;
44830
44831		const coeff = this.coefficients;
44832
44833		// band 0
44834		target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
44835
44836		// band 1
44837		target.addScaledVector( coeff[ 1 ], 0.488603 * y );
44838		target.addScaledVector( coeff[ 2 ], 0.488603 * z );
44839		target.addScaledVector( coeff[ 3 ], 0.488603 * x );
44840
44841		// band 2
44842		target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
44843		target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
44844		target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
44845		target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
44846		target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
44847
44848		return target;
44849
44850	}
44851
44852	// get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
44853	// target is a Vector3
44854	// https://graphics.stanford.edu/papers/envmap/envmap.pdf
44855	getIrradianceAt( normal, target ) {
44856
44857		// normal is assumed to be unit length
44858
44859		const x = normal.x, y = normal.y, z = normal.z;
44860
44861		const coeff = this.coefficients;
44862
44863		// band 0
44864		target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
44865
44866		// band 1
44867		target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
44868		target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
44869		target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
44870
44871		// band 2
44872		target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
44873		target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
44874		target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
44875		target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
44876		target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
44877
44878		return target;
44879
44880	}
44881
vendor: 39,459 bytes, lines 44882-46521
44882	add( sh ) {
44883
44884		for ( let i = 0; i < 9; i ++ ) {
44885
44886			this.coefficients[ i ].add( sh.coefficients[ i ] );
44887
44888		}
44889
44890		return this;
44891
44892	}
44893
44894	addScaledSH( sh, s ) {
44895
44896		for ( let i = 0; i < 9; i ++ ) {
44897
44898			this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
44899
44900		}
44901
44902		return this;
44903
44904	}
44905
44906	scale( s ) {
44907
44908		for ( let i = 0; i < 9; i ++ ) {
44909
44910			this.coefficients[ i ].multiplyScalar( s );
44911
44912		}
44913
44914		return this;
44915
44916	}
44917
44918	lerp( sh, alpha ) {
44919
44920		for ( let i = 0; i < 9; i ++ ) {
44921
44922			this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
44923
44924		}
44925
44926		return this;
44927
44928	}
44929
44930	equals( sh ) {
44931
44932		for ( let i = 0; i < 9; i ++ ) {
44933
44934			if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
44935
44936				return false;
44937
44938			}
44939
44940		}
44941
44942		return true;
44943
44944	}
44945
44946	copy( sh ) {
44947
44948		return this.set( sh.coefficients );
44949
44950	}
44951
44952	clone() {
44953
44954		return new this.constructor().copy( this );
44955
44956	}
44957
44958	fromArray( array, offset = 0 ) {
44959
44960		const coefficients = this.coefficients;
44961
44962		for ( let i = 0; i < 9; i ++ ) {
44963
44964			coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
44965
44966		}
44967
44968		return this;
44969
44970	}
44971
44972	toArray( array = [], offset = 0 ) {
44973
44974		const coefficients = this.coefficients;
44975
44976		for ( let i = 0; i < 9; i ++ ) {
44977
44978			coefficients[ i ].toArray( array, offset + ( i * 3 ) );
44979
44980		}
44981
44982		return array;
44983
44984	}
44985
44986	// evaluate the basis functions
44987	// shBasis is an Array[ 9 ]
44988	static getBasisAt( normal, shBasis ) {
44989
44990		// normal is assumed to be unit length
44991
44992		const x = normal.x, y = normal.y, z = normal.z;
44993
44994		// band 0
44995		shBasis[ 0 ] = 0.282095;
44996
44997		// band 1
44998		shBasis[ 1 ] = 0.488603 * y;
44999		shBasis[ 2 ] = 0.488603 * z;
45000		shBasis[ 3 ] = 0.488603 * x;
45001
45002		// band 2
45003		shBasis[ 4 ] = 1.092548 * x * y;
45004		shBasis[ 5 ] = 1.092548 * y * z;
45005		shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
45006		shBasis[ 7 ] = 1.092548 * x * z;
45007		shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
45008
45009	}
45010
45011}
45012
45013class LightProbe extends Light {
45014
45015	constructor( sh = new SphericalHarmonics3(), intensity = 1 ) {
45016
45017		super( undefined, intensity );
45018
45019		this.isLightProbe = true;
45020
45021		this.sh = sh;
45022
45023	}
45024
45025	copy( source ) {
45026
45027		super.copy( source );
45028
45029		this.sh.copy( source.sh );
45030
45031		return this;
45032
45033	}
45034
45035	fromJSON( json ) {
45036
45037		this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
45038		this.sh.fromArray( json.sh );
45039
45040		return this;
45041
45042	}
45043
45044	toJSON( meta ) {
45045
45046		const data = super.toJSON( meta );
45047
45048		data.object.sh = this.sh.toArray();
45049
45050		return data;
45051
45052	}
45053
45054}
45055
45056class MaterialLoader extends Loader {
45057
45058	constructor( manager ) {
45059
45060		super( manager );
45061		this.textures = {};
45062
45063	}
45064
45065	load( url, onLoad, onProgress, onError ) {
45066
45067		const scope = this;
45068
45069		const loader = new FileLoader( scope.manager );
45070		loader.setPath( scope.path );
45071		loader.setRequestHeader( scope.requestHeader );
45072		loader.setWithCredentials( scope.withCredentials );
45073		loader.load( url, function ( text ) {
45074
45075			try {
45076
45077				onLoad( scope.parse( JSON.parse( text ) ) );
45078
45079			} catch ( e ) {
45080
45081				if ( onError ) {
45082
45083					onError( e );
45084
45085				} else {
45086
45087					console.error( e );
45088
45089				}
45090
45091				scope.manager.itemError( url );
45092
45093			}
45094
45095		}, onProgress, onError );
45096
45097	}
45098
45099	parse( json ) {
45100
45101		const textures = this.textures;
45102
45103		function getTexture( name ) {
45104
45105			if ( textures[ name ] === undefined ) {
45106
45107				console.warn( 'THREE.MaterialLoader: Undefined texture', name );
45108
45109			}
45110
45111			return textures[ name ];
45112
45113		}
45114
45115		const material = MaterialLoader.createMaterialFromType( json.type );
45116
45117		if ( json.uuid !== undefined ) material.uuid = json.uuid;
45118		if ( json.name !== undefined ) material.name = json.name;
45119		if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
45120		if ( json.roughness !== undefined ) material.roughness = json.roughness;
45121		if ( json.metalness !== undefined ) material.metalness = json.metalness;
45122		if ( json.sheen !== undefined ) material.sheen = json.sheen;
45123		if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor );
45124		if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness;
45125		if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
45126		if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
45127		if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;
45128		if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor );
45129		if ( json.shininess !== undefined ) material.shininess = json.shininess;
45130		if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
45131		if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
45132		if ( json.iridescence !== undefined ) material.iridescence = json.iridescence;
45133		if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR;
45134		if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange;
45135		if ( json.transmission !== undefined ) material.transmission = json.transmission;
45136		if ( json.thickness !== undefined ) material.thickness = json.thickness;
45137		if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;
45138		if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );
45139		if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;
45140		if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation;
45141		if ( json.fog !== undefined ) material.fog = json.fog;
45142		if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
45143		if ( json.blending !== undefined ) material.blending = json.blending;
45144		if ( json.combine !== undefined ) material.combine = json.combine;
45145		if ( json.side !== undefined ) material.side = json.side;
45146		if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide;
45147		if ( json.opacity !== undefined ) material.opacity = json.opacity;
45148		if ( json.transparent !== undefined ) material.transparent = json.transparent;
45149		if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
45150		if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;
45151		if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc;
45152		if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
45153		if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
45154		if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
45155		if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc;
45156		if ( json.blendDst !== undefined ) material.blendDst = json.blendDst;
45157		if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation;
45158		if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha;
45159		if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha;
45160		if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha;
45161		if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor );
45162		if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha;
45163		if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
45164		if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
45165		if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
45166		if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
45167		if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
45168		if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
45169		if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
45170		if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
45171
45172		if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
45173		if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
45174		if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
45175		if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
45176
45177		if ( json.rotation !== undefined ) material.rotation = json.rotation;
45178
45179		if ( json.linewidth !== undefined ) material.linewidth = json.linewidth;
45180		if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
45181		if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
45182		if ( json.scale !== undefined ) material.scale = json.scale;
45183
45184		if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
45185		if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
45186		if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
45187
45188		if ( json.dithering !== undefined ) material.dithering = json.dithering;
45189
45190		if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage;
45191		if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha;
45192		if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass;
45193
45194		if ( json.visible !== undefined ) material.visible = json.visible;
45195
45196		if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
45197
45198		if ( json.userData !== undefined ) material.userData = json.userData;
45199
45200		if ( json.vertexColors !== undefined ) {
45201
45202			if ( typeof json.vertexColors === 'number' ) {
45203
45204				material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
45205
45206			} else {
45207
45208				material.vertexColors = json.vertexColors;
45209
45210			}
45211
45212		}
45213
45214		// Shader Material
45215
45216		if ( json.uniforms !== undefined ) {
45217
45218			for ( const name in json.uniforms ) {
45219
45220				const uniform = json.uniforms[ name ];
45221
45222				material.uniforms[ name ] = {};
45223
45224				switch ( uniform.type ) {
45225
45226					case 't':
45227						material.uniforms[ name ].value = getTexture( uniform.value );
45228						break;
45229
45230					case 'c':
45231						material.uniforms[ name ].value = new Color().setHex( uniform.value );
45232						break;
45233
45234					case 'v2':
45235						material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
45236						break;
45237
45238					case 'v3':
45239						material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
45240						break;
45241
45242					case 'v4':
45243						material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
45244						break;
45245
45246					case 'm3':
45247						material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
45248						break;
45249
45250					case 'm4':
45251						material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
45252						break;
45253
45254					default:
45255						material.uniforms[ name ].value = uniform.value;
45256
45257				}
45258
45259			}
45260
45261		}
45262
45263		if ( json.defines !== undefined ) material.defines = json.defines;
45264		if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
45265		if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
45266		if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion;
45267
45268		if ( json.extensions !== undefined ) {
45269
45270			for ( const key in json.extensions ) {
45271
45272				material.extensions[ key ] = json.extensions[ key ];
45273
45274			}
45275
45276		}
45277
45278		if ( json.lights !== undefined ) material.lights = json.lights;
45279		if ( json.clipping !== undefined ) material.clipping = json.clipping;
45280
45281		// for PointsMaterial
45282
45283		if ( json.size !== undefined ) material.size = json.size;
45284		if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
45285
45286		// maps
45287
45288		if ( json.map !== undefined ) material.map = getTexture( json.map );
45289		if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
45290
45291		if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
45292
45293		if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
45294		if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
45295
45296		if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
45297		if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
45298		if ( json.normalScale !== undefined ) {
45299
45300			let normalScale = json.normalScale;
45301
45302			if ( Array.isArray( normalScale ) === false ) {
45303
45304				// Blender exporter used to export a scalar. See #7459
45305
45306				normalScale = [ normalScale, normalScale ];
45307
45308			}
45309
45310			material.normalScale = new Vector2().fromArray( normalScale );
45311
45312		}
45313
45314		if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
45315		if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
45316		if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
45317
45318		if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
45319		if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
45320
45321		if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
45322		if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
45323
45324		if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
45325		if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );
45326		if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap );
45327
45328		if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
45329		if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
45330
45331		if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
45332		if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
45333
45334		if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
45335		if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
45336
45337		if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
45338		if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
45339
45340		if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
45341
45342		if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
45343		if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
45344		if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
45345		if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
45346
45347		if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap );
45348		if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap );
45349
45350		if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
45351		if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );
45352
45353		if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );
45354
45355		if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );
45356		if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );
45357
45358		return material;
45359
45360	}
45361
45362	setTextures( value ) {
45363
45364		this.textures = value;
45365		return this;
45366
45367	}
45368
45369	static createMaterialFromType( type ) {
45370
45371		const materialLib = {
45372			ShadowMaterial,
45373			SpriteMaterial,
45374			RawShaderMaterial,
45375			ShaderMaterial,
45376			PointsMaterial,
45377			MeshPhysicalMaterial,
45378			MeshStandardMaterial,
45379			MeshPhongMaterial,
45380			MeshToonMaterial,
45381			MeshNormalMaterial,
45382			MeshLambertMaterial,
45383			MeshDepthMaterial,
45384			MeshDistanceMaterial,
45385			MeshBasicMaterial,
45386			MeshMatcapMaterial,
45387			LineDashedMaterial,
45388			LineBasicMaterial,
45389			Material
45390		};
45391
45392		return new materialLib[ type ]();
45393
45394	}
45395
45396}
45397
45398class LoaderUtils {
45399
45400	static decodeText( array ) {
45401
45402		if ( typeof TextDecoder !== 'undefined' ) {
45403
45404			return new TextDecoder().decode( array );
45405
45406		}
45407
45408		// Avoid the String.fromCharCode.apply(null, array) shortcut, which
45409		// throws a "maximum call stack size exceeded" error for large arrays.
45410
45411		let s = '';
45412
45413		for ( let i = 0, il = array.length; i < il; i ++ ) {
45414
45415			// Implicitly assumes little-endian.
45416			s += String.fromCharCode( array[ i ] );
45417
45418		}
45419
45420		try {
45421
45422			// merges multi-byte utf-8 characters.
45423
45424			return decodeURIComponent( escape( s ) );
45425
45426		} catch ( e ) { // see #16358
45427
45428			return s;
45429
45430		}
45431
45432	}
45433
45434	static extractUrlBase( url ) {
45435
45436		const index = url.lastIndexOf( '/' );
45437
45438		if ( index === - 1 ) return './';
45439
45440		return url.slice( 0, index + 1 );
45441
45442	}
45443
45444	static resolveURL( url, path ) {
45445
45446		// Invalid URL
45447		if ( typeof url !== 'string' || url === '' ) return '';
45448
45449		// Host Relative URL
45450		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
45451
45452			path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
45453
45454		}
45455
45456		// Absolute URL http://,https://,//
45457		if ( /^(https?:)?\/\//i.test( url ) ) return url;
45458
45459		// Data URI
45460		if ( /^data:.*,.*$/i.test( url ) ) return url;
45461
45462		// Blob URL
45463		if ( /^blob:.*$/i.test( url ) ) return url;
45464
45465		// Relative URL
45466		return path + url;
45467
45468	}
45469
45470}
45471
45472class InstancedBufferGeometry extends BufferGeometry {
45473
45474	constructor() {
45475
45476		super();
45477
45478		this.isInstancedBufferGeometry = true;
45479
45480		this.type = 'InstancedBufferGeometry';
45481		this.instanceCount = Infinity;
45482
45483	}
45484
45485	copy( source ) {
45486
45487		super.copy( source );
45488
45489		this.instanceCount = source.instanceCount;
45490
45491		return this;
45492
45493	}
45494
45495	toJSON() {
45496
45497		const data = super.toJSON();
45498
45499		data.instanceCount = this.instanceCount;
45500
45501		data.isInstancedBufferGeometry = true;
45502
45503		return data;
45504
45505	}
45506
45507}
45508
45509class BufferGeometryLoader extends Loader {
45510
45511	constructor( manager ) {
45512
45513		super( manager );
45514
45515	}
45516
45517	load( url, onLoad, onProgress, onError ) {
45518
45519		const scope = this;
45520
45521		const loader = new FileLoader( scope.manager );
45522		loader.setPath( scope.path );
45523		loader.setRequestHeader( scope.requestHeader );
45524		loader.setWithCredentials( scope.withCredentials );
45525		loader.load( url, function ( text ) {
45526
45527			try {
45528
45529				onLoad( scope.parse( JSON.parse( text ) ) );
45530
45531			} catch ( e ) {
45532
45533				if ( onError ) {
45534
45535					onError( e );
45536
45537				} else {
45538
45539					console.error( e );
45540
45541				}
45542
45543				scope.manager.itemError( url );
45544
45545			}
45546
45547		}, onProgress, onError );
45548
45549	}
45550
45551	parse( json ) {
45552
45553		const interleavedBufferMap = {};
45554		const arrayBufferMap = {};
45555
45556		function getInterleavedBuffer( json, uuid ) {
45557
45558			if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
45559
45560			const interleavedBuffers = json.interleavedBuffers;
45561			const interleavedBuffer = interleavedBuffers[ uuid ];
45562
45563			const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
45564
45565			const array = getTypedArray( interleavedBuffer.type, buffer );
45566			const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
45567			ib.uuid = interleavedBuffer.uuid;
45568
45569			interleavedBufferMap[ uuid ] = ib;
45570
45571			return ib;
45572
45573		}
45574
45575		function getArrayBuffer( json, uuid ) {
45576
45577			if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
45578
45579			const arrayBuffers = json.arrayBuffers;
45580			const arrayBuffer = arrayBuffers[ uuid ];
45581
45582			const ab = new Uint32Array( arrayBuffer ).buffer;
45583
45584			arrayBufferMap[ uuid ] = ab;
45585
45586			return ab;
45587
45588		}
45589
45590		const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
45591
45592		const index = json.data.index;
45593
45594		if ( index !== undefined ) {
45595
45596			const typedArray = getTypedArray( index.type, index.array );
45597			geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
45598
45599		}
45600
45601		const attributes = json.data.attributes;
45602
45603		for ( const key in attributes ) {
45604
45605			const attribute = attributes[ key ];
45606			let bufferAttribute;
45607
45608			if ( attribute.isInterleavedBufferAttribute ) {
45609
45610				const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45611				bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45612
45613			} else {
45614
45615				const typedArray = getTypedArray( attribute.type, attribute.array );
45616				const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
45617				bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
45618
45619			}
45620
45621			if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45622			if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage );
45623
45624			geometry.setAttribute( key, bufferAttribute );
45625
45626		}
45627
45628		const morphAttributes = json.data.morphAttributes;
45629
45630		if ( morphAttributes ) {
45631
45632			for ( const key in morphAttributes ) {
45633
45634				const attributeArray = morphAttributes[ key ];
45635
45636				const array = [];
45637
45638				for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
45639
45640					const attribute = attributeArray[ i ];
45641					let bufferAttribute;
45642
45643					if ( attribute.isInterleavedBufferAttribute ) {
45644
45645						const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45646						bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45647
45648					} else {
45649
45650						const typedArray = getTypedArray( attribute.type, attribute.array );
45651						bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
45652
45653					}
45654
45655					if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45656					array.push( bufferAttribute );
45657
45658				}
45659
45660				geometry.morphAttributes[ key ] = array;
45661
45662			}
45663
45664		}
45665
45666		const morphTargetsRelative = json.data.morphTargetsRelative;
45667
45668		if ( morphTargetsRelative ) {
45669
45670			geometry.morphTargetsRelative = true;
45671
45672		}
45673
45674		const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
45675
45676		if ( groups !== undefined ) {
45677
45678			for ( let i = 0, n = groups.length; i !== n; ++ i ) {
45679
45680				const group = groups[ i ];
45681
45682				geometry.addGroup( group.start, group.count, group.materialIndex );
45683
45684			}
45685
45686		}
45687
45688		const boundingSphere = json.data.boundingSphere;
45689
45690		if ( boundingSphere !== undefined ) {
45691
45692			const center = new Vector3();
45693
45694			if ( boundingSphere.center !== undefined ) {
45695
45696				center.fromArray( boundingSphere.center );
45697
45698			}
45699
45700			geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
45701
45702		}
45703
45704		if ( json.name ) geometry.name = json.name;
45705		if ( json.userData ) geometry.userData = json.userData;
45706
45707		return geometry;
45708
45709	}
45710
45711}
45712
45713class ObjectLoader extends Loader {
45714
45715	constructor( manager ) {
45716
45717		super( manager );
45718
45719	}
45720
45721	load( url, onLoad, onProgress, onError ) {
45722
45723		const scope = this;
45724
45725		const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45726		this.resourcePath = this.resourcePath || path;
45727
45728		const loader = new FileLoader( this.manager );
45729		loader.setPath( this.path );
45730		loader.setRequestHeader( this.requestHeader );
45731		loader.setWithCredentials( this.withCredentials );
45732		loader.load( url, function ( text ) {
45733
45734			let json = null;
45735
45736			try {
45737
45738				json = JSON.parse( text );
45739
45740			} catch ( error ) {
45741
45742				if ( onError !== undefined ) onError( error );
45743
45744				console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
45745
45746				return;
45747
45748			}
45749
45750			const metadata = json.metadata;
45751
45752			if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45753
45754				if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) );
45755
45756				console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
45757				return;
45758
45759			}
45760
45761			scope.parse( json, onLoad );
45762
45763		}, onProgress, onError );
45764
45765	}
45766
45767	async loadAsync( url, onProgress ) {
45768
45769		const scope = this;
45770
45771		const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45772		this.resourcePath = this.resourcePath || path;
45773
45774		const loader = new FileLoader( this.manager );
45775		loader.setPath( this.path );
45776		loader.setRequestHeader( this.requestHeader );
45777		loader.setWithCredentials( this.withCredentials );
45778
45779		const text = await loader.loadAsync( url, onProgress );
45780
45781		const json = JSON.parse( text );
45782
45783		const metadata = json.metadata;
45784
45785		if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45786
45787			throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url );
45788
45789		}
45790
45791		return await scope.parseAsync( json );
45792
45793	}
45794
45795	parse( json, onLoad ) {
45796
45797		const animations = this.parseAnimations( json.animations );
45798		const shapes = this.parseShapes( json.shapes );
45799		const geometries = this.parseGeometries( json.geometries, shapes );
45800
45801		const images = this.parseImages( json.images, function () {
45802
45803			if ( onLoad !== undefined ) onLoad( object );
45804
45805		} );
45806
45807		const textures = this.parseTextures( json.textures, images );
45808		const materials = this.parseMaterials( json.materials, textures );
45809
45810		const object = this.parseObject( json.object, geometries, materials, textures, animations );
45811		const skeletons = this.parseSkeletons( json.skeletons, object );
45812
45813		this.bindSkeletons( object, skeletons );
45814
45815		//
45816
45817		if ( onLoad !== undefined ) {
45818
45819			let hasImages = false;
45820
45821			for ( const uuid in images ) {
45822
45823				if ( images[ uuid ].data instanceof HTMLImageElement ) {
45824
45825					hasImages = true;
45826					break;
45827
45828				}
45829
45830			}
45831
45832			if ( hasImages === false ) onLoad( object );
45833
45834		}
45835
45836		return object;
45837
45838	}
45839
45840	async parseAsync( json ) {
45841
45842		const animations = this.parseAnimations( json.animations );
45843		const shapes = this.parseShapes( json.shapes );
45844		const geometries = this.parseGeometries( json.geometries, shapes );
45845
45846		const images = await this.parseImagesAsync( json.images );
45847
45848		const textures = this.parseTextures( json.textures, images );
45849		const materials = this.parseMaterials( json.materials, textures );
45850
45851		const object = this.parseObject( json.object, geometries, materials, textures, animations );
45852		const skeletons = this.parseSkeletons( json.skeletons, object );
45853
45854		this.bindSkeletons( object, skeletons );
45855
45856		return object;
45857
45858	}
45859
45860	parseShapes( json ) {
45861
45862		const shapes = {};
45863
45864		if ( json !== undefined ) {
45865
45866			for ( let i = 0, l = json.length; i < l; i ++ ) {
45867
45868				const shape = new Shape().fromJSON( json[ i ] );
45869
45870				shapes[ shape.uuid ] = shape;
45871
45872			}
45873
45874		}
45875
45876		return shapes;
45877
45878	}
45879
45880	parseSkeletons( json, object ) {
45881
45882		const skeletons = {};
45883		const bones = {};
45884
45885		// generate bone lookup table
45886
45887		object.traverse( function ( child ) {
45888
45889			if ( child.isBone ) bones[ child.uuid ] = child;
45890
45891		} );
45892
45893		// create skeletons
45894
45895		if ( json !== undefined ) {
45896
45897			for ( let i = 0, l = json.length; i < l; i ++ ) {
45898
45899				const skeleton = new Skeleton().fromJSON( json[ i ], bones );
45900
45901				skeletons[ skeleton.uuid ] = skeleton;
45902
45903			}
45904
45905		}
45906
45907		return skeletons;
45908
45909	}
45910
45911	parseGeometries( json, shapes ) {
45912
45913		const geometries = {};
45914
45915		if ( json !== undefined ) {
45916
45917			const bufferGeometryLoader = new BufferGeometryLoader();
45918
45919			for ( let i = 0, l = json.length; i < l; i ++ ) {
45920
45921				let geometry;
45922				const data = json[ i ];
45923
45924				switch ( data.type ) {
45925
45926					case 'BufferGeometry':
45927					case 'InstancedBufferGeometry':
45928
45929						geometry = bufferGeometryLoader.parse( data );
45930						break;
45931
45932					default:
45933
45934						if ( data.type in Geometries ) {
45935
45936							geometry = Geometries[ data.type ].fromJSON( data, shapes );
45937
45938						} else {
45939
45940							console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` );
45941
45942						}
45943
45944				}
45945
45946				geometry.uuid = data.uuid;
45947
45948				if ( data.name !== undefined ) geometry.name = data.name;
45949				if ( data.userData !== undefined ) geometry.userData = data.userData;
45950
45951				geometries[ data.uuid ] = geometry;
45952
45953			}
45954
45955		}
45956
45957		return geometries;
45958
45959	}
45960
45961	parseMaterials( json, textures ) {
45962
45963		const cache = {}; // MultiMaterial
45964		const materials = {};
45965
45966		if ( json !== undefined ) {
45967
45968			const loader = new MaterialLoader();
45969			loader.setTextures( textures );
45970
45971			for ( let i = 0, l = json.length; i < l; i ++ ) {
45972
45973				const data = json[ i ];
45974
45975				if ( cache[ data.uuid ] === undefined ) {
45976
45977					cache[ data.uuid ] = loader.parse( data );
45978
45979				}
45980
45981				materials[ data.uuid ] = cache[ data.uuid ];
45982
45983			}
45984
45985		}
45986
45987		return materials;
45988
45989	}
45990
45991	parseAnimations( json ) {
45992
45993		const animations = {};
45994
45995		if ( json !== undefined ) {
45996
45997			for ( let i = 0; i < json.length; i ++ ) {
45998
45999				const data = json[ i ];
46000
46001				const clip = AnimationClip.parse( data );
46002
46003				animations[ clip.uuid ] = clip;
46004
46005			}
46006
46007		}
46008
46009		return animations;
46010
46011	}
46012
46013	parseImages( json, onLoad ) {
46014
46015		const scope = this;
46016		const images = {};
46017
46018		let loader;
46019
46020		function loadImage( url ) {
46021
46022			scope.manager.itemStart( url );
46023
46024			return loader.load( url, function () {
46025
46026				scope.manager.itemEnd( url );
46027
46028			}, undefined, function () {
46029
46030				scope.manager.itemError( url );
46031				scope.manager.itemEnd( url );
46032
46033			} );
46034
46035		}
46036
46037		function deserializeImage( image ) {
46038
46039			if ( typeof image === 'string' ) {
46040
46041				const url = image;
46042
46043				const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46044
46045				return loadImage( path );
46046
46047			} else {
46048
46049				if ( image.data ) {
46050
46051					return {
46052						data: getTypedArray( image.type, image.data ),
46053						width: image.width,
46054						height: image.height
46055					};
46056
46057				} else {
46058
46059					return null;
46060
46061				}
46062
46063			}
46064
46065		}
46066
46067		if ( json !== undefined && json.length > 0 ) {
46068
46069			const manager = new LoadingManager( onLoad );
46070
46071			loader = new ImageLoader( manager );
46072			loader.setCrossOrigin( this.crossOrigin );
46073
46074			for ( let i = 0, il = json.length; i < il; i ++ ) {
46075
46076				const image = json[ i ];
46077				const url = image.url;
46078
46079				if ( Array.isArray( url ) ) {
46080
46081					// load array of images e.g CubeTexture
46082
46083					const imageArray = [];
46084
46085					for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46086
46087						const currentUrl = url[ j ];
46088
46089						const deserializedImage = deserializeImage( currentUrl );
46090
46091						if ( deserializedImage !== null ) {
46092
46093							if ( deserializedImage instanceof HTMLImageElement ) {
46094
46095								imageArray.push( deserializedImage );
46096
46097							} else {
46098
46099								// special case: handle array of data textures for cube textures
46100
46101								imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46102
46103							}
46104
46105						}
46106
46107					}
46108
46109					images[ image.uuid ] = new Source( imageArray );
46110
46111				} else {
46112
46113					// load single image
46114
46115					const deserializedImage = deserializeImage( image.url );
46116					images[ image.uuid ] = new Source( deserializedImage );
46117
46118
46119				}
46120
46121			}
46122
46123		}
46124
46125		return images;
46126
46127	}
46128
46129	async parseImagesAsync( json ) {
46130
46131		const scope = this;
46132		const images = {};
46133
46134		let loader;
46135
46136		async function deserializeImage( image ) {
46137
46138			if ( typeof image === 'string' ) {
46139
46140				const url = image;
46141
46142				const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46143
46144				return await loader.loadAsync( path );
46145
46146			} else {
46147
46148				if ( image.data ) {
46149
46150					return {
46151						data: getTypedArray( image.type, image.data ),
46152						width: image.width,
46153						height: image.height
46154					};
46155
46156				} else {
46157
46158					return null;
46159
46160				}
46161
46162			}
46163
46164		}
46165
46166		if ( json !== undefined && json.length > 0 ) {
46167
46168			loader = new ImageLoader( this.manager );
46169			loader.setCrossOrigin( this.crossOrigin );
46170
46171			for ( let i = 0, il = json.length; i < il; i ++ ) {
46172
46173				const image = json[ i ];
46174				const url = image.url;
46175
46176				if ( Array.isArray( url ) ) {
46177
46178					// load array of images e.g CubeTexture
46179
46180					const imageArray = [];
46181
46182					for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46183
46184						const currentUrl = url[ j ];
46185
46186						const deserializedImage = await deserializeImage( currentUrl );
46187
46188						if ( deserializedImage !== null ) {
46189
46190							if ( deserializedImage instanceof HTMLImageElement ) {
46191
46192								imageArray.push( deserializedImage );
46193
46194							} else {
46195
46196								// special case: handle array of data textures for cube textures
46197
46198								imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46199
46200							}
46201
46202						}
46203
46204					}
46205
46206					images[ image.uuid ] = new Source( imageArray );
46207
46208				} else {
46209
46210					// load single image
46211
46212					const deserializedImage = await deserializeImage( image.url );
46213					images[ image.uuid ] = new Source( deserializedImage );
46214
46215				}
46216
46217			}
46218
46219		}
46220
46221		return images;
46222
46223	}
46224
46225	parseTextures( json, images ) {
46226
46227		function parseConstant( value, type ) {
46228
46229			if ( typeof value === 'number' ) return value;
46230
46231			console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
46232
46233			return type[ value ];
46234
46235		}
46236
46237		const textures = {};
46238
46239		if ( json !== undefined ) {
46240
46241			for ( let i = 0, l = json.length; i < l; i ++ ) {
46242
46243				const data = json[ i ];
46244
46245				if ( data.image === undefined ) {
46246
46247					console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
46248
46249				}
46250
46251				if ( images[ data.image ] === undefined ) {
46252
46253					console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
46254
46255				}
46256
46257				const source = images[ data.image ];
46258				const image = source.data;
46259
46260				let texture;
46261
46262				if ( Array.isArray( image ) ) {
46263
46264					texture = new CubeTexture();
46265
46266					if ( image.length === 6 ) texture.needsUpdate = true;
46267
46268				} else {
46269
46270					if ( image && image.data ) {
46271
46272						texture = new DataTexture();
46273
46274					} else {
46275
46276						texture = new Texture();
46277
46278					}
46279
46280					if ( image ) texture.needsUpdate = true; // textures can have undefined image data
46281
46282				}
46283
46284				texture.source = source;
46285
46286				texture.uuid = data.uuid;
46287
46288				if ( data.name !== undefined ) texture.name = data.name;
46289
46290				if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
46291				if ( data.channel !== undefined ) texture.channel = data.channel;
46292
46293				if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
46294				if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
46295				if ( data.center !== undefined ) texture.center.fromArray( data.center );
46296				if ( data.rotation !== undefined ) texture.rotation = data.rotation;
46297
46298				if ( data.wrap !== undefined ) {
46299
46300					texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
46301					texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
46302
46303				}
46304
46305				if ( data.format !== undefined ) texture.format = data.format;
46306				if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat;
46307				if ( data.type !== undefined ) texture.type = data.type;
46308				if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace;
46309				if ( data.encoding !== undefined ) texture.encoding = data.encoding; // @deprecated, r152
46310
46311				if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
46312				if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
46313				if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
46314
46315				if ( data.flipY !== undefined ) texture.flipY = data.flipY;
46316
46317				if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps;
46318				if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
46319				if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
46320				if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;
46321
46322				if ( data.userData !== undefined ) texture.userData = data.userData;
46323
46324				textures[ data.uuid ] = texture;
46325
46326			}
46327
46328		}
46329
46330		return textures;
46331
46332	}
46333
46334	parseObject( data, geometries, materials, textures, animations ) {
46335
46336		let object;
46337
46338		function getGeometry( name ) {
46339
46340			if ( geometries[ name ] === undefined ) {
46341
46342				console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
46343
46344			}
46345
46346			return geometries[ name ];
46347
46348		}
46349
46350		function getMaterial( name ) {
46351
46352			if ( name === undefined ) return undefined;
46353
46354			if ( Array.isArray( name ) ) {
46355
46356				const array = [];
46357
46358				for ( let i = 0, l = name.length; i < l; i ++ ) {
46359
46360					const uuid = name[ i ];
46361
46362					if ( materials[ uuid ] === undefined ) {
46363
46364						console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
46365
46366					}
46367
46368					array.push( materials[ uuid ] );
46369
46370				}
46371
46372				return array;
46373
46374			}
46375
46376			if ( materials[ name ] === undefined ) {
46377
46378				console.warn( 'THREE.ObjectLoader: Undefined material', name );
46379
46380			}
46381
46382			return materials[ name ];
46383
46384		}
46385
46386		function getTexture( uuid ) {
46387
46388			if ( textures[ uuid ] === undefined ) {
46389
46390				console.warn( 'THREE.ObjectLoader: Undefined texture', uuid );
46391
46392			}
46393
46394			return textures[ uuid ];
46395
46396		}
46397
46398		let geometry, material;
46399
46400		switch ( data.type ) {
46401
46402			case 'Scene':
46403
46404				object = new Scene();
46405
46406				if ( data.background !== undefined ) {
46407
46408					if ( Number.isInteger( data.background ) ) {
46409
46410						object.background = new Color( data.background );
46411
46412					} else {
46413
46414						object.background = getTexture( data.background );
46415
46416					}
46417
46418				}
46419
46420				if ( data.environment !== undefined ) {
46421
46422					object.environment = getTexture( data.environment );
46423
46424				}
46425
46426				if ( data.fog !== undefined ) {
46427
46428					if ( data.fog.type === 'Fog' ) {
46429
46430						object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
46431
46432					} else if ( data.fog.type === 'FogExp2' ) {
46433
46434						object.fog = new FogExp2( data.fog.color, data.fog.density );
46435
46436					}
46437
46438					if ( data.fog.name !== '' ) {
46439
46440						object.fog.name = data.fog.name;
46441
46442					}
46443
46444				}
46445
46446				if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness;
46447				if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity;
46448
46449				break;
46450
46451			case 'PerspectiveCamera':
46452
46453				object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
46454
46455				if ( data.focus !== undefined ) object.focus = data.focus;
46456				if ( data.zoom !== undefined ) object.zoom = data.zoom;
46457				if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
46458				if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
46459				if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46460
46461				break;
46462
46463			case 'OrthographicCamera':
46464
46465				object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
46466
46467				if ( data.zoom !== undefined ) object.zoom = data.zoom;
46468				if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46469
46470				break;
46471
46472			case 'AmbientLight':
46473
46474				object = new AmbientLight( data.color, data.intensity );
46475
46476				break;
46477
46478			case 'DirectionalLight':
46479
46480				object = new DirectionalLight( data.color, data.intensity );
46481
46482				break;
46483
46484			case 'PointLight':
46485
46486				object = new PointLight( data.color, data.intensity, data.distance, data.decay );
46487
46488				break;
46489
46490			case 'RectAreaLight':
46491
46492				object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
46493
46494				break;
46495
46496			case 'SpotLight':
46497
46498				object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
46499
46500				break;
46501
46502			case 'HemisphereLight':
46503
46504				object = new HemisphereLight( data.color, data.groundColor, data.intensity );
46505
46506				break;
46507
46508			case 'LightProbe':
46509
46510				object = new LightProbe().fromJSON( data );
46511
46512				break;
46513
46514			case 'SkinnedMesh':
46515
46516				geometry = getGeometry( data.geometry );
46517			 	material = getMaterial( data.material );
46518
46519				object = new SkinnedMesh( geometry, material );
46520
46521				if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
vendor: 17,451 bytes, lines 46522-47352
46522				if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
46523				if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
46524
46525				break;
46526
46527			case 'Mesh':
46528
46529				geometry = getGeometry( data.geometry );
46530				material = getMaterial( data.material );
46531
46532				object = new Mesh( geometry, material );
46533
46534				break;
46535
46536			case 'InstancedMesh':
46537
46538				geometry = getGeometry( data.geometry );
46539				material = getMaterial( data.material );
46540				const count = data.count;
46541				const instanceMatrix = data.instanceMatrix;
46542				const instanceColor = data.instanceColor;
46543
46544				object = new InstancedMesh( geometry, material, count );
46545				object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
46546				if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize );
46547
46548				break;
46549
46550			case 'BatchedMesh':
46551
46552				geometry = getGeometry( data.geometry );
46553				material = getMaterial( data.material );
46554
46555				object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material );
46556				object.geometry = geometry;
46557				object.perObjectFrustumCulled = data.perObjectFrustumCulled;
46558				object.sortObjects = data.sortObjects;
46559
46560				object._drawRanges = data.drawRanges;
46561				object._reservedRanges = data.reservedRanges;
46562
46563				object._visibility = data.visibility;
46564				object._active = data.active;
46565				object._bounds = data.bounds.map( bound => {
46566
46567					const box = new Box3();
46568					box.min.fromArray( bound.boxMin );
46569					box.max.fromArray( bound.boxMax );
46570
46571					const sphere = new Sphere();
46572					sphere.radius = bound.sphereRadius;
46573					sphere.center.fromArray( bound.sphereCenter );
46574
46575					return {
46576						boxInitialized: bound.boxInitialized,
46577						box: box,
46578
46579						sphereInitialized: bound.sphereInitialized,
46580						sphere: sphere
46581					};
46582
46583				} );
46584
46585				object._maxGeometryCount = data.maxGeometryCount;
46586				object._maxVertexCount = data.maxVertexCount;
46587				object._maxIndexCount = data.maxIndexCount;
46588
46589				object._geometryInitialized = data.geometryInitialized;
46590				object._geometryCount = data.geometryCount;
46591
46592				object._matricesTexture = getTexture( data.matricesTexture.uuid );
46593
46594				break;
46595
46596			case 'LOD':
46597
46598				object = new LOD();
46599
46600				break;
46601
46602			case 'Line':
46603
46604				object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );
46605
46606				break;
46607
46608			case 'LineLoop':
46609
46610				object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
46611
46612				break;
46613
46614			case 'LineSegments':
46615
46616				object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
46617
46618				break;
46619
46620			case 'PointCloud':
46621			case 'Points':
46622
46623				object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
46624
46625				break;
46626
46627			case 'Sprite':
46628
46629				object = new Sprite( getMaterial( data.material ) );
46630
46631				break;
46632
46633			case 'Group':
46634
46635				object = new Group();
46636
46637				break;
46638
46639			case 'Bone':
46640
46641				object = new Bone();
46642
46643				break;
46644
46645			default:
46646
46647				object = new Object3D();
46648
46649		}
46650
46651		object.uuid = data.uuid;
46652
46653		if ( data.name !== undefined ) object.name = data.name;
46654
46655		if ( data.matrix !== undefined ) {
46656
46657			object.matrix.fromArray( data.matrix );
46658
46659			if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
46660			if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
46661
46662		} else {
46663
46664			if ( data.position !== undefined ) object.position.fromArray( data.position );
46665			if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
46666			if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
46667			if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
46668
46669		}
46670
46671		if ( data.up !== undefined ) object.up.fromArray( data.up );
46672
46673		if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
46674		if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
46675
46676		if ( data.shadow ) {
46677
46678			if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
46679			if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
46680			if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
46681			if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
46682			if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
46683
46684		}
46685
46686		if ( data.visible !== undefined ) object.visible = data.visible;
46687		if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
46688		if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
46689		if ( data.userData !== undefined ) object.userData = data.userData;
46690		if ( data.layers !== undefined ) object.layers.mask = data.layers;
46691
46692		if ( data.children !== undefined ) {
46693
46694			const children = data.children;
46695
46696			for ( let i = 0; i < children.length; i ++ ) {
46697
46698				object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) );
46699
46700			}
46701
46702		}
46703
46704		if ( data.animations !== undefined ) {
46705
46706			const objectAnimations = data.animations;
46707
46708			for ( let i = 0; i < objectAnimations.length; i ++ ) {
46709
46710				const uuid = objectAnimations[ i ];
46711
46712				object.animations.push( animations[ uuid ] );
46713
46714			}
46715
46716		}
46717
46718		if ( data.type === 'LOD' ) {
46719
46720			if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
46721
46722			const levels = data.levels;
46723
46724			for ( let l = 0; l < levels.length; l ++ ) {
46725
46726				const level = levels[ l ];
46727				const child = object.getObjectByProperty( 'uuid', level.object );
46728
46729				if ( child !== undefined ) {
46730
46731					object.addLevel( child, level.distance, level.hysteresis );
46732
46733				}
46734
46735			}
46736
46737		}
46738
46739		return object;
46740
46741	}
46742
46743	bindSkeletons( object, skeletons ) {
46744
46745		if ( Object.keys( skeletons ).length === 0 ) return;
46746
46747		object.traverse( function ( child ) {
46748
46749			if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
46750
46751				const skeleton = skeletons[ child.skeleton ];
46752
46753				if ( skeleton === undefined ) {
46754
46755					console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
46756
46757				} else {
46758
46759					child.bind( skeleton, child.bindMatrix );
46760
46761				}
46762
46763			}
46764
46765		} );
46766
46767	}
46768
46769}
46770
46771const TEXTURE_MAPPING = {
46772	UVMapping: UVMapping,
46773	CubeReflectionMapping: CubeReflectionMapping,
46774	CubeRefractionMapping: CubeRefractionMapping,
46775	EquirectangularReflectionMapping: EquirectangularReflectionMapping,
46776	EquirectangularRefractionMapping: EquirectangularRefractionMapping,
46777	CubeUVReflectionMapping: CubeUVReflectionMapping
46778};
46779
46780const TEXTURE_WRAPPING = {
46781	RepeatWrapping: RepeatWrapping,
46782	ClampToEdgeWrapping: ClampToEdgeWrapping,
46783	MirroredRepeatWrapping: MirroredRepeatWrapping
46784};
46785
46786const TEXTURE_FILTER = {
46787	NearestFilter: NearestFilter,
46788	NearestMipmapNearestFilter: NearestMipmapNearestFilter,
46789	NearestMipmapLinearFilter: NearestMipmapLinearFilter,
46790	LinearFilter: LinearFilter,
46791	LinearMipmapNearestFilter: LinearMipmapNearestFilter,
46792	LinearMipmapLinearFilter: LinearMipmapLinearFilter
46793};
46794
46795class ImageBitmapLoader extends Loader {
46796
46797	constructor( manager ) {
46798
46799		super( manager );
46800
46801		this.isImageBitmapLoader = true;
46802
46803		if ( typeof createImageBitmap === 'undefined' ) {
46804
46805			console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
46806
46807		}
46808
46809		if ( typeof fetch === 'undefined' ) {
46810
46811			console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
46812
46813		}
46814
46815		this.options = { premultiplyAlpha: 'none' };
46816
46817	}
46818
46819	setOptions( options ) {
46820
46821		this.options = options;
46822
46823		return this;
46824
46825	}
46826
46827	load( url, onLoad, onProgress, onError ) {
46828
46829		if ( url === undefined ) url = '';
46830
46831		if ( this.path !== undefined ) url = this.path + url;
46832
46833		url = this.manager.resolveURL( url );
46834
46835		const scope = this;
46836
46837		const cached = Cache.get( url );
46838
46839		if ( cached !== undefined ) {
46840
46841			scope.manager.itemStart( url );
46842
46843			// If cached is a promise, wait for it to resolve
46844			if ( cached.then ) {
46845
46846				cached.then( imageBitmap => {
46847
46848					if ( onLoad ) onLoad( imageBitmap );
46849
46850					scope.manager.itemEnd( url );
46851
46852				} ).catch( e => {
46853
46854					if ( onError ) onError( e );
46855
46856				} );
46857				return;
46858
46859			}
46860
46861			// If cached is not a promise (i.e., it's already an imageBitmap)
46862			setTimeout( function () {
46863
46864				if ( onLoad ) onLoad( cached );
46865
46866				scope.manager.itemEnd( url );
46867
46868			}, 0 );
46869
46870			return cached;
46871
46872		}
46873
46874		const fetchOptions = {};
46875		fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
46876		fetchOptions.headers = this.requestHeader;
46877
46878		const promise = fetch( url, fetchOptions ).then( function ( res ) {
46879
46880			return res.blob();
46881
46882		} ).then( function ( blob ) {
46883
46884			return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );
46885
46886		} ).then( function ( imageBitmap ) {
46887
46888			Cache.add( url, imageBitmap );
46889
46890			if ( onLoad ) onLoad( imageBitmap );
46891
46892			scope.manager.itemEnd( url );
46893
46894			return imageBitmap;
46895
46896		} ).catch( function ( e ) {
46897
46898			if ( onError ) onError( e );
46899
46900			Cache.remove( url );
46901
46902			scope.manager.itemError( url );
46903			scope.manager.itemEnd( url );
46904
46905		} );
46906
46907		Cache.add( url, promise );
46908		scope.manager.itemStart( url );
46909
46910	}
46911
46912}
46913
46914let _context;
46915
46916class AudioContext {
46917
46918	static getContext() {
46919
46920		if ( _context === undefined ) {
46921
46922			_context = new ( window.AudioContext || window.webkitAudioContext )();
46923
46924		}
46925
46926		return _context;
46927
46928	}
46929
46930	static setContext( value ) {
46931
46932		_context = value;
46933
46934	}
46935
46936}
46937
46938class AudioLoader extends Loader {
46939
46940	constructor( manager ) {
46941
46942		super( manager );
46943
46944	}
46945
46946	load( url, onLoad, onProgress, onError ) {
46947
46948		const scope = this;
46949
46950		const loader = new FileLoader( this.manager );
46951		loader.setResponseType( 'arraybuffer' );
46952		loader.setPath( this.path );
46953		loader.setRequestHeader( this.requestHeader );
46954		loader.setWithCredentials( this.withCredentials );
46955		loader.load( url, function ( buffer ) {
46956
46957			try {
46958
46959				// Create a copy of the buffer. The `decodeAudioData` method
46960				// detaches the buffer when complete, preventing reuse.
46961				const bufferCopy = buffer.slice( 0 );
46962
46963				const context = AudioContext.getContext();
46964				context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
46965
46966					onLoad( audioBuffer );
46967
46968				} ).catch( handleError );
46969
46970			} catch ( e ) {
46971
46972				handleError( e );
46973
46974			}
46975
46976		}, onProgress, onError );
46977
46978		function handleError( e ) {
46979
46980			if ( onError ) {
46981
46982				onError( e );
46983
46984			} else {
46985
46986				console.error( e );
46987
46988			}
46989
46990			scope.manager.itemError( url );
46991
46992		}
46993
46994	}
46995
46996}
46997
46998const _eyeRight = /*@__PURE__*/ new Matrix4();
46999const _eyeLeft = /*@__PURE__*/ new Matrix4();
47000const _projectionMatrix = /*@__PURE__*/ new Matrix4();
47001
47002class StereoCamera {
47003
47004	constructor() {
47005
47006		this.type = 'StereoCamera';
47007
47008		this.aspect = 1;
47009
47010		this.eyeSep = 0.064;
47011
47012		this.cameraL = new PerspectiveCamera();
47013		this.cameraL.layers.enable( 1 );
47014		this.cameraL.matrixAutoUpdate = false;
47015
47016		this.cameraR = new PerspectiveCamera();
47017		this.cameraR.layers.enable( 2 );
47018		this.cameraR.matrixAutoUpdate = false;
47019
47020		this._cache = {
47021			focus: null,
47022			fov: null,
47023			aspect: null,
47024			near: null,
47025			far: null,
47026			zoom: null,
47027			eyeSep: null
47028		};
47029
47030	}
47031
47032	update( camera ) {
47033
47034		const cache = this._cache;
47035
47036		const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
47037			cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
47038			cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
47039
47040		if ( needsUpdate ) {
47041
47042			cache.focus = camera.focus;
47043			cache.fov = camera.fov;
47044			cache.aspect = camera.aspect * this.aspect;
47045			cache.near = camera.near;
47046			cache.far = camera.far;
47047			cache.zoom = camera.zoom;
47048			cache.eyeSep = this.eyeSep;
47049
47050			// Off-axis stereoscopic effect based on
47051			// http://paulbourke.net/stereographics/stereorender/
47052
47053			_projectionMatrix.copy( camera.projectionMatrix );
47054			const eyeSepHalf = cache.eyeSep / 2;
47055			const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
47056			const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
47057			let xmin, xmax;
47058
47059			// translate xOffset
47060
47061			_eyeLeft.elements[ 12 ] = - eyeSepHalf;
47062			_eyeRight.elements[ 12 ] = eyeSepHalf;
47063
47064			// for left eye
47065
47066			xmin = - ymax * cache.aspect + eyeSepOnProjection;
47067			xmax = ymax * cache.aspect + eyeSepOnProjection;
47068
47069			_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47070			_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47071
47072			this.cameraL.projectionMatrix.copy( _projectionMatrix );
47073
47074			// for right eye
47075
47076			xmin = - ymax * cache.aspect - eyeSepOnProjection;
47077			xmax = ymax * cache.aspect - eyeSepOnProjection;
47078
47079			_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47080			_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47081
47082			this.cameraR.projectionMatrix.copy( _projectionMatrix );
47083
47084		}
47085
47086		this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
47087		this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
47088
47089	}
47090
47091}
47092
47093class Clock {
47094
47095	constructor( autoStart = true ) {
47096
47097		this.autoStart = autoStart;
47098
47099		this.startTime = 0;
47100		this.oldTime = 0;
47101		this.elapsedTime = 0;
47102
47103		this.running = false;
47104
47105	}
47106
47107	start() {
47108
47109		this.startTime = now();
47110
47111		this.oldTime = this.startTime;
47112		this.elapsedTime = 0;
47113		this.running = true;
47114
47115	}
47116
47117	stop() {
47118
47119		this.getElapsedTime();
47120		this.running = false;
47121		this.autoStart = false;
47122
47123	}
47124
47125	getElapsedTime() {
47126
47127		this.getDelta();
47128		return this.elapsedTime;
47129
47130	}
47131
47132	getDelta() {
47133
47134		let diff = 0;
47135
47136		if ( this.autoStart && ! this.running ) {
47137
47138			this.start();
47139			return 0;
47140
47141		}
47142
47143		if ( this.running ) {
47144
47145			const newTime = now();
47146
47147			diff = ( newTime - this.oldTime ) / 1000;
47148			this.oldTime = newTime;
47149
47150			this.elapsedTime += diff;
47151
47152		}
47153
47154		return diff;
47155
47156	}
47157
47158}
47159
47160function now() {
47161
47162	return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
47163
47164}
47165
47166const _position$1 = /*@__PURE__*/ new Vector3();
47167const _quaternion$1 = /*@__PURE__*/ new Quaternion();
47168const _scale$1 = /*@__PURE__*/ new Vector3();
47169const _orientation$1 = /*@__PURE__*/ new Vector3();
47170
47171class AudioListener extends Object3D {
47172
47173	constructor() {
47174
47175		super();
47176
47177		this.type = 'AudioListener';
47178
47179		this.context = AudioContext.getContext();
47180
47181		this.gain = this.context.createGain();
47182		this.gain.connect( this.context.destination );
47183
47184		this.filter = null;
47185
47186		this.timeDelta = 0;
47187
47188		// private
47189
47190		this._clock = new Clock();
47191
47192	}
47193
47194	getInput() {
47195
47196		return this.gain;
47197
47198	}
47199
47200	removeFilter() {
47201
47202		if ( this.filter !== null ) {
47203
47204			this.gain.disconnect( this.filter );
47205			this.filter.disconnect( this.context.destination );
47206			this.gain.connect( this.context.destination );
47207			this.filter = null;
47208
47209		}
47210
47211		return this;
47212
47213	}
47214
47215	getFilter() {
47216
47217		return this.filter;
47218
47219	}
47220
47221	setFilter( value ) {
47222
47223		if ( this.filter !== null ) {
47224
47225			this.gain.disconnect( this.filter );
47226			this.filter.disconnect( this.context.destination );
47227
47228		} else {
47229
47230			this.gain.disconnect( this.context.destination );
47231
47232		}
47233
47234		this.filter = value;
47235		this.gain.connect( this.filter );
47236		this.filter.connect( this.context.destination );
47237
47238		return this;
47239
47240	}
47241
47242	getMasterVolume() {
47243
47244		return this.gain.gain.value;
47245
47246	}
47247
47248	setMasterVolume( value ) {
47249
47250		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47251
47252		return this;
47253
47254	}
47255
47256	updateMatrixWorld( force ) {
47257
47258		super.updateMatrixWorld( force );
47259
47260		const listener = this.context.listener;
47261		const up = this.up;
47262
47263		this.timeDelta = this._clock.getDelta();
47264
47265		this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );
47266
47267		_orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 );
47268
47269		if ( listener.positionX ) {
47270
47271			// code path for Chrome (see #14393)
47272
47273			const endTime = this.context.currentTime + this.timeDelta;
47274
47275			listener.positionX.linearRampToValueAtTime( _position$1.x, endTime );
47276			listener.positionY.linearRampToValueAtTime( _position$1.y, endTime );
47277			listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );
47278			listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime );
47279			listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime );
47280			listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime );
47281			listener.upX.linearRampToValueAtTime( up.x, endTime );
47282			listener.upY.linearRampToValueAtTime( up.y, endTime );
47283			listener.upZ.linearRampToValueAtTime( up.z, endTime );
47284
47285		} else {
47286
47287			listener.setPosition( _position$1.x, _position$1.y, _position$1.z );
47288			listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z );
47289
47290		}
47291
47292	}
47293
47294}
47295
47296class Audio extends Object3D {
47297
47298	constructor( listener ) {
47299
47300		super();
47301
47302		this.type = 'Audio';
47303
47304		this.listener = listener;
47305		this.context = listener.context;
47306
47307		this.gain = this.context.createGain();
47308		this.gain.connect( listener.getInput() );
47309
47310		this.autoplay = false;
47311
47312		this.buffer = null;
47313		this.detune = 0;
47314		this.loop = false;
47315		this.loopStart = 0;
47316		this.loopEnd = 0;
47317		this.offset = 0;
47318		this.duration = undefined;
47319		this.playbackRate = 1;
47320		this.isPlaying = false;
47321		this.hasPlaybackControl = true;
47322		this.source = null;
47323		this.sourceType = 'empty';
47324
47325		this._startedAt = 0;
47326		this._progress = 0;
47327		this._connected = false;
47328
47329		this.filters = [];
47330
47331	}
47332
47333	getOutput() {
47334
47335		return this.gain;
47336
47337	}
47338
47339	setNodeSource( audioNode ) {
47340
47341		this.hasPlaybackControl = false;
47342		this.sourceType = 'audioNode';
47343		this.source = audioNode;
47344		this.connect();
47345
47346		return this;
47347
47348	}
47349
47350	setMediaElementSource( mediaElement ) {
47351
47352		this.hasPlaybackControl = false;
vendor: 8,731 bytes, lines 47353-47898
47353		this.sourceType = 'mediaNode';
47354		this.source = this.context.createMediaElementSource( mediaElement );
47355		this.connect();
47356
47357		return this;
47358
47359	}
47360
47361	setMediaStreamSource( mediaStream ) {
47362
47363		this.hasPlaybackControl = false;
47364		this.sourceType = 'mediaStreamNode';
47365		this.source = this.context.createMediaStreamSource( mediaStream );
47366		this.connect();
47367
47368		return this;
47369
47370	}
47371
47372	setBuffer( audioBuffer ) {
47373
47374		this.buffer = audioBuffer;
47375		this.sourceType = 'buffer';
47376
47377		if ( this.autoplay ) this.play();
47378
47379		return this;
47380
47381	}
47382
47383	play( delay = 0 ) {
47384
47385		if ( this.isPlaying === true ) {
47386
47387			console.warn( 'THREE.Audio: Audio is already playing.' );
47388			return;
47389
47390		}
47391
47392		if ( this.hasPlaybackControl === false ) {
47393
47394			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47395			return;
47396
47397		}
47398
47399		this._startedAt = this.context.currentTime + delay;
47400
47401		const source = this.context.createBufferSource();
47402		source.buffer = this.buffer;
47403		source.loop = this.loop;
47404		source.loopStart = this.loopStart;
47405		source.loopEnd = this.loopEnd;
47406		source.onended = this.onEnded.bind( this );
47407		source.start( this._startedAt, this._progress + this.offset, this.duration );
47408
47409		this.isPlaying = true;
47410
47411		this.source = source;
47412
47413		this.setDetune( this.detune );
47414		this.setPlaybackRate( this.playbackRate );
47415
47416		return this.connect();
47417
47418	}
47419
47420	pause() {
47421
47422		if ( this.hasPlaybackControl === false ) {
47423
47424			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47425			return;
47426
47427		}
47428
47429		if ( this.isPlaying === true ) {
47430
47431			// update current progress
47432
47433			this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
47434
47435			if ( this.loop === true ) {
47436
47437				// ensure _progress does not exceed duration with looped audios
47438
47439				this._progress = this._progress % ( this.duration || this.buffer.duration );
47440
47441			}
47442
47443			this.source.stop();
47444			this.source.onended = null;
47445
47446			this.isPlaying = false;
47447
47448		}
47449
47450		return this;
47451
47452	}
47453
47454	stop() {
47455
47456		if ( this.hasPlaybackControl === false ) {
47457
47458			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47459			return;
47460
47461		}
47462
47463		this._progress = 0;
47464
47465		if ( this.source !== null ) {
47466
47467			this.source.stop();
47468			this.source.onended = null;
47469
47470		}
47471
47472		this.isPlaying = false;
47473
47474		return this;
47475
47476	}
47477
47478	connect() {
47479
47480		if ( this.filters.length > 0 ) {
47481
47482			this.source.connect( this.filters[ 0 ] );
47483
47484			for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47485
47486				this.filters[ i - 1 ].connect( this.filters[ i ] );
47487
47488			}
47489
47490			this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
47491
47492		} else {
47493
47494			this.source.connect( this.getOutput() );
47495
47496		}
47497
47498		this._connected = true;
47499
47500		return this;
47501
47502	}
47503
47504	disconnect() {
47505
47506		if ( this._connected === false ) {
47507
47508			return;
47509
47510		}
47511
47512		if ( this.filters.length > 0 ) {
47513
47514			this.source.disconnect( this.filters[ 0 ] );
47515
47516			for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47517
47518				this.filters[ i - 1 ].disconnect( this.filters[ i ] );
47519
47520			}
47521
47522			this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
47523
47524		} else {
47525
47526			this.source.disconnect( this.getOutput() );
47527
47528		}
47529
47530		this._connected = false;
47531
47532		return this;
47533
47534	}
47535
47536	getFilters() {
47537
47538		return this.filters;
47539
47540	}
47541
47542	setFilters( value ) {
47543
47544		if ( ! value ) value = [];
47545
47546		if ( this._connected === true ) {
47547
47548			this.disconnect();
47549			this.filters = value.slice();
47550			this.connect();
47551
47552		} else {
47553
47554			this.filters = value.slice();
47555
47556		}
47557
47558		return this;
47559
47560	}
47561
47562	setDetune( value ) {
47563
47564		this.detune = value;
47565
47566		if ( this.source.detune === undefined ) return; // only set detune when available
47567
47568		if ( this.isPlaying === true ) {
47569
47570			this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
47571
47572		}
47573
47574		return this;
47575
47576	}
47577
47578	getDetune() {
47579
47580		return this.detune;
47581
47582	}
47583
47584	getFilter() {
47585
47586		return this.getFilters()[ 0 ];
47587
47588	}
47589
47590	setFilter( filter ) {
47591
47592		return this.setFilters( filter ? [ filter ] : [] );
47593
47594	}
47595
47596	setPlaybackRate( value ) {
47597
47598		if ( this.hasPlaybackControl === false ) {
47599
47600			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47601			return;
47602
47603		}
47604
47605		this.playbackRate = value;
47606
47607		if ( this.isPlaying === true ) {
47608
47609			this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
47610
47611		}
47612
47613		return this;
47614
47615	}
47616
47617	getPlaybackRate() {
47618
47619		return this.playbackRate;
47620
47621	}
47622
47623	onEnded() {
47624
47625		this.isPlaying = false;
47626
47627	}
47628
47629	getLoop() {
47630
47631		if ( this.hasPlaybackControl === false ) {
47632
47633			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47634			return false;
47635
47636		}
47637
47638		return this.loop;
47639
47640	}
47641
47642	setLoop( value ) {
47643
47644		if ( this.hasPlaybackControl === false ) {
47645
47646			console.warn( 'THREE.Audio: this Audio has no playback control.' );
47647			return;
47648
47649		}
47650
47651		this.loop = value;
47652
47653		if ( this.isPlaying === true ) {
47654
47655			this.source.loop = this.loop;
47656
47657		}
47658
47659		return this;
47660
47661	}
47662
47663	setLoopStart( value ) {
47664
47665		this.loopStart = value;
47666
47667		return this;
47668
47669	}
47670
47671	setLoopEnd( value ) {
47672
47673		this.loopEnd = value;
47674
47675		return this;
47676
47677	}
47678
47679	getVolume() {
47680
47681		return this.gain.gain.value;
47682
47683	}
47684
47685	setVolume( value ) {
47686
47687		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47688
47689		return this;
47690
47691	}
47692
47693}
47694
47695const _position = /*@__PURE__*/ new Vector3();
47696const _quaternion = /*@__PURE__*/ new Quaternion();
47697const _scale = /*@__PURE__*/ new Vector3();
47698const _orientation = /*@__PURE__*/ new Vector3();
47699
47700class PositionalAudio extends Audio {
47701
47702	constructor( listener ) {
47703
47704		super( listener );
47705
47706		this.panner = this.context.createPanner();
47707		this.panner.panningModel = 'HRTF';
47708		this.panner.connect( this.gain );
47709
47710	}
47711
47712	connect() {
47713
47714		super.connect();
47715
47716		this.panner.connect( this.gain );
47717
47718	}
47719
47720	disconnect() {
47721
47722		super.disconnect();
47723
47724		this.panner.disconnect( this.gain );
47725
47726	}
47727
47728	getOutput() {
47729
47730		return this.panner;
47731
47732	}
47733
47734	getRefDistance() {
47735
47736		return this.panner.refDistance;
47737
47738	}
47739
47740	setRefDistance( value ) {
47741
47742		this.panner.refDistance = value;
47743
47744		return this;
47745
47746	}
47747
47748	getRolloffFactor() {
47749
47750		return this.panner.rolloffFactor;
47751
47752	}
47753
47754	setRolloffFactor( value ) {
47755
47756		this.panner.rolloffFactor = value;
47757
47758		return this;
47759
47760	}
47761
47762	getDistanceModel() {
47763
47764		return this.panner.distanceModel;
47765
47766	}
47767
47768	setDistanceModel( value ) {
47769
47770		this.panner.distanceModel = value;
47771
47772		return this;
47773
47774	}
47775
47776	getMaxDistance() {
47777
47778		return this.panner.maxDistance;
47779
47780	}
47781
47782	setMaxDistance( value ) {
47783
47784		this.panner.maxDistance = value;
47785
47786		return this;
47787
47788	}
47789
47790	setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
47791
47792		this.panner.coneInnerAngle = coneInnerAngle;
47793		this.panner.coneOuterAngle = coneOuterAngle;
47794		this.panner.coneOuterGain = coneOuterGain;
47795
47796		return this;
47797
47798	}
47799
47800	updateMatrixWorld( force ) {
47801
47802		super.updateMatrixWorld( force );
47803
47804		if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
47805
47806		this.matrixWorld.decompose( _position, _quaternion, _scale );
47807
47808		_orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );
47809
47810		const panner = this.panner;
47811
47812		if ( panner.positionX ) {
47813
47814			// code path for Chrome and Firefox (see #14393)
47815
47816			const endTime = this.context.currentTime + this.listener.timeDelta;
47817
47818			panner.positionX.linearRampToValueAtTime( _position.x, endTime );
47819			panner.positionY.linearRampToValueAtTime( _position.y, endTime );
47820			panner.positionZ.linearRampToValueAtTime( _position.z, endTime );
47821			panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );
47822			panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );
47823			panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );
47824
47825		} else {
47826
47827			panner.setPosition( _position.x, _position.y, _position.z );
47828			panner.setOrientation( _orientation.x, _orientation.y, _orientation.z );
47829
47830		}
47831
47832	}
47833
47834}
47835
47836class AudioAnalyser {
47837
47838	constructor( audio, fftSize = 2048 ) {
47839
47840		this.analyser = audio.context.createAnalyser();
47841		this.analyser.fftSize = fftSize;
47842
47843		this.data = new Uint8Array( this.analyser.frequencyBinCount );
47844
47845		audio.getOutput().connect( this.analyser );
47846
47847	}
47848
47849
47850	getFrequencyData() {
47851
47852		this.analyser.getByteFrequencyData( this.data );
47853
47854		return this.data;
47855
47856	}
47857
47858	getAverageFrequency() {
47859
47860		let value = 0;
47861		const data = this.getFrequencyData();
47862
47863		for ( let i = 0; i < data.length; i ++ ) {
47864
47865			value += data[ i ];
47866
47867		}
47868
47869		return value / data.length;
47870
47871	}
47872
47873}
47874
47875class PropertyMixer {
47876
47877	constructor( binding, typeName, valueSize ) {
47878
47879		this.binding = binding;
47880		this.valueSize = valueSize;
47881
47882		let mixFunction,
47883			mixFunctionAdditive,
47884			setIdentity;
47885
47886		// buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
47887		//
47888		// interpolators can use .buffer as their .result
47889		// the data then goes to 'incoming'
47890		//
47891		// 'accu0' and 'accu1' are used frame-interleaved for
47892		// the cumulative result and are compared to detect
47893		// changes
47894		//
47895		// 'orig' stores the original state of the property
47896		//
47897		// 'add' is used for additive cumulative results
47898		//
vendor: 13,778 bytes, lines 47899-48529
47899		// 'work' is optional and is only present for quaternion types. It is used
47900		// to store intermediate quaternion multiplication results
47901
47902		switch ( typeName ) {
47903
47904			case 'quaternion':
47905				mixFunction = this._slerp;
47906				mixFunctionAdditive = this._slerpAdditive;
47907				setIdentity = this._setAdditiveIdentityQuaternion;
47908
47909				this.buffer = new Float64Array( valueSize * 6 );
47910				this._workIndex = 5;
47911				break;
47912
47913			case 'string':
47914			case 'bool':
47915				mixFunction = this._select;
47916
47917				// Use the regular mix function and for additive on these types,
47918				// additive is not relevant for non-numeric types
47919				mixFunctionAdditive = this._select;
47920
47921				setIdentity = this._setAdditiveIdentityOther;
47922
47923				this.buffer = new Array( valueSize * 5 );
47924				break;
47925
47926			default:
47927				mixFunction = this._lerp;
47928				mixFunctionAdditive = this._lerpAdditive;
47929				setIdentity = this._setAdditiveIdentityNumeric;
47930
47931				this.buffer = new Float64Array( valueSize * 5 );
47932
47933		}
47934
47935		this._mixBufferRegion = mixFunction;
47936		this._mixBufferRegionAdditive = mixFunctionAdditive;
47937		this._setIdentity = setIdentity;
47938		this._origIndex = 3;
47939		this._addIndex = 4;
47940
47941		this.cumulativeWeight = 0;
47942		this.cumulativeWeightAdditive = 0;
47943
47944		this.useCount = 0;
47945		this.referenceCount = 0;
47946
47947	}
47948
47949	// accumulate data in the 'incoming' region into 'accu<i>'
47950	accumulate( accuIndex, weight ) {
47951
47952		// note: happily accumulating nothing when weight = 0, the caller knows
47953		// the weight and shouldn't have made the call in the first place
47954
47955		const buffer = this.buffer,
47956			stride = this.valueSize,
47957			offset = accuIndex * stride + stride;
47958
47959		let currentWeight = this.cumulativeWeight;
47960
47961		if ( currentWeight === 0 ) {
47962
47963			// accuN := incoming * weight
47964
47965			for ( let i = 0; i !== stride; ++ i ) {
47966
47967				buffer[ offset + i ] = buffer[ i ];
47968
47969			}
47970
47971			currentWeight = weight;
47972
47973		} else {
47974
47975			// accuN := accuN + incoming * weight
47976
47977			currentWeight += weight;
47978			const mix = weight / currentWeight;
47979			this._mixBufferRegion( buffer, offset, 0, mix, stride );
47980
47981		}
47982
47983		this.cumulativeWeight = currentWeight;
47984
47985	}
47986
47987	// accumulate data in the 'incoming' region into 'add'
47988	accumulateAdditive( weight ) {
47989
47990		const buffer = this.buffer,
47991			stride = this.valueSize,
47992			offset = stride * this._addIndex;
47993
47994		if ( this.cumulativeWeightAdditive === 0 ) {
47995
47996			// add = identity
47997
47998			this._setIdentity();
47999
48000		}
48001
48002		// add := add + incoming * weight
48003
48004		this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
48005		this.cumulativeWeightAdditive += weight;
48006
48007	}
48008
48009	// apply the state of 'accu<i>' to the binding when accus differ
48010	apply( accuIndex ) {
48011
48012		const stride = this.valueSize,
48013			buffer = this.buffer,
48014			offset = accuIndex * stride + stride,
48015
48016			weight = this.cumulativeWeight,
48017			weightAdditive = this.cumulativeWeightAdditive,
48018
48019			binding = this.binding;
48020
48021		this.cumulativeWeight = 0;
48022		this.cumulativeWeightAdditive = 0;
48023
48024		if ( weight < 1 ) {
48025
48026			// accuN := accuN + original * ( 1 - cumulativeWeight )
48027
48028			const originalValueOffset = stride * this._origIndex;
48029
48030			this._mixBufferRegion(
48031				buffer, offset, originalValueOffset, 1 - weight, stride );
48032
48033		}
48034
48035		if ( weightAdditive > 0 ) {
48036
48037			// accuN := accuN + additive accuN
48038
48039			this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
48040
48041		}
48042
48043		for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
48044
48045			if ( buffer[ i ] !== buffer[ i + stride ] ) {
48046
48047				// value has changed -> update scene graph
48048
48049				binding.setValue( buffer, offset );
48050				break;
48051
48052			}
48053
48054		}
48055
48056	}
48057
48058	// remember the state of the bound property and copy it to both accus
48059	saveOriginalState() {
48060
48061		const binding = this.binding;
48062
48063		const buffer = this.buffer,
48064			stride = this.valueSize,
48065
48066			originalValueOffset = stride * this._origIndex;
48067
48068		binding.getValue( buffer, originalValueOffset );
48069
48070		// accu[0..1] := orig -- initially detect changes against the original
48071		for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
48072
48073			buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
48074
48075		}
48076
48077		// Add to identity for additive
48078		this._setIdentity();
48079
48080		this.cumulativeWeight = 0;
48081		this.cumulativeWeightAdditive = 0;
48082
48083	}
48084
48085	// apply the state previously taken via 'saveOriginalState' to the binding
48086	restoreOriginalState() {
48087
48088		const originalValueOffset = this.valueSize * 3;
48089		this.binding.setValue( this.buffer, originalValueOffset );
48090
48091	}
48092
48093	_setAdditiveIdentityNumeric() {
48094
48095		const startIndex = this._addIndex * this.valueSize;
48096		const endIndex = startIndex + this.valueSize;
48097
48098		for ( let i = startIndex; i < endIndex; i ++ ) {
48099
48100			this.buffer[ i ] = 0;
48101
48102		}
48103
48104	}
48105
48106	_setAdditiveIdentityQuaternion() {
48107
48108		this._setAdditiveIdentityNumeric();
48109		this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
48110
48111	}
48112
48113	_setAdditiveIdentityOther() {
48114
48115		const startIndex = this._origIndex * this.valueSize;
48116		const targetIndex = this._addIndex * this.valueSize;
48117
48118		for ( let i = 0; i < this.valueSize; i ++ ) {
48119
48120			this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
48121
48122		}
48123
48124	}
48125
48126
48127	// mix functions
48128
48129	_select( buffer, dstOffset, srcOffset, t, stride ) {
48130
48131		if ( t >= 0.5 ) {
48132
48133			for ( let i = 0; i !== stride; ++ i ) {
48134
48135				buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
48136
48137			}
48138
48139		}
48140
48141	}
48142
48143	_slerp( buffer, dstOffset, srcOffset, t ) {
48144
48145		Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
48146
48147	}
48148
48149	_slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48150
48151		const workOffset = this._workIndex * stride;
48152
48153		// Store result in intermediate buffer offset
48154		Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
48155
48156		// Slerp to the intermediate result
48157		Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
48158
48159	}
48160
48161	_lerp( buffer, dstOffset, srcOffset, t, stride ) {
48162
48163		const s = 1 - t;
48164
48165		for ( let i = 0; i !== stride; ++ i ) {
48166
48167			const j = dstOffset + i;
48168
48169			buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
48170
48171		}
48172
48173	}
48174
48175	_lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48176
48177		for ( let i = 0; i !== stride; ++ i ) {
48178
48179			const j = dstOffset + i;
48180
48181			buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
48182
48183		}
48184
48185	}
48186
48187}
48188
48189// Characters [].:/ are reserved for track binding syntax.
48190const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
48191const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
48192
48193// Attempts to allow node names from any language. ES5's `\w` regexp matches
48194// only latin characters, and the unicode \p{L} is not yet supported. So
48195// instead, we exclude reserved characters and match everything else.
48196const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
48197const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
48198
48199// Parent directories, delimited by '/' or ':'. Currently unused, but must
48200// be matched to parse the rest of the track name.
48201const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
48202
48203// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
48204const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
48205
48206// Object on target node, and accessor. May not contain reserved
48207// characters. Accessor may contain any character except closing bracket.
48208const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
48209
48210// Property and accessor. May not contain reserved characters. Accessor may
48211// contain any non-bracket characters.
48212const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
48213
48214const _trackRe = new RegExp( ''
48215	+ '^'
48216	+ _directoryRe
48217	+ _nodeRe
48218	+ _objectRe
48219	+ _propertyRe
48220	+ '$'
48221);
48222
48223const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ];
48224
48225class Composite {
48226
48227	constructor( targetGroup, path, optionalParsedPath ) {
48228
48229		const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
48230
48231		this._targetGroup = targetGroup;
48232		this._bindings = targetGroup.subscribe_( path, parsedPath );
48233
48234	}
48235
48236	getValue( array, offset ) {
48237
48238		this.bind(); // bind all binding
48239
48240		const firstValidIndex = this._targetGroup.nCachedObjects_,
48241			binding = this._bindings[ firstValidIndex ];
48242
48243		// and only call .getValue on the first
48244		if ( binding !== undefined ) binding.getValue( array, offset );
48245
48246	}
48247
48248	setValue( array, offset ) {
48249
48250		const bindings = this._bindings;
48251
48252		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48253
48254			bindings[ i ].setValue( array, offset );
48255
48256		}
48257
48258	}
48259
48260	bind() {
48261
48262		const bindings = this._bindings;
48263
48264		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48265
48266			bindings[ i ].bind();
48267
48268		}
48269
48270	}
48271
48272	unbind() {
48273
48274		const bindings = this._bindings;
48275
48276		for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48277
48278			bindings[ i ].unbind();
48279
48280		}
48281
48282	}
48283
48284}
48285
48286// Note: This class uses a State pattern on a per-method basis:
48287// 'bind' sets 'this.getValue' / 'setValue' and shadows the
48288// prototype version of these methods with one that represents
48289// the bound state. When the property is not found, the methods
48290// become no-ops.
48291class PropertyBinding {
48292
48293	constructor( rootNode, path, parsedPath ) {
48294
48295		this.path = path;
48296		this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
48297
48298		this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName );
48299
48300		this.rootNode = rootNode;
48301
48302		// initial state of these methods that calls 'bind'
48303		this.getValue = this._getValue_unbound;
48304		this.setValue = this._setValue_unbound;
48305
48306	}
48307
48308
48309	static create( root, path, parsedPath ) {
48310
48311		if ( ! ( root && root.isAnimationObjectGroup ) ) {
48312
48313			return new PropertyBinding( root, path, parsedPath );
48314
48315		} else {
48316
48317			return new PropertyBinding.Composite( root, path, parsedPath );
48318
48319		}
48320
48321	}
48322
48323	/**
48324	 * Replaces spaces with underscores and removes unsupported characters from
48325	 * node names, to ensure compatibility with parseTrackName().
48326	 *
48327	 * @param {string} name Node name to be sanitized.
48328	 * @return {string}
48329	 */
48330	static sanitizeNodeName( name ) {
48331
48332		return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
48333
48334	}
48335
48336	static parseTrackName( trackName ) {
48337
48338		const matches = _trackRe.exec( trackName );
48339
48340		if ( matches === null ) {
48341
48342			throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
48343
48344		}
48345
48346		const results = {
48347			// directoryName: matches[ 1 ], // (tschw) currently unused
48348			nodeName: matches[ 2 ],
48349			objectName: matches[ 3 ],
48350			objectIndex: matches[ 4 ],
48351			propertyName: matches[ 5 ], // required
48352			propertyIndex: matches[ 6 ]
48353		};
48354
48355		const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
48356
48357		if ( lastDot !== undefined && lastDot !== - 1 ) {
48358
48359			const objectName = results.nodeName.substring( lastDot + 1 );
48360
48361			// Object names must be checked against an allowlist. Otherwise, there
48362			// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
48363			// 'bar' could be the objectName, or part of a nodeName (which can
48364			// include '.' characters).
48365			if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
48366
48367				results.nodeName = results.nodeName.substring( 0, lastDot );
48368				results.objectName = objectName;
48369
48370			}
48371
48372		}
48373
48374		if ( results.propertyName === null || results.propertyName.length === 0 ) {
48375
48376			throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
48377
48378		}
48379
48380		return results;
48381
48382	}
48383
48384	static findNode( root, nodeName ) {
48385
48386		if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
48387
48388			return root;
48389
48390		}
48391
48392		// search into skeleton bones.
48393		if ( root.skeleton ) {
48394
48395			const bone = root.skeleton.getBoneByName( nodeName );
48396
48397			if ( bone !== undefined ) {
48398
48399				return bone;
48400
48401			}
48402
48403		}
48404
48405		// search into node subtree.
48406		if ( root.children ) {
48407
48408			const searchNodeSubtree = function ( children ) {
48409
48410				for ( let i = 0; i < children.length; i ++ ) {
48411
48412					const childNode = children[ i ];
48413
48414					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
48415
48416						return childNode;
48417
48418					}
48419
48420					const result = searchNodeSubtree( childNode.children );
48421
48422					if ( result ) return result;
48423
48424				}
48425
48426				return null;
48427
48428			};
48429
48430			const subTreeNode = searchNodeSubtree( root.children );
48431
48432			if ( subTreeNode ) {
48433
48434				return subTreeNode;
48435
48436			}
48437
48438		}
48439
48440		return null;
48441
48442	}
48443
48444	// these are used to "bind" a nonexistent property
48445	_getValue_unavailable() {}
48446	_setValue_unavailable() {}
48447
48448	// Getters
48449
48450	_getValue_direct( buffer, offset ) {
48451
48452		buffer[ offset ] = this.targetObject[ this.propertyName ];
48453
48454	}
48455
48456	_getValue_array( buffer, offset ) {
48457
48458		const source = this.resolvedProperty;
48459
48460		for ( let i = 0, n = source.length; i !== n; ++ i ) {
48461
48462			buffer[ offset ++ ] = source[ i ];
48463
48464		}
48465
48466	}
48467
48468	_getValue_arrayElement( buffer, offset ) {
48469
48470		buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
48471
48472	}
48473
48474	_getValue_toArray( buffer, offset ) {
48475
48476		this.resolvedProperty.toArray( buffer, offset );
48477
48478	}
48479
48480	// Direct
48481
48482	_setValue_direct( buffer, offset ) {
48483
48484		this.targetObject[ this.propertyName ] = buffer[ offset ];
48485
48486	}
48487
48488	_setValue_direct_setNeedsUpdate( buffer, offset ) {
48489
48490		this.targetObject[ this.propertyName ] = buffer[ offset ];
48491		this.targetObject.needsUpdate = true;
48492
48493	}
48494
48495	_setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
48496
48497		this.targetObject[ this.propertyName ] = buffer[ offset ];
48498		this.targetObject.matrixWorldNeedsUpdate = true;
48499
48500	}
48501
48502	// EntireArray
48503
48504	_setValue_array( buffer, offset ) {
48505
48506		const dest = this.resolvedProperty;
48507
48508		for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48509
48510			dest[ i ] = buffer[ offset ++ ];
48511
48512		}
48513
48514	}
48515
48516	_setValue_array_setNeedsUpdate( 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		this.targetObject.needsUpdate = true;
48527
48528	}
48529
vendor: 8,185 bytes, lines 48530-48885
48530	_setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
48531
48532		const dest = this.resolvedProperty;
48533
48534		for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48535
48536			dest[ i ] = buffer[ offset ++ ];
48537
48538		}
48539
48540		this.targetObject.matrixWorldNeedsUpdate = true;
48541
48542	}
48543
48544	// ArrayElement
48545
48546	_setValue_arrayElement( buffer, offset ) {
48547
48548		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48549
48550	}
48551
48552	_setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
48553
48554		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48555		this.targetObject.needsUpdate = true;
48556
48557	}
48558
48559	_setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
48560
48561		this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48562		this.targetObject.matrixWorldNeedsUpdate = true;
48563
48564	}
48565
48566	// HasToFromArray
48567
48568	_setValue_fromArray( buffer, offset ) {
48569
48570		this.resolvedProperty.fromArray( buffer, offset );
48571
48572	}
48573
48574	_setValue_fromArray_setNeedsUpdate( buffer, offset ) {
48575
48576		this.resolvedProperty.fromArray( buffer, offset );
48577		this.targetObject.needsUpdate = true;
48578
48579	}
48580
48581	_setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
48582
48583		this.resolvedProperty.fromArray( buffer, offset );
48584		this.targetObject.matrixWorldNeedsUpdate = true;
48585
48586	}
48587
48588	_getValue_unbound( targetArray, offset ) {
48589
48590		this.bind();
48591		this.getValue( targetArray, offset );
48592
48593	}
48594
48595	_setValue_unbound( sourceArray, offset ) {
48596
48597		this.bind();
48598		this.setValue( sourceArray, offset );
48599
48600	}
48601
48602	// create getter / setter pair for a property in the scene graph
48603	bind() {
48604
48605		let targetObject = this.node;
48606		const parsedPath = this.parsedPath;
48607
48608		const objectName = parsedPath.objectName;
48609		const propertyName = parsedPath.propertyName;
48610		let propertyIndex = parsedPath.propertyIndex;
48611
48612		if ( ! targetObject ) {
48613
48614			targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName );
48615
48616			this.node = targetObject;
48617
48618		}
48619
48620		// set fail state so we can just 'return' on error
48621		this.getValue = this._getValue_unavailable;
48622		this.setValue = this._setValue_unavailable;
48623
48624		// ensure there is a value node
48625		if ( ! targetObject ) {
48626
48627			console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' );
48628			return;
48629
48630		}
48631
48632		if ( objectName ) {
48633
48634			let objectIndex = parsedPath.objectIndex;
48635
48636			// special cases were we need to reach deeper into the hierarchy to get the face materials....
48637			switch ( objectName ) {
48638
48639				case 'materials':
48640
48641					if ( ! targetObject.material ) {
48642
48643						console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48644						return;
48645
48646					}
48647
48648					if ( ! targetObject.material.materials ) {
48649
48650						console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
48651						return;
48652
48653					}
48654
48655					targetObject = targetObject.material.materials;
48656
48657					break;
48658
48659				case 'bones':
48660
48661					if ( ! targetObject.skeleton ) {
48662
48663						console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
48664						return;
48665
48666					}
48667
48668					// potential future optimization: skip this if propertyIndex is already an integer
48669					// and convert the integer string to a true integer.
48670
48671					targetObject = targetObject.skeleton.bones;
48672
48673					// support resolving morphTarget names into indices.
48674					for ( let i = 0; i < targetObject.length; i ++ ) {
48675
48676						if ( targetObject[ i ].name === objectIndex ) {
48677
48678							objectIndex = i;
48679							break;
48680
48681						}
48682
48683					}
48684
48685					break;
48686
48687				case 'map':
48688
48689					if ( 'map' in targetObject ) {
48690
48691						targetObject = targetObject.map;
48692						break;
48693
48694					}
48695
48696					if ( ! targetObject.material ) {
48697
48698						console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48699						return;
48700
48701					}
48702
48703					if ( ! targetObject.material.map ) {
48704
48705						console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this );
48706						return;
48707
48708					}
48709
48710					targetObject = targetObject.material.map;
48711					break;
48712
48713				default:
48714
48715					if ( targetObject[ objectName ] === undefined ) {
48716
48717						console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
48718						return;
48719
48720					}
48721
48722					targetObject = targetObject[ objectName ];
48723
48724			}
48725
48726
48727			if ( objectIndex !== undefined ) {
48728
48729				if ( targetObject[ objectIndex ] === undefined ) {
48730
48731					console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
48732					return;
48733
48734				}
48735
48736				targetObject = targetObject[ objectIndex ];
48737
48738			}
48739
48740		}
48741
48742		// resolve property
48743		const nodeProperty = targetObject[ propertyName ];
48744
48745		if ( nodeProperty === undefined ) {
48746
48747			const nodeName = parsedPath.nodeName;
48748
48749			console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
48750				'.' + propertyName + ' but it wasn\'t found.', targetObject );
48751			return;
48752
48753		}
48754
48755		// determine versioning scheme
48756		let versioning = this.Versioning.None;
48757
48758		this.targetObject = targetObject;
48759
48760		if ( targetObject.needsUpdate !== undefined ) { // material
48761
48762			versioning = this.Versioning.NeedsUpdate;
48763
48764		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
48765
48766			versioning = this.Versioning.MatrixWorldNeedsUpdate;
48767
48768		}
48769
48770		// determine how the property gets bound
48771		let bindingType = this.BindingType.Direct;
48772
48773		if ( propertyIndex !== undefined ) {
48774
48775			// access a sub element of the property array (only primitives are supported right now)
48776
48777			if ( propertyName === 'morphTargetInfluences' ) {
48778
48779				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
48780
48781				// support resolving morphTarget names into indices.
48782				if ( ! targetObject.geometry ) {
48783
48784					console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
48785					return;
48786
48787				}
48788
48789				if ( ! targetObject.geometry.morphAttributes ) {
48790
48791					console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
48792					return;
48793
48794				}
48795
48796				if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
48797
48798					propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
48799
48800				}
48801
48802			}
48803
48804			bindingType = this.BindingType.ArrayElement;
48805
48806			this.resolvedProperty = nodeProperty;
48807			this.propertyIndex = propertyIndex;
48808
48809		} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
48810
48811			// must use copy for Object3D.Euler/Quaternion
48812
48813			bindingType = this.BindingType.HasFromToArray;
48814
48815			this.resolvedProperty = nodeProperty;
48816
48817		} else if ( Array.isArray( nodeProperty ) ) {
48818
48819			bindingType = this.BindingType.EntireArray;
48820
48821			this.resolvedProperty = nodeProperty;
48822
48823		} else {
48824
48825			this.propertyName = propertyName;
48826
48827		}
48828
48829		// select getter / setter
48830		this.getValue = this.GetterByBindingType[ bindingType ];
48831		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
48832
48833	}
48834
48835	unbind() {
48836
48837		this.node = null;
48838
48839		// back to the prototype version of getValue / setValue
48840		// note: avoiding to mutate the shape of 'this' via 'delete'
48841		this.getValue = this._getValue_unbound;
48842		this.setValue = this._setValue_unbound;
48843
48844	}
48845
48846}
48847
48848PropertyBinding.Composite = Composite;
48849
48850PropertyBinding.prototype.BindingType = {
48851	Direct: 0,
48852	EntireArray: 1,
48853	ArrayElement: 2,
48854	HasFromToArray: 3
48855};
48856
48857PropertyBinding.prototype.Versioning = {
48858	None: 0,
48859	NeedsUpdate: 1,
48860	MatrixWorldNeedsUpdate: 2
48861};
48862
48863PropertyBinding.prototype.GetterByBindingType = [
48864
48865	PropertyBinding.prototype._getValue_direct,
48866	PropertyBinding.prototype._getValue_array,
48867	PropertyBinding.prototype._getValue_arrayElement,
48868	PropertyBinding.prototype._getValue_toArray,
48869
48870];
48871
48872PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [
48873
48874	[
48875		// Direct
48876		PropertyBinding.prototype._setValue_direct,
48877		PropertyBinding.prototype._setValue_direct_setNeedsUpdate,
48878		PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,
48879
48880	], [
48881
48882		// EntireArray
48883
48884		PropertyBinding.prototype._setValue_array,
48885		PropertyBinding.prototype._setValue_array_setNeedsUpdate,
vendor: 4,282 bytes, lines 48886-49066
48886		PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,
48887
48888	], [
48889
48890		// ArrayElement
48891		PropertyBinding.prototype._setValue_arrayElement,
48892		PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,
48893		PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,
48894
48895	], [
48896
48897		// HasToFromArray
48898		PropertyBinding.prototype._setValue_fromArray,
48899		PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,
48900		PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,
48901
48902	]
48903
48904];
48905
48906/**
48907 *
48908 * A group of objects that receives a shared animation state.
48909 *
48910 * Usage:
48911 *
48912 *  - Add objects you would otherwise pass as 'root' to the
48913 *    constructor or the .clipAction method of AnimationMixer.
48914 *
48915 *  - Instead pass this object as 'root'.
48916 *
48917 *  - You can also add and remove objects later when the mixer
48918 *    is running.
48919 *
48920 * Note:
48921 *
48922 *    Objects of this class appear as one object to the mixer,
48923 *    so cache control of the individual objects must be done
48924 *    on the group.
48925 *
48926 * Limitation:
48927 *
48928 *  - The animated properties must be compatible among the
48929 *    all objects in the group.
48930 *
48931 *  - A single property can either be controlled through a
48932 *    target group or directly, but not both.
48933 */
48934
48935class AnimationObjectGroup {
48936
48937	constructor() {
48938
48939		this.isAnimationObjectGroup = true;
48940
48941		this.uuid = generateUUID();
48942
48943		// cached objects followed by the active ones
48944		this._objects = Array.prototype.slice.call( arguments );
48945
48946		this.nCachedObjects_ = 0; // threshold
48947		// note: read by PropertyBinding.Composite
48948
48949		const indices = {};
48950		this._indicesByUUID = indices; // for bookkeeping
48951
48952		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
48953
48954			indices[ arguments[ i ].uuid ] = i;
48955
48956		}
48957
48958		this._paths = []; // inside: string
48959		this._parsedPaths = []; // inside: { we don't care, here }
48960		this._bindings = []; // inside: Array< PropertyBinding >
48961		this._bindingsIndicesByPath = {}; // inside: indices in these arrays
48962
48963		const scope = this;
48964
48965		this.stats = {
48966
48967			objects: {
48968				get total() {
48969
48970					return scope._objects.length;
48971
48972				},
48973				get inUse() {
48974
48975					return this.total - scope.nCachedObjects_;
48976
48977				}
48978			},
48979			get bindingsPerObject() {
48980
48981				return scope._bindings.length;
48982
48983			}
48984
48985		};
48986
48987	}
48988
48989	add() {
48990
48991		const objects = this._objects,
48992			indicesByUUID = this._indicesByUUID,
48993			paths = this._paths,
48994			parsedPaths = this._parsedPaths,
48995			bindings = this._bindings,
48996			nBindings = bindings.length;
48997
48998		let knownObject = undefined,
48999			nObjects = objects.length,
49000			nCachedObjects = this.nCachedObjects_;
49001
49002		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49003
49004			const object = arguments[ i ],
49005				uuid = object.uuid;
49006			let index = indicesByUUID[ uuid ];
49007
49008			if ( index === undefined ) {
49009
49010				// unknown object -> add it to the ACTIVE region
49011
49012				index = nObjects ++;
49013				indicesByUUID[ uuid ] = index;
49014				objects.push( object );
49015
49016				// accounting is done, now do the same for all bindings
49017
49018				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49019
49020					bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
49021
49022				}
49023
49024			} else if ( index < nCachedObjects ) {
49025
49026				knownObject = objects[ index ];
49027
49028				// move existing object to the ACTIVE region
49029
49030				const firstActiveIndex = -- nCachedObjects,
49031					lastCachedObject = objects[ firstActiveIndex ];
49032
49033				indicesByUUID[ lastCachedObject.uuid ] = index;
49034				objects[ index ] = lastCachedObject;
49035
49036				indicesByUUID[ uuid ] = firstActiveIndex;
49037				objects[ firstActiveIndex ] = object;
49038
49039				// accounting is done, now do the same for all bindings
49040
49041				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49042
49043					const bindingsForPath = bindings[ j ],
49044						lastCached = bindingsForPath[ firstActiveIndex ];
49045
49046					let binding = bindingsForPath[ index ];
49047
49048					bindingsForPath[ index ] = lastCached;
49049
49050					if ( binding === undefined ) {
49051
49052						// since we do not bother to create new bindings
49053						// for objects that are cached, the binding may
49054						// or may not exist
49055
49056						binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
49057
49058					}
49059
49060					bindingsForPath[ firstActiveIndex ] = binding;
49061
49062				}
49063
49064			} else if ( objects[ index ] !== knownObject ) {
49065
49066				console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
vendor: 4,120 bytes, lines 49067-49233
49067					'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
49068
49069			} // else the object is already where we want it to be
49070
49071		} // for arguments
49072
49073		this.nCachedObjects_ = nCachedObjects;
49074
49075	}
49076
49077	remove() {
49078
49079		const objects = this._objects,
49080			indicesByUUID = this._indicesByUUID,
49081			bindings = this._bindings,
49082			nBindings = bindings.length;
49083
49084		let nCachedObjects = this.nCachedObjects_;
49085
49086		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49087
49088			const object = arguments[ i ],
49089				uuid = object.uuid,
49090				index = indicesByUUID[ uuid ];
49091
49092			if ( index !== undefined && index >= nCachedObjects ) {
49093
49094				// move existing object into the CACHED region
49095
49096				const lastCachedIndex = nCachedObjects ++,
49097					firstActiveObject = objects[ lastCachedIndex ];
49098
49099				indicesByUUID[ firstActiveObject.uuid ] = index;
49100				objects[ index ] = firstActiveObject;
49101
49102				indicesByUUID[ uuid ] = lastCachedIndex;
49103				objects[ lastCachedIndex ] = object;
49104
49105				// accounting is done, now do the same for all bindings
49106
49107				for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49108
49109					const bindingsForPath = bindings[ j ],
49110						firstActive = bindingsForPath[ lastCachedIndex ],
49111						binding = bindingsForPath[ index ];
49112
49113					bindingsForPath[ index ] = firstActive;
49114					bindingsForPath[ lastCachedIndex ] = binding;
49115
49116				}
49117
49118			}
49119
49120		} // for arguments
49121
49122		this.nCachedObjects_ = nCachedObjects;
49123
49124	}
49125
49126	// remove & forget
49127	uncache() {
49128
49129		const objects = this._objects,
49130			indicesByUUID = this._indicesByUUID,
49131			bindings = this._bindings,
49132			nBindings = bindings.length;
49133
49134		let nCachedObjects = this.nCachedObjects_,
49135			nObjects = objects.length;
49136
49137		for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49138
49139			const object = arguments[ i ],
49140				uuid = object.uuid,
49141				index = indicesByUUID[ uuid ];
49142
49143			if ( index !== undefined ) {
49144
49145				delete indicesByUUID[ uuid ];
49146
49147				if ( index < nCachedObjects ) {
49148
49149					// object is cached, shrink the CACHED region
49150
49151					const firstActiveIndex = -- nCachedObjects,
49152						lastCachedObject = objects[ firstActiveIndex ],
49153						lastIndex = -- nObjects,
49154						lastObject = objects[ lastIndex ];
49155
49156					// last cached object takes this object's place
49157					indicesByUUID[ lastCachedObject.uuid ] = index;
49158					objects[ index ] = lastCachedObject;
49159
49160					// last object goes to the activated slot and pop
49161					indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
49162					objects[ firstActiveIndex ] = lastObject;
49163					objects.pop();
49164
49165					// accounting is done, now do the same for all bindings
49166
49167					for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49168
49169						const bindingsForPath = bindings[ j ],
49170							lastCached = bindingsForPath[ firstActiveIndex ],
49171							last = bindingsForPath[ lastIndex ];
49172
49173						bindingsForPath[ index ] = lastCached;
49174						bindingsForPath[ firstActiveIndex ] = last;
49175						bindingsForPath.pop();
49176
49177					}
49178
49179				} else {
49180
49181					// object is active, just swap with the last and pop
49182
49183					const lastIndex = -- nObjects,
49184						lastObject = objects[ lastIndex ];
49185
49186					if ( lastIndex > 0 ) {
49187
49188						indicesByUUID[ lastObject.uuid ] = index;
49189
49190					}
49191
49192					objects[ index ] = lastObject;
49193					objects.pop();
49194
49195					// accounting is done, now do the same for all bindings
49196
49197					for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49198
49199						const bindingsForPath = bindings[ j ];
49200
49201						bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
49202						bindingsForPath.pop();
49203
49204					}
49205
49206				} // cached or active
49207
49208			} // if object is known
49209
49210		} // for arguments
49211
49212		this.nCachedObjects_ = nCachedObjects;
49213
49214	}
49215
49216	// Internal interface used by befriended PropertyBinding.Composite:
49217
49218	subscribe_( path, parsedPath ) {
49219
49220		// returns an array of bindings for the given path that is changed
49221		// according to the contained objects in the group
49222
49223		const indicesByPath = this._bindingsIndicesByPath;
49224		let index = indicesByPath[ path ];
49225		const bindings = this._bindings;
49226
49227		if ( index !== undefined ) return bindings[ index ];
49228
49229		const paths = this._paths,
49230			parsedPaths = this._parsedPaths,
49231			objects = this._objects,
49232			nObjects = objects.length,
49233			nCachedObjects = this.nCachedObjects_,
vendor: 7,613 bytes, lines 49234-49627
49234			bindingsForPath = new Array( nObjects );
49235
49236		index = bindings.length;
49237
49238		indicesByPath[ path ] = index;
49239
49240		paths.push( path );
49241		parsedPaths.push( parsedPath );
49242		bindings.push( bindingsForPath );
49243
49244		for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
49245
49246			const object = objects[ i ];
49247			bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
49248
49249		}
49250
49251		return bindingsForPath;
49252
49253	}
49254
49255	unsubscribe_( path ) {
49256
49257		// tells the group to forget about a property path and no longer
49258		// update the array previously obtained with 'subscribe_'
49259
49260		const indicesByPath = this._bindingsIndicesByPath,
49261			index = indicesByPath[ path ];
49262
49263		if ( index !== undefined ) {
49264
49265			const paths = this._paths,
49266				parsedPaths = this._parsedPaths,
49267				bindings = this._bindings,
49268				lastBindingsIndex = bindings.length - 1,
49269				lastBindings = bindings[ lastBindingsIndex ],
49270				lastBindingsPath = path[ lastBindingsIndex ];
49271
49272			indicesByPath[ lastBindingsPath ] = index;
49273
49274			bindings[ index ] = lastBindings;
49275			bindings.pop();
49276
49277			parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
49278			parsedPaths.pop();
49279
49280			paths[ index ] = paths[ lastBindingsIndex ];
49281			paths.pop();
49282
49283		}
49284
49285	}
49286
49287}
49288
49289class AnimationAction {
49290
49291	constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
49292
49293		this._mixer = mixer;
49294		this._clip = clip;
49295		this._localRoot = localRoot;
49296		this.blendMode = blendMode;
49297
49298		const tracks = clip.tracks,
49299			nTracks = tracks.length,
49300			interpolants = new Array( nTracks );
49301
49302		const interpolantSettings = {
49303			endingStart: ZeroCurvatureEnding,
49304			endingEnd: ZeroCurvatureEnding
49305		};
49306
49307		for ( let i = 0; i !== nTracks; ++ i ) {
49308
49309			const interpolant = tracks[ i ].createInterpolant( null );
49310			interpolants[ i ] = interpolant;
49311			interpolant.settings = interpolantSettings;
49312
49313		}
49314
49315		this._interpolantSettings = interpolantSettings;
49316
49317		this._interpolants = interpolants; // bound by the mixer
49318
49319		// inside: PropertyMixer (managed by the mixer)
49320		this._propertyBindings = new Array( nTracks );
49321
49322		this._cacheIndex = null; // for the memory manager
49323		this._byClipCacheIndex = null; // for the memory manager
49324
49325		this._timeScaleInterpolant = null;
49326		this._weightInterpolant = null;
49327
49328		this.loop = LoopRepeat;
49329		this._loopCount = - 1;
49330
49331		// global mixer time when the action is to be started
49332		// it's set back to 'null' upon start of the action
49333		this._startTime = null;
49334
49335		// scaled local time of the action
49336		// gets clamped or wrapped to 0..clip.duration according to loop
49337		this.time = 0;
49338
49339		this.timeScale = 1;
49340		this._effectiveTimeScale = 1;
49341
49342		this.weight = 1;
49343		this._effectiveWeight = 1;
49344
49345		this.repetitions = Infinity; // no. of repetitions when looping
49346
49347		this.paused = false; // true -> zero effective time scale
49348		this.enabled = true; // false -> zero effective weight
49349
49350		this.clampWhenFinished = false;// keep feeding the last frame?
49351
49352		this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
49353		this.zeroSlopeAtEnd = true;// clips for start, loop and end
49354
49355	}
49356
49357	// State & Scheduling
49358
49359	play() {
49360
49361		this._mixer._activateAction( this );
49362
49363		return this;
49364
49365	}
49366
49367	stop() {
49368
49369		this._mixer._deactivateAction( this );
49370
49371		return this.reset();
49372
49373	}
49374
49375	reset() {
49376
49377		this.paused = false;
49378		this.enabled = true;
49379
49380		this.time = 0; // restart clip
49381		this._loopCount = - 1;// forget previous loops
49382		this._startTime = null;// forget scheduling
49383
49384		return this.stopFading().stopWarping();
49385
49386	}
49387
49388	isRunning() {
49389
49390		return this.enabled && ! this.paused && this.timeScale !== 0 &&
49391			this._startTime === null && this._mixer._isActiveAction( this );
49392
49393	}
49394
49395	// return true when play has been called
49396	isScheduled() {
49397
49398		return this._mixer._isActiveAction( this );
49399
49400	}
49401
49402	startAt( time ) {
49403
49404		this._startTime = time;
49405
49406		return this;
49407
49408	}
49409
49410	setLoop( mode, repetitions ) {
49411
49412		this.loop = mode;
49413		this.repetitions = repetitions;
49414
49415		return this;
49416
49417	}
49418
49419	// Weight
49420
49421	// set the weight stopping any scheduled fading
49422	// although .enabled = false yields an effective weight of zero, this
49423	// method does *not* change .enabled, because it would be confusing
49424	setEffectiveWeight( weight ) {
49425
49426		this.weight = weight;
49427
49428		// note: same logic as when updated at runtime
49429		this._effectiveWeight = this.enabled ? weight : 0;
49430
49431		return this.stopFading();
49432
49433	}
49434
49435	// return the weight considering fading and .enabled
49436	getEffectiveWeight() {
49437
49438		return this._effectiveWeight;
49439
49440	}
49441
49442	fadeIn( duration ) {
49443
49444		return this._scheduleFading( duration, 0, 1 );
49445
49446	}
49447
49448	fadeOut( duration ) {
49449
49450		return this._scheduleFading( duration, 1, 0 );
49451
49452	}
49453
49454	crossFadeFrom( fadeOutAction, duration, warp ) {
49455
49456		fadeOutAction.fadeOut( duration );
49457		this.fadeIn( duration );
49458
49459		if ( warp ) {
49460
49461			const fadeInDuration = this._clip.duration,
49462				fadeOutDuration = fadeOutAction._clip.duration,
49463
49464				startEndRatio = fadeOutDuration / fadeInDuration,
49465				endStartRatio = fadeInDuration / fadeOutDuration;
49466
49467			fadeOutAction.warp( 1.0, startEndRatio, duration );
49468			this.warp( endStartRatio, 1.0, duration );
49469
49470		}
49471
49472		return this;
49473
49474	}
49475
49476	crossFadeTo( fadeInAction, duration, warp ) {
49477
49478		return fadeInAction.crossFadeFrom( this, duration, warp );
49479
49480	}
49481
49482	stopFading() {
49483
49484		const weightInterpolant = this._weightInterpolant;
49485
49486		if ( weightInterpolant !== null ) {
49487
49488			this._weightInterpolant = null;
49489			this._mixer._takeBackControlInterpolant( weightInterpolant );
49490
49491		}
49492
49493		return this;
49494
49495	}
49496
49497	// Time Scale Control
49498
49499	// set the time scale stopping any scheduled warping
49500	// although .paused = true yields an effective time scale of zero, this
49501	// method does *not* change .paused, because it would be confusing
49502	setEffectiveTimeScale( timeScale ) {
49503
49504		this.timeScale = timeScale;
49505		this._effectiveTimeScale = this.paused ? 0 : timeScale;
49506
49507		return this.stopWarping();
49508
49509	}
49510
49511	// return the time scale considering warping and .paused
49512	getEffectiveTimeScale() {
49513
49514		return this._effectiveTimeScale;
49515
49516	}
49517
49518	setDuration( duration ) {
49519
49520		this.timeScale = this._clip.duration / duration;
49521
49522		return this.stopWarping();
49523
49524	}
49525
49526	syncWith( action ) {
49527
49528		this.time = action.time;
49529		this.timeScale = action.timeScale;
49530
49531		return this.stopWarping();
49532
49533	}
49534
49535	halt( duration ) {
49536
49537		return this.warp( this._effectiveTimeScale, 0, duration );
49538
49539	}
49540
49541	warp( startTimeScale, endTimeScale, duration ) {
49542
49543		const mixer = this._mixer,
49544			now = mixer.time,
49545			timeScale = this.timeScale;
49546
49547		let interpolant = this._timeScaleInterpolant;
49548
49549		if ( interpolant === null ) {
49550
49551			interpolant = mixer._lendControlInterpolant();
49552			this._timeScaleInterpolant = interpolant;
49553
49554		}
49555
49556		const times = interpolant.parameterPositions,
49557			values = interpolant.sampleValues;
49558
49559		times[ 0 ] = now;
49560		times[ 1 ] = now + duration;
49561
49562		values[ 0 ] = startTimeScale / timeScale;
49563		values[ 1 ] = endTimeScale / timeScale;
49564
49565		return this;
49566
49567	}
49568
49569	stopWarping() {
49570
49571		const timeScaleInterpolant = this._timeScaleInterpolant;
49572
49573		if ( timeScaleInterpolant !== null ) {
49574
49575			this._timeScaleInterpolant = null;
49576			this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
49577
49578		}
49579
49580		return this;
49581
49582	}
49583
49584	// Object Accessors
49585
49586	getMixer() {
49587
49588		return this._mixer;
49589
49590	}
49591
49592	getClip() {
49593
49594		return this._clip;
49595
49596	}
49597
49598	getRoot() {
49599
49600		return this._localRoot || this._mixer._root;
49601
49602	}
49603
49604	// Interna
49605
49606	_update( time, deltaTime, timeDirection, accuIndex ) {
49607
49608		// called by the mixer
49609
49610		if ( ! this.enabled ) {
49611
49612			// call ._updateWeight() to update ._effectiveWeight
49613
49614			this._updateWeight( time );
49615			return;
49616
49617		}
49618
49619		const startTime = this._startTime;
49620
49621		if ( startTime !== null ) {
49622
49623			// check for scheduled start of action
49624
49625			const timeRunning = ( time - startTime ) * timeDirection;
49626			if ( timeRunning < 0 || timeDirection === 0 ) {
49627
vendor: 6,044 bytes, lines 49628-49986
49628				deltaTime = 0;
49629
49630			} else {
49631
49632
49633				this._startTime = null; // unschedule
49634				deltaTime = timeDirection * timeRunning;
49635
49636			}
49637
49638		}
49639
49640		// apply time scale and advance time
49641
49642		deltaTime *= this._updateTimeScale( time );
49643		const clipTime = this._updateTime( deltaTime );
49644
49645		// note: _updateTime may disable the action resulting in
49646		// an effective weight of 0
49647
49648		const weight = this._updateWeight( time );
49649
49650		if ( weight > 0 ) {
49651
49652			const interpolants = this._interpolants;
49653			const propertyMixers = this._propertyBindings;
49654
49655			switch ( this.blendMode ) {
49656
49657				case AdditiveAnimationBlendMode:
49658
49659					for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49660
49661						interpolants[ j ].evaluate( clipTime );
49662						propertyMixers[ j ].accumulateAdditive( weight );
49663
49664					}
49665
49666					break;
49667
49668				case NormalAnimationBlendMode:
49669				default:
49670
49671					for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49672
49673						interpolants[ j ].evaluate( clipTime );
49674						propertyMixers[ j ].accumulate( accuIndex, weight );
49675
49676					}
49677
49678			}
49679
49680		}
49681
49682	}
49683
49684	_updateWeight( time ) {
49685
49686		let weight = 0;
49687
49688		if ( this.enabled ) {
49689
49690			weight = this.weight;
49691			const interpolant = this._weightInterpolant;
49692
49693			if ( interpolant !== null ) {
49694
49695				const interpolantValue = interpolant.evaluate( time )[ 0 ];
49696
49697				weight *= interpolantValue;
49698
49699				if ( time > interpolant.parameterPositions[ 1 ] ) {
49700
49701					this.stopFading();
49702
49703					if ( interpolantValue === 0 ) {
49704
49705						// faded out, disable
49706						this.enabled = false;
49707
49708					}
49709
49710				}
49711
49712			}
49713
49714		}
49715
49716		this._effectiveWeight = weight;
49717		return weight;
49718
49719	}
49720
49721	_updateTimeScale( time ) {
49722
49723		let timeScale = 0;
49724
49725		if ( ! this.paused ) {
49726
49727			timeScale = this.timeScale;
49728
49729			const interpolant = this._timeScaleInterpolant;
49730
49731			if ( interpolant !== null ) {
49732
49733				const interpolantValue = interpolant.evaluate( time )[ 0 ];
49734
49735				timeScale *= interpolantValue;
49736
49737				if ( time > interpolant.parameterPositions[ 1 ] ) {
49738
49739					this.stopWarping();
49740
49741					if ( timeScale === 0 ) {
49742
49743						// motion has halted, pause
49744						this.paused = true;
49745
49746					} else {
49747
49748						// warp done - apply final time scale
49749						this.timeScale = timeScale;
49750
49751					}
49752
49753				}
49754
49755			}
49756
49757		}
49758
49759		this._effectiveTimeScale = timeScale;
49760		return timeScale;
49761
49762	}
49763
49764	_updateTime( deltaTime ) {
49765
49766		const duration = this._clip.duration;
49767		const loop = this.loop;
49768
49769		let time = this.time + deltaTime;
49770		let loopCount = this._loopCount;
49771
49772		const pingPong = ( loop === LoopPingPong );
49773
49774		if ( deltaTime === 0 ) {
49775
49776			if ( loopCount === - 1 ) return time;
49777
49778			return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
49779
49780		}
49781
49782		if ( loop === LoopOnce ) {
49783
49784			if ( loopCount === - 1 ) {
49785
49786				// just started
49787
49788				this._loopCount = 0;
49789				this._setEndings( true, true, false );
49790
49791			}
49792
49793			handle_stop: {
49794
49795				if ( time >= duration ) {
49796
49797					time = duration;
49798
49799				} else if ( time < 0 ) {
49800
49801					time = 0;
49802
49803				} else {
49804
49805					this.time = time;
49806
49807					break handle_stop;
49808
49809				}
49810
49811				if ( this.clampWhenFinished ) this.paused = true;
49812				else this.enabled = false;
49813
49814				this.time = time;
49815
49816				this._mixer.dispatchEvent( {
49817					type: 'finished', action: this,
49818					direction: deltaTime < 0 ? - 1 : 1
49819				} );
49820
49821			}
49822
49823		} else { // repetitive Repeat or PingPong
49824
49825			if ( loopCount === - 1 ) {
49826
49827				// just started
49828
49829				if ( deltaTime >= 0 ) {
49830
49831					loopCount = 0;
49832
49833					this._setEndings( true, this.repetitions === 0, pingPong );
49834
49835				} else {
49836
49837					// when looping in reverse direction, the initial
49838					// transition through zero counts as a repetition,
49839					// so leave loopCount at -1
49840
49841					this._setEndings( this.repetitions === 0, true, pingPong );
49842
49843				}
49844
49845			}
49846
49847			if ( time >= duration || time < 0 ) {
49848
49849				// wrap around
49850
49851				const loopDelta = Math.floor( time / duration ); // signed
49852				time -= duration * loopDelta;
49853
49854				loopCount += Math.abs( loopDelta );
49855
49856				const pending = this.repetitions - loopCount;
49857
49858				if ( pending <= 0 ) {
49859
49860					// have to stop (switch state, clamp time, fire event)
49861
49862					if ( this.clampWhenFinished ) this.paused = true;
49863					else this.enabled = false;
49864
49865					time = deltaTime > 0 ? duration : 0;
49866
49867					this.time = time;
49868
49869					this._mixer.dispatchEvent( {
49870						type: 'finished', action: this,
49871						direction: deltaTime > 0 ? 1 : - 1
49872					} );
49873
49874				} else {
49875
49876					// keep running
49877
49878					if ( pending === 1 ) {
49879
49880						// entering the last round
49881
49882						const atStart = deltaTime < 0;
49883						this._setEndings( atStart, ! atStart, pingPong );
49884
49885					} else {
49886
49887						this._setEndings( false, false, pingPong );
49888
49889					}
49890
49891					this._loopCount = loopCount;
49892
49893					this.time = time;
49894
49895					this._mixer.dispatchEvent( {
49896						type: 'loop', action: this, loopDelta: loopDelta
49897					} );
49898
49899				}
49900
49901			} else {
49902
49903				this.time = time;
49904
49905			}
49906
49907			if ( pingPong && ( loopCount & 1 ) === 1 ) {
49908
49909				// invert time for the "pong round"
49910
49911				return duration - time;
49912
49913			}
49914
49915		}
49916
49917		return time;
49918
49919	}
49920
49921	_setEndings( atStart, atEnd, pingPong ) {
49922
49923		const settings = this._interpolantSettings;
49924
49925		if ( pingPong ) {
49926
49927			settings.endingStart = ZeroSlopeEnding;
49928			settings.endingEnd = ZeroSlopeEnding;
49929
49930		} else {
49931
49932			// assuming for LoopOnce atStart == atEnd == true
49933
49934			if ( atStart ) {
49935
49936				settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
49937
49938			} else {
49939
49940				settings.endingStart = WrapAroundEnding;
49941
49942			}
49943
49944			if ( atEnd ) {
49945
49946				settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
49947
49948			} else {
49949
49950				settings.endingEnd 	 = WrapAroundEnding;
49951
49952			}
49953
49954		}
49955
49956	}
49957
49958	_scheduleFading( duration, weightNow, weightThen ) {
49959
49960		const mixer = this._mixer, now = mixer.time;
49961		let interpolant = this._weightInterpolant;
49962
49963		if ( interpolant === null ) {
49964
49965			interpolant = mixer._lendControlInterpolant();
49966			this._weightInterpolant = interpolant;
49967
49968		}
49969
49970		const times = interpolant.parameterPositions,
49971			values = interpolant.sampleValues;
49972
49973		times[ 0 ] = now;
49974		values[ 0 ] = weightNow;
49975		times[ 1 ] = now + duration;
49976		values[ 1 ] = weightThen;
49977
49978		return this;
49979
49980	}
49981
49982}
49983
49984const _controlInterpolantsResultBuffer = new Float32Array( 1 );
49985
49986
vendor: 13,381 bytes, lines 49987-50627
49987class AnimationMixer extends EventDispatcher {
49988
49989	constructor( root ) {
49990
49991		super();
49992
49993		this._root = root;
49994		this._initMemoryManager();
49995		this._accuIndex = 0;
49996		this.time = 0;
49997		this.timeScale = 1.0;
49998
49999	}
50000
50001	_bindAction( action, prototypeAction ) {
50002
50003		const root = action._localRoot || this._root,
50004			tracks = action._clip.tracks,
50005			nTracks = tracks.length,
50006			bindings = action._propertyBindings,
50007			interpolants = action._interpolants,
50008			rootUuid = root.uuid,
50009			bindingsByRoot = this._bindingsByRootAndName;
50010
50011		let bindingsByName = bindingsByRoot[ rootUuid ];
50012
50013		if ( bindingsByName === undefined ) {
50014
50015			bindingsByName = {};
50016			bindingsByRoot[ rootUuid ] = bindingsByName;
50017
50018		}
50019
50020		for ( let i = 0; i !== nTracks; ++ i ) {
50021
50022			const track = tracks[ i ],
50023				trackName = track.name;
50024
50025			let binding = bindingsByName[ trackName ];
50026
50027			if ( binding !== undefined ) {
50028
50029				++ binding.referenceCount;
50030				bindings[ i ] = binding;
50031
50032			} else {
50033
50034				binding = bindings[ i ];
50035
50036				if ( binding !== undefined ) {
50037
50038					// existing binding, make sure the cache knows
50039
50040					if ( binding._cacheIndex === null ) {
50041
50042						++ binding.referenceCount;
50043						this._addInactiveBinding( binding, rootUuid, trackName );
50044
50045					}
50046
50047					continue;
50048
50049				}
50050
50051				const path = prototypeAction && prototypeAction.
50052					_propertyBindings[ i ].binding.parsedPath;
50053
50054				binding = new PropertyMixer(
50055					PropertyBinding.create( root, trackName, path ),
50056					track.ValueTypeName, track.getValueSize() );
50057
50058				++ binding.referenceCount;
50059				this._addInactiveBinding( binding, rootUuid, trackName );
50060
50061				bindings[ i ] = binding;
50062
50063			}
50064
50065			interpolants[ i ].resultBuffer = binding.buffer;
50066
50067		}
50068
50069	}
50070
50071	_activateAction( action ) {
50072
50073		if ( ! this._isActiveAction( action ) ) {
50074
50075			if ( action._cacheIndex === null ) {
50076
50077				// this action has been forgotten by the cache, but the user
50078				// appears to be still using it -> rebind
50079
50080				const rootUuid = ( action._localRoot || this._root ).uuid,
50081					clipUuid = action._clip.uuid,
50082					actionsForClip = this._actionsByClip[ clipUuid ];
50083
50084				this._bindAction( action,
50085					actionsForClip && actionsForClip.knownActions[ 0 ] );
50086
50087				this._addInactiveAction( action, clipUuid, rootUuid );
50088
50089			}
50090
50091			const bindings = action._propertyBindings;
50092
50093			// increment reference counts / sort out state
50094			for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50095
50096				const binding = bindings[ i ];
50097
50098				if ( binding.useCount ++ === 0 ) {
50099
50100					this._lendBinding( binding );
50101					binding.saveOriginalState();
50102
50103				}
50104
50105			}
50106
50107			this._lendAction( action );
50108
50109		}
50110
50111	}
50112
50113	_deactivateAction( action ) {
50114
50115		if ( this._isActiveAction( action ) ) {
50116
50117			const bindings = action._propertyBindings;
50118
50119			// decrement reference counts / sort out state
50120			for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50121
50122				const binding = bindings[ i ];
50123
50124				if ( -- binding.useCount === 0 ) {
50125
50126					binding.restoreOriginalState();
50127					this._takeBackBinding( binding );
50128
50129				}
50130
50131			}
50132
50133			this._takeBackAction( action );
50134
50135		}
50136
50137	}
50138
50139	// Memory manager
50140
50141	_initMemoryManager() {
50142
50143		this._actions = []; // 'nActiveActions' followed by inactive ones
50144		this._nActiveActions = 0;
50145
50146		this._actionsByClip = {};
50147		// inside:
50148		// {
50149		// 	knownActions: Array< AnimationAction > - used as prototypes
50150		// 	actionByRoot: AnimationAction - lookup
50151		// }
50152
50153
50154		this._bindings = []; // 'nActiveBindings' followed by inactive ones
50155		this._nActiveBindings = 0;
50156
50157		this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
50158
50159
50160		this._controlInterpolants = []; // same game as above
50161		this._nActiveControlInterpolants = 0;
50162
50163		const scope = this;
50164
50165		this.stats = {
50166
50167			actions: {
50168				get total() {
50169
50170					return scope._actions.length;
50171
50172				},
50173				get inUse() {
50174
50175					return scope._nActiveActions;
50176
50177				}
50178			},
50179			bindings: {
50180				get total() {
50181
50182					return scope._bindings.length;
50183
50184				},
50185				get inUse() {
50186
50187					return scope._nActiveBindings;
50188
50189				}
50190			},
50191			controlInterpolants: {
50192				get total() {
50193
50194					return scope._controlInterpolants.length;
50195
50196				},
50197				get inUse() {
50198
50199					return scope._nActiveControlInterpolants;
50200
50201				}
50202			}
50203
50204		};
50205
50206	}
50207
50208	// Memory management for AnimationAction objects
50209
50210	_isActiveAction( action ) {
50211
50212		const index = action._cacheIndex;
50213		return index !== null && index < this._nActiveActions;
50214
50215	}
50216
50217	_addInactiveAction( action, clipUuid, rootUuid ) {
50218
50219		const actions = this._actions,
50220			actionsByClip = this._actionsByClip;
50221
50222		let actionsForClip = actionsByClip[ clipUuid ];
50223
50224		if ( actionsForClip === undefined ) {
50225
50226			actionsForClip = {
50227
50228				knownActions: [ action ],
50229				actionByRoot: {}
50230
50231			};
50232
50233			action._byClipCacheIndex = 0;
50234
50235			actionsByClip[ clipUuid ] = actionsForClip;
50236
50237		} else {
50238
50239			const knownActions = actionsForClip.knownActions;
50240
50241			action._byClipCacheIndex = knownActions.length;
50242			knownActions.push( action );
50243
50244		}
50245
50246		action._cacheIndex = actions.length;
50247		actions.push( action );
50248
50249		actionsForClip.actionByRoot[ rootUuid ] = action;
50250
50251	}
50252
50253	_removeInactiveAction( action ) {
50254
50255		const actions = this._actions,
50256			lastInactiveAction = actions[ actions.length - 1 ],
50257			cacheIndex = action._cacheIndex;
50258
50259		lastInactiveAction._cacheIndex = cacheIndex;
50260		actions[ cacheIndex ] = lastInactiveAction;
50261		actions.pop();
50262
50263		action._cacheIndex = null;
50264
50265
50266		const clipUuid = action._clip.uuid,
50267			actionsByClip = this._actionsByClip,
50268			actionsForClip = actionsByClip[ clipUuid ],
50269			knownActionsForClip = actionsForClip.knownActions,
50270
50271			lastKnownAction =
50272				knownActionsForClip[ knownActionsForClip.length - 1 ],
50273
50274			byClipCacheIndex = action._byClipCacheIndex;
50275
50276		lastKnownAction._byClipCacheIndex = byClipCacheIndex;
50277		knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
50278		knownActionsForClip.pop();
50279
50280		action._byClipCacheIndex = null;
50281
50282
50283		const actionByRoot = actionsForClip.actionByRoot,
50284			rootUuid = ( action._localRoot || this._root ).uuid;
50285
50286		delete actionByRoot[ rootUuid ];
50287
50288		if ( knownActionsForClip.length === 0 ) {
50289
50290			delete actionsByClip[ clipUuid ];
50291
50292		}
50293
50294		this._removeInactiveBindingsForAction( action );
50295
50296	}
50297
50298	_removeInactiveBindingsForAction( action ) {
50299
50300		const bindings = action._propertyBindings;
50301
50302		for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50303
50304			const binding = bindings[ i ];
50305
50306			if ( -- binding.referenceCount === 0 ) {
50307
50308				this._removeInactiveBinding( binding );
50309
50310			}
50311
50312		}
50313
50314	}
50315
50316	_lendAction( action ) {
50317
50318		// [ active actions |  inactive actions  ]
50319		// [  active actions >| inactive actions ]
50320		//                 s        a
50321		//                  <-swap->
50322		//                 a        s
50323
50324		const actions = this._actions,
50325			prevIndex = action._cacheIndex,
50326
50327			lastActiveIndex = this._nActiveActions ++,
50328
50329			firstInactiveAction = actions[ lastActiveIndex ];
50330
50331		action._cacheIndex = lastActiveIndex;
50332		actions[ lastActiveIndex ] = action;
50333
50334		firstInactiveAction._cacheIndex = prevIndex;
50335		actions[ prevIndex ] = firstInactiveAction;
50336
50337	}
50338
50339	_takeBackAction( action ) {
50340
50341		// [  active actions  | inactive actions ]
50342		// [ active actions |< inactive actions  ]
50343		//        a        s
50344		//         <-swap->
50345		//        s        a
50346
50347		const actions = this._actions,
50348			prevIndex = action._cacheIndex,
50349
50350			firstInactiveIndex = -- this._nActiveActions,
50351
50352			lastActiveAction = actions[ firstInactiveIndex ];
50353
50354		action._cacheIndex = firstInactiveIndex;
50355		actions[ firstInactiveIndex ] = action;
50356
50357		lastActiveAction._cacheIndex = prevIndex;
50358		actions[ prevIndex ] = lastActiveAction;
50359
50360	}
50361
50362	// Memory management for PropertyMixer objects
50363
50364	_addInactiveBinding( binding, rootUuid, trackName ) {
50365
50366		const bindingsByRoot = this._bindingsByRootAndName,
50367			bindings = this._bindings;
50368
50369		let bindingByName = bindingsByRoot[ rootUuid ];
50370
50371		if ( bindingByName === undefined ) {
50372
50373			bindingByName = {};
50374			bindingsByRoot[ rootUuid ] = bindingByName;
50375
50376		}
50377
50378		bindingByName[ trackName ] = binding;
50379
50380		binding._cacheIndex = bindings.length;
50381		bindings.push( binding );
50382
50383	}
50384
50385	_removeInactiveBinding( binding ) {
50386
50387		const bindings = this._bindings,
50388			propBinding = binding.binding,
50389			rootUuid = propBinding.rootNode.uuid,
50390			trackName = propBinding.path,
50391			bindingsByRoot = this._bindingsByRootAndName,
50392			bindingByName = bindingsByRoot[ rootUuid ],
50393
50394			lastInactiveBinding = bindings[ bindings.length - 1 ],
50395			cacheIndex = binding._cacheIndex;
50396
50397		lastInactiveBinding._cacheIndex = cacheIndex;
50398		bindings[ cacheIndex ] = lastInactiveBinding;
50399		bindings.pop();
50400
50401		delete bindingByName[ trackName ];
50402
50403		if ( Object.keys( bindingByName ).length === 0 ) {
50404
50405			delete bindingsByRoot[ rootUuid ];
50406
50407		}
50408
50409	}
50410
50411	_lendBinding( binding ) {
50412
50413		const bindings = this._bindings,
50414			prevIndex = binding._cacheIndex,
50415
50416			lastActiveIndex = this._nActiveBindings ++,
50417
50418			firstInactiveBinding = bindings[ lastActiveIndex ];
50419
50420		binding._cacheIndex = lastActiveIndex;
50421		bindings[ lastActiveIndex ] = binding;
50422
50423		firstInactiveBinding._cacheIndex = prevIndex;
50424		bindings[ prevIndex ] = firstInactiveBinding;
50425
50426	}
50427
50428	_takeBackBinding( binding ) {
50429
50430		const bindings = this._bindings,
50431			prevIndex = binding._cacheIndex,
50432
50433			firstInactiveIndex = -- this._nActiveBindings,
50434
50435			lastActiveBinding = bindings[ firstInactiveIndex ];
50436
50437		binding._cacheIndex = firstInactiveIndex;
50438		bindings[ firstInactiveIndex ] = binding;
50439
50440		lastActiveBinding._cacheIndex = prevIndex;
50441		bindings[ prevIndex ] = lastActiveBinding;
50442
50443	}
50444
50445
50446	// Memory management of Interpolants for weight and time scale
50447
50448	_lendControlInterpolant() {
50449
50450		const interpolants = this._controlInterpolants,
50451			lastActiveIndex = this._nActiveControlInterpolants ++;
50452
50453		let interpolant = interpolants[ lastActiveIndex ];
50454
50455		if ( interpolant === undefined ) {
50456
50457			interpolant = new LinearInterpolant(
50458				new Float32Array( 2 ), new Float32Array( 2 ),
50459				1, _controlInterpolantsResultBuffer );
50460
50461			interpolant.__cacheIndex = lastActiveIndex;
50462			interpolants[ lastActiveIndex ] = interpolant;
50463
50464		}
50465
50466		return interpolant;
50467
50468	}
50469
50470	_takeBackControlInterpolant( interpolant ) {
50471
50472		const interpolants = this._controlInterpolants,
50473			prevIndex = interpolant.__cacheIndex,
50474
50475			firstInactiveIndex = -- this._nActiveControlInterpolants,
50476
50477			lastActiveInterpolant = interpolants[ firstInactiveIndex ];
50478
50479		interpolant.__cacheIndex = firstInactiveIndex;
50480		interpolants[ firstInactiveIndex ] = interpolant;
50481
50482		lastActiveInterpolant.__cacheIndex = prevIndex;
50483		interpolants[ prevIndex ] = lastActiveInterpolant;
50484
50485	}
50486
50487	// return an action for a clip optionally using a custom root target
50488	// object (this method allocates a lot of dynamic memory in case a
50489	// previously unknown clip/root combination is specified)
50490	clipAction( clip, optionalRoot, blendMode ) {
50491
50492		const root = optionalRoot || this._root,
50493			rootUuid = root.uuid;
50494
50495		let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
50496
50497		const clipUuid = clipObject !== null ? clipObject.uuid : clip;
50498
50499		const actionsForClip = this._actionsByClip[ clipUuid ];
50500		let prototypeAction = null;
50501
50502		if ( blendMode === undefined ) {
50503
50504			if ( clipObject !== null ) {
50505
50506				blendMode = clipObject.blendMode;
50507
50508			} else {
50509
50510				blendMode = NormalAnimationBlendMode;
50511
50512			}
50513
50514		}
50515
50516		if ( actionsForClip !== undefined ) {
50517
50518			const existingAction = actionsForClip.actionByRoot[ rootUuid ];
50519
50520			if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
50521
50522				return existingAction;
50523
50524			}
50525
50526			// we know the clip, so we don't have to parse all
50527			// the bindings again but can just copy
50528			prototypeAction = actionsForClip.knownActions[ 0 ];
50529
50530			// also, take the clip from the prototype action
50531			if ( clipObject === null )
50532				clipObject = prototypeAction._clip;
50533
50534		}
50535
50536		// clip must be known when specified via string
50537		if ( clipObject === null ) return null;
50538
50539		// allocate all resources required to run it
50540		const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
50541
50542		this._bindAction( newAction, prototypeAction );
50543
50544		// and make the action known to the memory manager
50545		this._addInactiveAction( newAction, clipUuid, rootUuid );
50546
50547		return newAction;
50548
50549	}
50550
50551	// get an existing action
50552	existingAction( clip, optionalRoot ) {
50553
50554		const root = optionalRoot || this._root,
50555			rootUuid = root.uuid,
50556
50557			clipObject = typeof clip === 'string' ?
50558				AnimationClip.findByName( root, clip ) : clip,
50559
50560			clipUuid = clipObject ? clipObject.uuid : clip,
50561
50562			actionsForClip = this._actionsByClip[ clipUuid ];
50563
50564		if ( actionsForClip !== undefined ) {
50565
50566			return actionsForClip.actionByRoot[ rootUuid ] || null;
50567
50568		}
50569
50570		return null;
50571
50572	}
50573
50574	// deactivates all previously scheduled actions
50575	stopAllAction() {
50576
50577		const actions = this._actions,
50578			nActions = this._nActiveActions;
50579
50580		for ( let i = nActions - 1; i >= 0; -- i ) {
50581
50582			actions[ i ].stop();
50583
50584		}
50585
50586		return this;
50587
50588	}
50589
50590	// advance the time and update apply the animation
50591	update( deltaTime ) {
50592
50593		deltaTime *= this.timeScale;
50594
50595		const actions = this._actions,
50596			nActions = this._nActiveActions,
50597
50598			time = this.time += deltaTime,
50599			timeDirection = Math.sign( deltaTime ),
50600
50601			accuIndex = this._accuIndex ^= 1;
50602
50603		// run active actions
50604
50605		for ( let i = 0; i !== nActions; ++ i ) {
50606
50607			const action = actions[ i ];
50608
50609			action._update( time, deltaTime, timeDirection, accuIndex );
50610
50611		}
50612
50613		// update scene graph
50614
50615		const bindings = this._bindings,
50616			nBindings = this._nActiveBindings;
50617
50618		for ( let i = 0; i !== nBindings; ++ i ) {
50619
50620			bindings[ i ].apply( accuIndex );
50621
50622		}
50623
50624		return this;
50625
50626	}
50627
vendor: 2,763 bytes, lines 50628-50761
50628	// Allows you to seek to a specific time in an animation.
50629	setTime( timeInSeconds ) {
50630
50631		this.time = 0; // Zero out time attribute for AnimationMixer object;
50632		for ( let i = 0; i < this._actions.length; i ++ ) {
50633
50634			this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
50635
50636		}
50637
50638		return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
50639
50640	}
50641
50642	// return this mixer's root target object
50643	getRoot() {
50644
50645		return this._root;
50646
50647	}
50648
50649	// free all resources specific to a particular clip
50650	uncacheClip( clip ) {
50651
50652		const actions = this._actions,
50653			clipUuid = clip.uuid,
50654			actionsByClip = this._actionsByClip,
50655			actionsForClip = actionsByClip[ clipUuid ];
50656
50657		if ( actionsForClip !== undefined ) {
50658
50659			// note: just calling _removeInactiveAction would mess up the
50660			// iteration state and also require updating the state we can
50661			// just throw away
50662
50663			const actionsToRemove = actionsForClip.knownActions;
50664
50665			for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
50666
50667				const action = actionsToRemove[ i ];
50668
50669				this._deactivateAction( action );
50670
50671				const cacheIndex = action._cacheIndex,
50672					lastInactiveAction = actions[ actions.length - 1 ];
50673
50674				action._cacheIndex = null;
50675				action._byClipCacheIndex = null;
50676
50677				lastInactiveAction._cacheIndex = cacheIndex;
50678				actions[ cacheIndex ] = lastInactiveAction;
50679				actions.pop();
50680
50681				this._removeInactiveBindingsForAction( action );
50682
50683			}
50684
50685			delete actionsByClip[ clipUuid ];
50686
50687		}
50688
50689	}
50690
50691	// free all resources specific to a particular root target object
50692	uncacheRoot( root ) {
50693
50694		const rootUuid = root.uuid,
50695			actionsByClip = this._actionsByClip;
50696
50697		for ( const clipUuid in actionsByClip ) {
50698
50699			const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
50700				action = actionByRoot[ rootUuid ];
50701
50702			if ( action !== undefined ) {
50703
50704				this._deactivateAction( action );
50705				this._removeInactiveAction( action );
50706
50707			}
50708
50709		}
50710
50711		const bindingsByRoot = this._bindingsByRootAndName,
50712			bindingByName = bindingsByRoot[ rootUuid ];
50713
50714		if ( bindingByName !== undefined ) {
50715
50716			for ( const trackName in bindingByName ) {
50717
50718				const binding = bindingByName[ trackName ];
50719				binding.restoreOriginalState();
50720				this._removeInactiveBinding( binding );
50721
50722			}
50723
50724		}
50725
50726	}
50727
50728	// remove a targeted clip from the cache
50729	uncacheAction( clip, optionalRoot ) {
50730
50731		const action = this.existingAction( clip, optionalRoot );
50732
50733		if ( action !== null ) {
50734
50735			this._deactivateAction( action );
50736			this._removeInactiveAction( action );
50737
50738		}
50739
50740	}
50741
50742}
50743
50744class Uniform {
50745
50746	constructor( value ) {
50747
50748		this.value = value;
50749
50750	}
50751
50752	clone() {
50753
50754		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
50755
50756	}
50757
50758}
50759
50760let _id = 0;
50761
vendor: 4,926 bytes, lines 50762-51073
50762class UniformsGroup extends EventDispatcher {
50763
50764	constructor() {
50765
50766		super();
50767
50768		this.isUniformsGroup = true;
50769
50770		Object.defineProperty( this, 'id', { value: _id ++ } );
50771
50772		this.name = '';
50773
50774		this.usage = StaticDrawUsage;
50775		this.uniforms = [];
50776
50777	}
50778
50779	add( uniform ) {
50780
50781		this.uniforms.push( uniform );
50782
50783		return this;
50784
50785	}
50786
50787	remove( uniform ) {
50788
50789		const index = this.uniforms.indexOf( uniform );
50790
50791		if ( index !== - 1 ) this.uniforms.splice( index, 1 );
50792
50793		return this;
50794
50795	}
50796
50797	setName( name ) {
50798
50799		this.name = name;
50800
50801		return this;
50802
50803	}
50804
50805	setUsage( value ) {
50806
50807		this.usage = value;
50808
50809		return this;
50810
50811	}
50812
50813	dispose() {
50814
50815		this.dispatchEvent( { type: 'dispose' } );
50816
50817		return this;
50818
50819	}
50820
50821	copy( source ) {
50822
50823		this.name = source.name;
50824		this.usage = source.usage;
50825
50826		const uniformsSource = source.uniforms;
50827
50828		this.uniforms.length = 0;
50829
50830		for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) {
50831
50832			const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ];
50833
50834			for ( let j = 0; j < uniforms.length; j ++ ) {
50835
50836				this.uniforms.push( uniforms[ j ].clone() );
50837
50838			}
50839
50840		}
50841
50842		return this;
50843
50844	}
50845
50846	clone() {
50847
50848		return new this.constructor().copy( this );
50849
50850	}
50851
50852}
50853
50854class InstancedInterleavedBuffer extends InterleavedBuffer {
50855
50856	constructor( array, stride, meshPerAttribute = 1 ) {
50857
50858		super( array, stride );
50859
50860		this.isInstancedInterleavedBuffer = true;
50861
50862		this.meshPerAttribute = meshPerAttribute;
50863
50864	}
50865
50866	copy( source ) {
50867
50868		super.copy( source );
50869
50870		this.meshPerAttribute = source.meshPerAttribute;
50871
50872		return this;
50873
50874	}
50875
50876	clone( data ) {
50877
50878		const ib = super.clone( data );
50879
50880		ib.meshPerAttribute = this.meshPerAttribute;
50881
50882		return ib;
50883
50884	}
50885
50886	toJSON( data ) {
50887
50888		const json = super.toJSON( data );
50889
50890		json.isInstancedInterleavedBuffer = true;
50891		json.meshPerAttribute = this.meshPerAttribute;
50892
50893		return json;
50894
50895	}
50896
50897}
50898
50899class GLBufferAttribute {
50900
50901	constructor( buffer, type, itemSize, elementSize, count ) {
50902
50903		this.isGLBufferAttribute = true;
50904
50905		this.name = '';
50906
50907		this.buffer = buffer;
50908		this.type = type;
50909		this.itemSize = itemSize;
50910		this.elementSize = elementSize;
50911		this.count = count;
50912
50913		this.version = 0;
50914
50915	}
50916
50917	set needsUpdate( value ) {
50918
50919		if ( value === true ) this.version ++;
50920
50921	}
50922
50923	setBuffer( buffer ) {
50924
50925		this.buffer = buffer;
50926
50927		return this;
50928
50929	}
50930
50931	setType( type, elementSize ) {
50932
50933		this.type = type;
50934		this.elementSize = elementSize;
50935
50936		return this;
50937
50938	}
50939
50940	setItemSize( itemSize ) {
50941
50942		this.itemSize = itemSize;
50943
50944		return this;
50945
50946	}
50947
50948	setCount( count ) {
50949
50950		this.count = count;
50951
50952		return this;
50953
50954	}
50955
50956}
50957
50958class Raycaster {
50959
50960	constructor( origin, direction, near = 0, far = Infinity ) {
50961
50962		this.ray = new Ray( origin, direction );
50963		// direction is assumed to be normalized (for accurate distance calculations)
50964
50965		this.near = near;
50966		this.far = far;
50967		this.camera = null;
50968		this.layers = new Layers();
50969
50970		this.params = {
50971			Mesh: {},
50972			Line: { threshold: 1 },
50973			LOD: {},
50974			Points: { threshold: 1 },
50975			Sprite: {}
50976		};
50977
50978	}
50979
50980	set( origin, direction ) {
50981
50982		// direction is assumed to be normalized (for accurate distance calculations)
50983
50984		this.ray.set( origin, direction );
50985
50986	}
50987
50988	setFromCamera( coords, camera ) {
50989
50990		if ( camera.isPerspectiveCamera ) {
50991
50992			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
50993			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
50994			this.camera = camera;
50995
50996		} else if ( camera.isOrthographicCamera ) {
50997
50998			this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
50999			this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
51000			this.camera = camera;
51001
51002		} else {
51003
51004			console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
51005
51006		}
51007
51008	}
51009
51010	intersectObject( object, recursive = true, intersects = [] ) {
51011
51012		intersectObject( object, this, intersects, recursive );
51013
51014		intersects.sort( ascSort );
51015
51016		return intersects;
51017
51018	}
51019
51020	intersectObjects( objects, recursive = true, intersects = [] ) {
51021
51022		for ( let i = 0, l = objects.length; i < l; i ++ ) {
51023
51024			intersectObject( objects[ i ], this, intersects, recursive );
51025
51026		}
51027
51028		intersects.sort( ascSort );
51029
51030		return intersects;
51031
51032	}
51033
51034}
51035
51036function ascSort( a, b ) {
51037
51038	return a.distance - b.distance;
51039
51040}
51041
51042function intersectObject( object, raycaster, intersects, recursive ) {
51043
51044	if ( object.layers.test( raycaster.layers ) ) {
51045
51046		object.raycast( raycaster, intersects );
51047
51048	}
51049
51050	if ( recursive === true ) {
51051
51052		const children = object.children;
51053
51054		for ( let i = 0, l = children.length; i < l; i ++ ) {
51055
51056			intersectObject( children[ i ], raycaster, intersects, true );
51057
51058		}
51059
51060	}
51061
51062}
51063
51064/**
51065 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
51066 *
51067 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
51068 * The azimuthal angle (theta) is measured from the positive z-axis.
51069 */
51070
51071
51072class Spherical {
51073
vendor: 20,801 bytes, lines 51074-52209
51074	constructor( radius = 1, phi = 0, theta = 0 ) {
51075
51076		this.radius = radius;
51077		this.phi = phi; // polar angle
51078		this.theta = theta; // azimuthal angle
51079
51080		return this;
51081
51082	}
51083
51084	set( radius, phi, theta ) {
51085
51086		this.radius = radius;
51087		this.phi = phi;
51088		this.theta = theta;
51089
51090		return this;
51091
51092	}
51093
51094	copy( other ) {
51095
51096		this.radius = other.radius;
51097		this.phi = other.phi;
51098		this.theta = other.theta;
51099
51100		return this;
51101
51102	}
51103
51104	// restrict phi to be between EPS and PI-EPS
51105	makeSafe() {
51106
51107		const EPS = 0.000001;
51108		this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
51109
51110		return this;
51111
51112	}
51113
51114	setFromVector3( v ) {
51115
51116		return this.setFromCartesianCoords( v.x, v.y, v.z );
51117
51118	}
51119
51120	setFromCartesianCoords( x, y, z ) {
51121
51122		this.radius = Math.sqrt( x * x + y * y + z * z );
51123
51124		if ( this.radius === 0 ) {
51125
51126			this.theta = 0;
51127			this.phi = 0;
51128
51129		} else {
51130
51131			this.theta = Math.atan2( x, z );
51132			this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) );
51133
51134		}
51135
51136		return this;
51137
51138	}
51139
51140	clone() {
51141
51142		return new this.constructor().copy( this );
51143
51144	}
51145
51146}
51147
51148/**
51149 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
51150 */
51151
51152class Cylindrical {
51153
51154	constructor( radius = 1, theta = 0, y = 0 ) {
51155
51156		this.radius = radius; // distance from the origin to a point in the x-z plane
51157		this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
51158		this.y = y; // height above the x-z plane
51159
51160		return this;
51161
51162	}
51163
51164	set( radius, theta, y ) {
51165
51166		this.radius = radius;
51167		this.theta = theta;
51168		this.y = y;
51169
51170		return this;
51171
51172	}
51173
51174	copy( other ) {
51175
51176		this.radius = other.radius;
51177		this.theta = other.theta;
51178		this.y = other.y;
51179
51180		return this;
51181
51182	}
51183
51184	setFromVector3( v ) {
51185
51186		return this.setFromCartesianCoords( v.x, v.y, v.z );
51187
51188	}
51189
51190	setFromCartesianCoords( x, y, z ) {
51191
51192		this.radius = Math.sqrt( x * x + z * z );
51193		this.theta = Math.atan2( x, z );
51194		this.y = y;
51195
51196		return this;
51197
51198	}
51199
51200	clone() {
51201
51202		return new this.constructor().copy( this );
51203
51204	}
51205
51206}
51207
51208const _vector$4 = /*@__PURE__*/ new Vector2();
51209
51210class Box2 {
51211
51212	constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) {
51213
51214		this.isBox2 = true;
51215
51216		this.min = min;
51217		this.max = max;
51218
51219	}
51220
51221	set( min, max ) {
51222
51223		this.min.copy( min );
51224		this.max.copy( max );
51225
51226		return this;
51227
51228	}
51229
51230	setFromPoints( points ) {
51231
51232		this.makeEmpty();
51233
51234		for ( let i = 0, il = points.length; i < il; i ++ ) {
51235
51236			this.expandByPoint( points[ i ] );
51237
51238		}
51239
51240		return this;
51241
51242	}
51243
51244	setFromCenterAndSize( center, size ) {
51245
51246		const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 );
51247		this.min.copy( center ).sub( halfSize );
51248		this.max.copy( center ).add( halfSize );
51249
51250		return this;
51251
51252	}
51253
51254	clone() {
51255
51256		return new this.constructor().copy( this );
51257
51258	}
51259
51260	copy( box ) {
51261
51262		this.min.copy( box.min );
51263		this.max.copy( box.max );
51264
51265		return this;
51266
51267	}
51268
51269	makeEmpty() {
51270
51271		this.min.x = this.min.y = + Infinity;
51272		this.max.x = this.max.y = - Infinity;
51273
51274		return this;
51275
51276	}
51277
51278	isEmpty() {
51279
51280		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
51281
51282		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
51283
51284	}
51285
51286	getCenter( target ) {
51287
51288		return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
51289
51290	}
51291
51292	getSize( target ) {
51293
51294		return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
51295
51296	}
51297
51298	expandByPoint( point ) {
51299
51300		this.min.min( point );
51301		this.max.max( point );
51302
51303		return this;
51304
51305	}
51306
51307	expandByVector( vector ) {
51308
51309		this.min.sub( vector );
51310		this.max.add( vector );
51311
51312		return this;
51313
51314	}
51315
51316	expandByScalar( scalar ) {
51317
51318		this.min.addScalar( - scalar );
51319		this.max.addScalar( scalar );
51320
51321		return this;
51322
51323	}
51324
51325	containsPoint( point ) {
51326
51327		return point.x < this.min.x || point.x > this.max.x ||
51328			point.y < this.min.y || point.y > this.max.y ? false : true;
51329
51330	}
51331
51332	containsBox( box ) {
51333
51334		return this.min.x <= box.min.x && box.max.x <= this.max.x &&
51335			this.min.y <= box.min.y && box.max.y <= this.max.y;
51336
51337	}
51338
51339	getParameter( point, target ) {
51340
51341		// This can potentially have a divide by zero if the box
51342		// has a size dimension of 0.
51343
51344		return target.set(
51345			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
51346			( point.y - this.min.y ) / ( this.max.y - this.min.y )
51347		);
51348
51349	}
51350
51351	intersectsBox( box ) {
51352
51353		// using 4 splitting planes to rule out intersections
51354
51355		return box.max.x < this.min.x || box.min.x > this.max.x ||
51356			box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
51357
51358	}
51359
51360	clampPoint( point, target ) {
51361
51362		return target.copy( point ).clamp( this.min, this.max );
51363
51364	}
51365
51366	distanceToPoint( point ) {
51367
51368		return this.clampPoint( point, _vector$4 ).distanceTo( point );
51369
51370	}
51371
51372	intersect( box ) {
51373
51374		this.min.max( box.min );
51375		this.max.min( box.max );
51376
51377		if ( this.isEmpty() ) this.makeEmpty();
51378
51379		return this;
51380
51381	}
51382
51383	union( box ) {
51384
51385		this.min.min( box.min );
51386		this.max.max( box.max );
51387
51388		return this;
51389
51390	}
51391
51392	translate( offset ) {
51393
51394		this.min.add( offset );
51395		this.max.add( offset );
51396
51397		return this;
51398
51399	}
51400
51401	equals( box ) {
51402
51403		return box.min.equals( this.min ) && box.max.equals( this.max );
51404
51405	}
51406
51407}
51408
51409const _startP = /*@__PURE__*/ new Vector3();
51410const _startEnd = /*@__PURE__*/ new Vector3();
51411
51412class Line3 {
51413
51414	constructor( start = new Vector3(), end = new Vector3() ) {
51415
51416		this.start = start;
51417		this.end = end;
51418
51419	}
51420
51421	set( start, end ) {
51422
51423		this.start.copy( start );
51424		this.end.copy( end );
51425
51426		return this;
51427
51428	}
51429
51430	copy( line ) {
51431
51432		this.start.copy( line.start );
51433		this.end.copy( line.end );
51434
51435		return this;
51436
51437	}
51438
51439	getCenter( target ) {
51440
51441		return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
51442
51443	}
51444
51445	delta( target ) {
51446
51447		return target.subVectors( this.end, this.start );
51448
51449	}
51450
51451	distanceSq() {
51452
51453		return this.start.distanceToSquared( this.end );
51454
51455	}
51456
51457	distance() {
51458
51459		return this.start.distanceTo( this.end );
51460
51461	}
51462
51463	at( t, target ) {
51464
51465		return this.delta( target ).multiplyScalar( t ).add( this.start );
51466
51467	}
51468
51469	closestPointToPointParameter( point, clampToLine ) {
51470
51471		_startP.subVectors( point, this.start );
51472		_startEnd.subVectors( this.end, this.start );
51473
51474		const startEnd2 = _startEnd.dot( _startEnd );
51475		const startEnd_startP = _startEnd.dot( _startP );
51476
51477		let t = startEnd_startP / startEnd2;
51478
51479		if ( clampToLine ) {
51480
51481			t = clamp( t, 0, 1 );
51482
51483		}
51484
51485		return t;
51486
51487	}
51488
51489	closestPointToPoint( point, clampToLine, target ) {
51490
51491		const t = this.closestPointToPointParameter( point, clampToLine );
51492
51493		return this.delta( target ).multiplyScalar( t ).add( this.start );
51494
51495	}
51496
51497	applyMatrix4( matrix ) {
51498
51499		this.start.applyMatrix4( matrix );
51500		this.end.applyMatrix4( matrix );
51501
51502		return this;
51503
51504	}
51505
51506	equals( line ) {
51507
51508		return line.start.equals( this.start ) && line.end.equals( this.end );
51509
51510	}
51511
51512	clone() {
51513
51514		return new this.constructor().copy( this );
51515
51516	}
51517
51518}
51519
51520const _vector$3 = /*@__PURE__*/ new Vector3();
51521
51522class SpotLightHelper extends Object3D {
51523
51524	constructor( light, color ) {
51525
51526		super();
51527
51528		this.light = light;
51529
51530		this.matrix = light.matrixWorld;
51531		this.matrixAutoUpdate = false;
51532
51533		this.color = color;
51534
51535		this.type = 'SpotLightHelper';
51536
51537		const geometry = new BufferGeometry();
51538
51539		const positions = [
51540			0, 0, 0, 	0, 0, 1,
51541			0, 0, 0, 	1, 0, 1,
51542			0, 0, 0,	- 1, 0, 1,
51543			0, 0, 0, 	0, 1, 1,
51544			0, 0, 0, 	0, - 1, 1
51545		];
51546
51547		for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
51548
51549			const p1 = ( i / l ) * Math.PI * 2;
51550			const p2 = ( j / l ) * Math.PI * 2;
51551
51552			positions.push(
51553				Math.cos( p1 ), Math.sin( p1 ), 1,
51554				Math.cos( p2 ), Math.sin( p2 ), 1
51555			);
51556
51557		}
51558
51559		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
51560
51561		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
51562
51563		this.cone = new LineSegments( geometry, material );
51564		this.add( this.cone );
51565
51566		this.update();
51567
51568	}
51569
51570	dispose() {
51571
51572		this.cone.geometry.dispose();
51573		this.cone.material.dispose();
51574
51575	}
51576
51577	update() {
51578
51579		this.light.updateWorldMatrix( true, false );
51580		this.light.target.updateWorldMatrix( true, false );
51581
51582		const coneLength = this.light.distance ? this.light.distance : 1000;
51583		const coneWidth = coneLength * Math.tan( this.light.angle );
51584
51585		this.cone.scale.set( coneWidth, coneWidth, coneLength );
51586
51587		_vector$3.setFromMatrixPosition( this.light.target.matrixWorld );
51588
51589		this.cone.lookAt( _vector$3 );
51590
51591		if ( this.color !== undefined ) {
51592
51593			this.cone.material.color.set( this.color );
51594
51595		} else {
51596
51597			this.cone.material.color.copy( this.light.color );
51598
51599		}
51600
51601	}
51602
51603}
51604
51605const _vector$2 = /*@__PURE__*/ new Vector3();
51606const _boneMatrix = /*@__PURE__*/ new Matrix4();
51607const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
51608
51609
51610class SkeletonHelper extends LineSegments {
51611
51612	constructor( object ) {
51613
51614		const bones = getBoneList( object );
51615
51616		const geometry = new BufferGeometry();
51617
51618		const vertices = [];
51619		const colors = [];
51620
51621		const color1 = new Color( 0, 0, 1 );
51622		const color2 = new Color( 0, 1, 0 );
51623
51624		for ( let i = 0; i < bones.length; i ++ ) {
51625
51626			const bone = bones[ i ];
51627
51628			if ( bone.parent && bone.parent.isBone ) {
51629
51630				vertices.push( 0, 0, 0 );
51631				vertices.push( 0, 0, 0 );
51632				colors.push( color1.r, color1.g, color1.b );
51633				colors.push( color2.r, color2.g, color2.b );
51634
51635			}
51636
51637		}
51638
51639		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51640		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51641
51642		const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
51643
51644		super( geometry, material );
51645
51646		this.isSkeletonHelper = true;
51647
51648		this.type = 'SkeletonHelper';
51649
51650		this.root = object;
51651		this.bones = bones;
51652
51653		this.matrix = object.matrixWorld;
51654		this.matrixAutoUpdate = false;
51655
51656	}
51657
51658	updateMatrixWorld( force ) {
51659
51660		const bones = this.bones;
51661
51662		const geometry = this.geometry;
51663		const position = geometry.getAttribute( 'position' );
51664
51665		_matrixWorldInv.copy( this.root.matrixWorld ).invert();
51666
51667		for ( let i = 0, j = 0; i < bones.length; i ++ ) {
51668
51669			const bone = bones[ i ];
51670
51671			if ( bone.parent && bone.parent.isBone ) {
51672
51673				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
51674				_vector$2.setFromMatrixPosition( _boneMatrix );
51675				position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );
51676
51677				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
51678				_vector$2.setFromMatrixPosition( _boneMatrix );
51679				position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );
51680
51681				j += 2;
51682
51683			}
51684
51685		}
51686
51687		geometry.getAttribute( 'position' ).needsUpdate = true;
51688
51689		super.updateMatrixWorld( force );
51690
51691	}
51692
51693	dispose() {
51694
51695		this.geometry.dispose();
51696		this.material.dispose();
51697
51698	}
51699
51700}
51701
51702
51703function getBoneList( object ) {
51704
51705	const boneList = [];
51706
51707	if ( object.isBone === true ) {
51708
51709		boneList.push( object );
51710
51711	}
51712
51713	for ( let i = 0; i < object.children.length; i ++ ) {
51714
51715		boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
51716
51717	}
51718
51719	return boneList;
51720
51721}
51722
51723class PointLightHelper extends Mesh {
51724
51725	constructor( light, sphereSize, color ) {
51726
51727		const geometry = new SphereGeometry( sphereSize, 4, 2 );
51728		const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51729
51730		super( geometry, material );
51731
51732		this.light = light;
51733
51734		this.color = color;
51735
51736		this.type = 'PointLightHelper';
51737
51738		this.matrix = this.light.matrixWorld;
51739		this.matrixAutoUpdate = false;
51740
51741		this.update();
51742
51743
51744		/*
51745	// TODO: delete this comment?
51746	const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
51747	const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
51748
51749	this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
51750	this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
51751
51752	const d = light.distance;
51753
51754	if ( d === 0.0 ) {
51755
51756		this.lightDistance.visible = false;
51757
51758	} else {
51759
51760		this.lightDistance.scale.set( d, d, d );
51761
51762	}
51763
51764	this.add( this.lightDistance );
51765	*/
51766
51767	}
51768
51769	dispose() {
51770
51771		this.geometry.dispose();
51772		this.material.dispose();
51773
51774	}
51775
51776	update() {
51777
51778		this.light.updateWorldMatrix( true, false );
51779
51780		if ( this.color !== undefined ) {
51781
51782			this.material.color.set( this.color );
51783
51784		} else {
51785
51786			this.material.color.copy( this.light.color );
51787
51788		}
51789
51790		/*
51791		const d = this.light.distance;
51792
51793		if ( d === 0.0 ) {
51794
51795			this.lightDistance.visible = false;
51796
51797		} else {
51798
51799			this.lightDistance.visible = true;
51800			this.lightDistance.scale.set( d, d, d );
51801
51802		}
51803		*/
51804
51805	}
51806
51807}
51808
51809const _vector$1 = /*@__PURE__*/ new Vector3();
51810const _color1 = /*@__PURE__*/ new Color();
51811const _color2 = /*@__PURE__*/ new Color();
51812
51813class HemisphereLightHelper extends Object3D {
51814
51815	constructor( light, size, color ) {
51816
51817		super();
51818
51819		this.light = light;
51820
51821		this.matrix = light.matrixWorld;
51822		this.matrixAutoUpdate = false;
51823
51824		this.color = color;
51825
51826		this.type = 'HemisphereLightHelper';
51827
51828		const geometry = new OctahedronGeometry( size );
51829		geometry.rotateY( Math.PI * 0.5 );
51830
51831		this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51832		if ( this.color === undefined ) this.material.vertexColors = true;
51833
51834		const position = geometry.getAttribute( 'position' );
51835		const colors = new Float32Array( position.count * 3 );
51836
51837		geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
51838
51839		this.add( new Mesh( geometry, this.material ) );
51840
51841		this.update();
51842
51843	}
51844
51845	dispose() {
51846
51847		this.children[ 0 ].geometry.dispose();
51848		this.children[ 0 ].material.dispose();
51849
51850	}
51851
51852	update() {
51853
51854		const mesh = this.children[ 0 ];
51855
51856		if ( this.color !== undefined ) {
51857
51858			this.material.color.set( this.color );
51859
51860		} else {
51861
51862			const colors = mesh.geometry.getAttribute( 'color' );
51863
51864			_color1.copy( this.light.color );
51865			_color2.copy( this.light.groundColor );
51866
51867			for ( let i = 0, l = colors.count; i < l; i ++ ) {
51868
51869				const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
51870
51871				colors.setXYZ( i, color.r, color.g, color.b );
51872
51873			}
51874
51875			colors.needsUpdate = true;
51876
51877		}
51878
51879		this.light.updateWorldMatrix( true, false );
51880
51881		mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() );
51882
51883	}
51884
51885}
51886
51887class GridHelper extends LineSegments {
51888
51889	constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
51890
51891		color1 = new Color( color1 );
51892		color2 = new Color( color2 );
51893
51894		const center = divisions / 2;
51895		const step = size / divisions;
51896		const halfSize = size / 2;
51897
51898		const vertices = [], colors = [];
51899
51900		for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
51901
51902			vertices.push( - halfSize, 0, k, halfSize, 0, k );
51903			vertices.push( k, 0, - halfSize, k, 0, halfSize );
51904
51905			const color = i === center ? color1 : color2;
51906
51907			color.toArray( colors, j ); j += 3;
51908			color.toArray( colors, j ); j += 3;
51909			color.toArray( colors, j ); j += 3;
51910			color.toArray( colors, j ); j += 3;
51911
51912		}
51913
51914		const geometry = new BufferGeometry();
51915		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51916		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51917
51918		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
51919
51920		super( geometry, material );
51921
51922		this.type = 'GridHelper';
51923
51924	}
51925
51926	dispose() {
51927
51928		this.geometry.dispose();
51929		this.material.dispose();
51930
51931	}
51932
51933}
51934
51935class PolarGridHelper extends LineSegments {
51936
51937	constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
51938
51939		color1 = new Color( color1 );
51940		color2 = new Color( color2 );
51941
51942		const vertices = [];
51943		const colors = [];
51944
51945		// create the sectors
51946
51947		if ( sectors > 1 ) {
51948
51949			for ( let i = 0; i < sectors; i ++ ) {
51950
51951				const v = ( i / sectors ) * ( Math.PI * 2 );
51952
51953				const x = Math.sin( v ) * radius;
51954				const z = Math.cos( v ) * radius;
51955
51956				vertices.push( 0, 0, 0 );
51957				vertices.push( x, 0, z );
51958
51959				const color = ( i & 1 ) ? color1 : color2;
51960
51961				colors.push( color.r, color.g, color.b );
51962				colors.push( color.r, color.g, color.b );
51963
51964			}
51965
51966		}
51967
51968		// create the rings
51969
51970		for ( let i = 0; i < rings; i ++ ) {
51971
51972			const color = ( i & 1 ) ? color1 : color2;
51973
51974			const r = radius - ( radius / rings * i );
51975
51976			for ( let j = 0; j < divisions; j ++ ) {
51977
51978				// first vertex
51979
51980				let v = ( j / divisions ) * ( Math.PI * 2 );
51981
51982				let x = Math.sin( v ) * r;
51983				let z = Math.cos( v ) * r;
51984
51985				vertices.push( x, 0, z );
51986				colors.push( color.r, color.g, color.b );
51987
51988				// second vertex
51989
51990				v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
51991
51992				x = Math.sin( v ) * r;
51993				z = Math.cos( v ) * r;
51994
51995				vertices.push( x, 0, z );
51996				colors.push( color.r, color.g, color.b );
51997
51998			}
51999
52000		}
52001
52002		const geometry = new BufferGeometry();
52003		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52004		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52005
52006		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52007
52008		super( geometry, material );
52009
52010		this.type = 'PolarGridHelper';
52011
52012	}
52013
52014	dispose() {
52015
52016		this.geometry.dispose();
52017		this.material.dispose();
52018
52019	}
52020
52021}
52022
52023const _v1 = /*@__PURE__*/ new Vector3();
52024const _v2 = /*@__PURE__*/ new Vector3();
52025const _v3 = /*@__PURE__*/ new Vector3();
52026
52027class DirectionalLightHelper extends Object3D {
52028
52029	constructor( light, size, color ) {
52030
52031		super();
52032
52033		this.light = light;
52034
52035		this.matrix = light.matrixWorld;
52036		this.matrixAutoUpdate = false;
52037
52038		this.color = color;
52039
52040		this.type = 'DirectionalLightHelper';
52041
52042		if ( size === undefined ) size = 1;
52043
52044		let geometry = new BufferGeometry();
52045		geometry.setAttribute( 'position', new Float32BufferAttribute( [
52046			- size, size, 0,
52047			size, size, 0,
52048			size, - size, 0,
52049			- size, - size, 0,
52050			- size, size, 0
52051		], 3 ) );
52052
52053		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
52054
52055		this.lightPlane = new Line( geometry, material );
52056		this.add( this.lightPlane );
52057
52058		geometry = new BufferGeometry();
52059		geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
52060
52061		this.targetLine = new Line( geometry, material );
52062		this.add( this.targetLine );
52063
52064		this.update();
52065
52066	}
52067
52068	dispose() {
52069
52070		this.lightPlane.geometry.dispose();
52071		this.lightPlane.material.dispose();
52072		this.targetLine.geometry.dispose();
52073		this.targetLine.material.dispose();
52074
52075	}
52076
52077	update() {
52078
52079		this.light.updateWorldMatrix( true, false );
52080		this.light.target.updateWorldMatrix( true, false );
52081
52082		_v1.setFromMatrixPosition( this.light.matrixWorld );
52083		_v2.setFromMatrixPosition( this.light.target.matrixWorld );
52084		_v3.subVectors( _v2, _v1 );
52085
52086		this.lightPlane.lookAt( _v2 );
52087
52088		if ( this.color !== undefined ) {
52089
52090			this.lightPlane.material.color.set( this.color );
52091			this.targetLine.material.color.set( this.color );
52092
52093		} else {
52094
52095			this.lightPlane.material.color.copy( this.light.color );
52096			this.targetLine.material.color.copy( this.light.color );
52097
52098		}
52099
52100		this.targetLine.lookAt( _v2 );
52101		this.targetLine.scale.z = _v3.length();
52102
52103	}
52104
52105}
52106
52107const _vector = /*@__PURE__*/ new Vector3();
52108const _camera = /*@__PURE__*/ new Camera();
52109
52110/**
52111 *	- shows frustum, line of sight and up of the camera
52112 *	- suitable for fast updates
52113 * 	- based on frustum visualization in lightgl.js shadowmap example
52114 *		https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html
52115 */
52116
52117class CameraHelper extends LineSegments {
52118
52119	constructor( camera ) {
52120
52121		const geometry = new BufferGeometry();
52122		const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
52123
52124		const vertices = [];
52125		const colors = [];
52126
52127		const pointMap = {};
52128
52129		// near
52130
52131		addLine( 'n1', 'n2' );
52132		addLine( 'n2', 'n4' );
52133		addLine( 'n4', 'n3' );
52134		addLine( 'n3', 'n1' );
52135
52136		// far
52137
52138		addLine( 'f1', 'f2' );
52139		addLine( 'f2', 'f4' );
52140		addLine( 'f4', 'f3' );
52141		addLine( 'f3', 'f1' );
52142
52143		// sides
52144
52145		addLine( 'n1', 'f1' );
52146		addLine( 'n2', 'f2' );
52147		addLine( 'n3', 'f3' );
52148		addLine( 'n4', 'f4' );
52149
52150		// cone
52151
52152		addLine( 'p', 'n1' );
52153		addLine( 'p', 'n2' );
52154		addLine( 'p', 'n3' );
52155		addLine( 'p', 'n4' );
52156
52157		// up
52158
52159		addLine( 'u1', 'u2' );
52160		addLine( 'u2', 'u3' );
52161		addLine( 'u3', 'u1' );
52162
52163		// target
52164
52165		addLine( 'c', 't' );
52166		addLine( 'p', 'c' );
52167
52168		// cross
52169
52170		addLine( 'cn1', 'cn2' );
52171		addLine( 'cn3', 'cn4' );
52172
52173		addLine( 'cf1', 'cf2' );
52174		addLine( 'cf3', 'cf4' );
52175
52176		function addLine( a, b ) {
52177
52178			addPoint( a );
52179			addPoint( b );
52180
52181		}
52182
52183		function addPoint( id ) {
52184
52185			vertices.push( 0, 0, 0 );
52186			colors.push( 0, 0, 0 );
52187
52188			if ( pointMap[ id ] === undefined ) {
52189
52190				pointMap[ id ] = [];
52191
52192			}
52193
52194			pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
52195
52196		}
52197
52198		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52199		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52200
52201		super( geometry, material );
52202
52203		this.type = 'CameraHelper';
52204
52205		this.camera = camera;
52206		if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
52207
52208		this.matrix = camera.matrixWorld;
52209		this.matrixAutoUpdate = false;
52210
52211		this.pointMap = pointMap;
52212
52213		this.update();
52214
52215		// colors
52216
52217		const colorFrustum = new Color( 0xffaa00 );
52218		const colorCone = new Color( 0xff0000 );
52219		const colorUp = new Color( 0x00aaff );
52220		const colorTarget = new Color( 0xffffff );
52221		const colorCross = new Color( 0x333333 );
52222
52223		this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross );
52224
52225	}
52226
52227	setColors( frustum, cone, up, target, cross ) {
52228
52229		const geometry = this.geometry;
52230
52231		const colorAttribute = geometry.getAttribute( 'color' );
52232
52233		// near
52234
52235		colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2
52236		colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4
52237		colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3
52238		colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1
52239
52240		// far
52241
52242		colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2
52243		colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4
52244		colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3
52245		colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1
52246
52247		// sides
52248
52249		colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1
52250		colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2
52251		colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3
52252		colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4
52253
52254		// cone
52255
52256		colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1
52257		colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2
52258		colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3
52259		colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4
52260
52261		// up
52262
52263		colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2
52264		colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3
52265		colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1
52266
52267		// target
52268
52269		colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t
52270		colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c
52271
52272		// cross
52273
52274		colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2
52275		colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4
52276
52277		colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2
52278		colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4
52279
52280		colorAttribute.needsUpdate = true;
52281
52282	}
52283
52284	update() {
52285
52286		const geometry = this.geometry;
52287		const pointMap = this.pointMap;
52288
52289		const w = 1, h = 1;
52290
52291		// we need just camera projection matrix inverse
52292		// world matrix must be identity
52293
52294		_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
52295
52296		// center / target
52297
52298		setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
52299		setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
52300
52301		// near
52302
52303		setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
52304		setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
52305		setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
52306		setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
52307
52308		// far
52309
52310		setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
52311		setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
52312		setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
52313		setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
52314
52315		// up
52316
52317		setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
52318		setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
52319		setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
52320
52321		// cross
52322
52323		setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
52324		setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
52325		setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
52326		setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
52327
52328		setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
52329		setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
52330		setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
52331		setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
52332
52333		geometry.getAttribute( 'position' ).needsUpdate = true;
52334
52335	}
52336
52337	dispose() {
52338
52339		this.geometry.dispose();
52340		this.material.dispose();
52341
52342	}
52343
52344}
52345
52346
52347function setPoint( point, pointMap, geometry, camera, x, y, z ) {
52348
52349	_vector.set( x, y, z ).unproject( camera );
52350
52351	const points = pointMap[ point ];
52352
52353	if ( points !== undefined ) {
52354
52355		const position = geometry.getAttribute( 'position' );
52356
52357		for ( let i = 0, l = points.length; i < l; i ++ ) {
52358
52359			position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z );
52360
52361		}
52362
52363	}
52364
52365}
52366
52367const _box = /*@__PURE__*/ new Box3();
52368
52369class BoxHelper extends LineSegments {
52370
52371	constructor( object, color = 0xffff00 ) {
52372
52373		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 ] );
52374		const positions = new Float32Array( 8 * 3 );
52375
52376		const geometry = new BufferGeometry();
52377		geometry.setIndex( new BufferAttribute( indices, 1 ) );
52378		geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
52379
52380		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52381
52382		this.object = object;
52383		this.type = 'BoxHelper';
52384
52385		this.matrixAutoUpdate = false;
vendor: 4,705 bytes, lines 52386-52602
52386
52387		this.update();
52388
52389	}
52390
52391	update( object ) {
52392
52393		if ( object !== undefined ) {
52394
52395			console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
52396
52397		}
52398
52399		if ( this.object !== undefined ) {
52400
52401			_box.setFromObject( this.object );
52402
52403		}
52404
52405		if ( _box.isEmpty() ) return;
52406
52407		const min = _box.min;
52408		const max = _box.max;
52409
52410		/*
52411			5____4
52412		1/___0/|
52413		| 6__|_7
52414		2/___3/
52415
52416		0: max.x, max.y, max.z
52417		1: min.x, max.y, max.z
52418		2: min.x, min.y, max.z
52419		3: max.x, min.y, max.z
52420		4: max.x, max.y, min.z
52421		5: min.x, max.y, min.z
52422		6: min.x, min.y, min.z
52423		7: max.x, min.y, min.z
52424		*/
52425
52426		const position = this.geometry.attributes.position;
52427		const array = position.array;
52428
52429		array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
52430		array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
52431		array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
52432		array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
52433		array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
52434		array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
52435		array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
52436		array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
52437
52438		position.needsUpdate = true;
52439
52440		this.geometry.computeBoundingSphere();
52441
52442	}
52443
52444	setFromObject( object ) {
52445
52446		this.object = object;
52447		this.update();
52448
52449		return this;
52450
52451	}
52452
52453	copy( source, recursive ) {
52454
52455		super.copy( source, recursive );
52456
52457		this.object = source.object;
52458
52459		return this;
52460
52461	}
52462
52463	dispose() {
52464
52465		this.geometry.dispose();
52466		this.material.dispose();
52467
52468	}
52469
52470}
52471
52472class Box3Helper extends LineSegments {
52473
52474	constructor( box, color = 0xffff00 ) {
52475
52476		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 ] );
52477
52478		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 ];
52479
52480		const geometry = new BufferGeometry();
52481
52482		geometry.setIndex( new BufferAttribute( indices, 1 ) );
52483
52484		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52485
52486		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52487
52488		this.box = box;
52489
52490		this.type = 'Box3Helper';
52491
52492		this.geometry.computeBoundingSphere();
52493
52494	}
52495
52496	updateMatrixWorld( force ) {
52497
52498		const box = this.box;
52499
52500		if ( box.isEmpty() ) return;
52501
52502		box.getCenter( this.position );
52503
52504		box.getSize( this.scale );
52505
52506		this.scale.multiplyScalar( 0.5 );
52507
52508		super.updateMatrixWorld( force );
52509
52510	}
52511
52512	dispose() {
52513
52514		this.geometry.dispose();
52515		this.material.dispose();
52516
52517	}
52518
52519}
52520
52521class PlaneHelper extends Line {
52522
52523	constructor( plane, size = 1, hex = 0xffff00 ) {
52524
52525		const color = hex;
52526
52527		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 ];
52528
52529		const geometry = new BufferGeometry();
52530		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52531		geometry.computeBoundingSphere();
52532
52533		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52534
52535		this.type = 'PlaneHelper';
52536
52537		this.plane = plane;
52538
52539		this.size = size;
52540
52541		const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];
52542
52543		const geometry2 = new BufferGeometry();
52544		geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
52545		geometry2.computeBoundingSphere();
52546
52547		this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
52548
52549	}
52550
52551	updateMatrixWorld( force ) {
52552
52553		this.position.set( 0, 0, 0 );
52554
52555		this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 );
52556
52557		this.lookAt( this.plane.normal );
52558
52559		this.translateZ( - this.plane.constant );
52560
52561		super.updateMatrixWorld( force );
52562
52563	}
52564
52565	dispose() {
52566
52567		this.geometry.dispose();
52568		this.material.dispose();
52569		this.children[ 0 ].geometry.dispose();
52570		this.children[ 0 ].material.dispose();
52571
52572	}
52573
52574}
52575
52576const _axis = /*@__PURE__*/ new Vector3();
52577let _lineGeometry, _coneGeometry;
52578
52579class ArrowHelper extends Object3D {
52580
52581	// dir is assumed to be normalized
52582
52583	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 ) {
52584
52585		super();
52586
52587		this.type = 'ArrowHelper';
52588
52589		if ( _lineGeometry === undefined ) {
52590
52591			_lineGeometry = new BufferGeometry();
52592			_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
52593
52594			_coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );
52595			_coneGeometry.translate( 0, - 0.5, 0 );
52596
52597		}
52598
52599		this.position.copy( origin );
52600
52601		this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52602		this.line.matrixAutoUpdate = false;
vendor: 3,957 bytes, lines 52603-52822
52603		this.add( this.line );
52604
52605		this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
52606		this.cone.matrixAutoUpdate = false;
52607		this.add( this.cone );
52608
52609		this.setDirection( dir );
52610		this.setLength( length, headLength, headWidth );
52611
52612	}
52613
52614	setDirection( dir ) {
52615
52616		// dir is assumed to be normalized
52617
52618		if ( dir.y > 0.99999 ) {
52619
52620			this.quaternion.set( 0, 0, 0, 1 );
52621
52622		} else if ( dir.y < - 0.99999 ) {
52623
52624			this.quaternion.set( 1, 0, 0, 0 );
52625
52626		} else {
52627
52628			_axis.set( dir.z, 0, - dir.x ).normalize();
52629
52630			const radians = Math.acos( dir.y );
52631
52632			this.quaternion.setFromAxisAngle( _axis, radians );
52633
52634		}
52635
52636	}
52637
52638	setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) {
52639
52640		this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
52641		this.line.updateMatrix();
52642
52643		this.cone.scale.set( headWidth, headLength, headWidth );
52644		this.cone.position.y = length;
52645		this.cone.updateMatrix();
52646
52647	}
52648
52649	setColor( color ) {
52650
52651		this.line.material.color.set( color );
52652		this.cone.material.color.set( color );
52653
52654	}
52655
52656	copy( source ) {
52657
52658		super.copy( source, false );
52659
52660		this.line.copy( source.line );
52661		this.cone.copy( source.cone );
52662
52663		return this;
52664
52665	}
52666
52667	dispose() {
52668
52669		this.line.geometry.dispose();
52670		this.line.material.dispose();
52671		this.cone.geometry.dispose();
52672		this.cone.material.dispose();
52673
52674	}
52675
52676}
52677
52678class AxesHelper extends LineSegments {
52679
52680	constructor( size = 1 ) {
52681
52682		const vertices = [
52683			0, 0, 0,	size, 0, 0,
52684			0, 0, 0,	0, size, 0,
52685			0, 0, 0,	0, 0, size
52686		];
52687
52688		const colors = [
52689			1, 0, 0,	1, 0.6, 0,
52690			0, 1, 0,	0.6, 1, 0,
52691			0, 0, 1,	0, 0.6, 1
52692		];
52693
52694		const geometry = new BufferGeometry();
52695		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52696		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52697
52698		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52699
52700		super( geometry, material );
52701
52702		this.type = 'AxesHelper';
52703
52704	}
52705
52706	setColors( xAxisColor, yAxisColor, zAxisColor ) {
52707
52708		const color = new Color();
52709		const array = this.geometry.attributes.color.array;
52710
52711		color.set( xAxisColor );
52712		color.toArray( array, 0 );
52713		color.toArray( array, 3 );
52714
52715		color.set( yAxisColor );
52716		color.toArray( array, 6 );
52717		color.toArray( array, 9 );
52718
52719		color.set( zAxisColor );
52720		color.toArray( array, 12 );
52721		color.toArray( array, 15 );
52722
52723		this.geometry.attributes.color.needsUpdate = true;
52724
52725		return this;
52726
52727	}
52728
52729	dispose() {
52730
52731		this.geometry.dispose();
52732		this.material.dispose();
52733
52734	}
52735
52736}
52737
52738class ShapePath {
52739
52740	constructor() {
52741
52742		this.type = 'ShapePath';
52743
52744		this.color = new Color();
52745
52746		this.subPaths = [];
52747		this.currentPath = null;
52748
52749	}
52750
52751	moveTo( x, y ) {
52752
52753		this.currentPath = new Path();
52754		this.subPaths.push( this.currentPath );
52755		this.currentPath.moveTo( x, y );
52756
52757		return this;
52758
52759	}
52760
52761	lineTo( x, y ) {
52762
52763		this.currentPath.lineTo( x, y );
52764
52765		return this;
52766
52767	}
52768
52769	quadraticCurveTo( aCPx, aCPy, aX, aY ) {
52770
52771		this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
52772
52773		return this;
52774
52775	}
52776
52777	bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
52778
52779		this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
52780
52781		return this;
52782
52783	}
52784
52785	splineThru( pts ) {
52786
52787		this.currentPath.splineThru( pts );
52788
52789		return this;
52790
52791	}
52792
52793	toShapes( isCCW ) {
52794
52795		function toShapesNoHoles( inSubpaths ) {
52796
52797			const shapes = [];
52798
52799			for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
52800
52801				const tmpPath = inSubpaths[ i ];
52802
52803				const tmpShape = new Shape();
52804				tmpShape.curves = tmpPath.curves;
52805
52806				shapes.push( tmpShape );
52807
52808			}
52809
52810			return shapes;
52811
52812		}
52813
52814		function isPointInsidePolygon( inPt, inPolygon ) {
52815
52816			const polyLen = inPolygon.length;
52817
52818			// inPt on polygon contour => immediate success    or
52819			// toggling of inside/outside at every single! intersection point of an edge
52820			//  with the horizontal line through inPt, left of inPt
52821			//  not counting lowerY endpoints of edges and whole edges on that line
52822			let inside = false;
52823			for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
52824
52825				let edgeLowPt = inPolygon[ p ];
52826				let edgeHighPt = inPolygon[ q ];
52827
52828				let edgeDx = edgeHighPt.x - edgeLowPt.x;
52829				let edgeDy = edgeHighPt.y - edgeLowPt.y;
52830
52831				if ( Math.abs( edgeDy ) > Number.EPSILON ) {
52832
52833					// not parallel
52834					if ( edgeDy < 0 ) {
52835
52836						edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
52837						edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
52838
52839					}
52840
52841					if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;
52842
52843					if ( inPt.y === edgeLowPt.y ) {
52844
52845						if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
52846						// continue;				// no intersection or edgeLowPt => doesn't count !!!
52847
52848					} else {
52849
52850						const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
52851						if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
52852						if ( perpEdge < 0 ) 				continue;
52853						inside = ! inside;		// true intersection left of inPt
52854
52855					}
52856
52857				} else {
52858
52859					// parallel or collinear
52860					if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
52861					// edge lies on the same horizontal line as inPt
52862					if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
52863						 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
52864					// continue;
52865
52866				}
52867
52868			}
52869
52870			return	inside;
52871
52872		}
52873
52874		const isClockWise = ShapeUtils.isClockWise;
52875
52876		const subPaths = this.subPaths;
52877		if ( subPaths.length === 0 ) return [];
52878
52879		let solid, tmpPath, tmpShape;
52880		const shapes = [];
52881
52882		if ( subPaths.length === 1 ) {
52883
52884			tmpPath = subPaths[ 0 ];
52885			tmpShape = new Shape();
52886			tmpShape.curves = tmpPath.curves;
52887			shapes.push( tmpShape );
52888			return shapes;
52889
52890		}
52891
52892		let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
52893		holesFirst = isCCW ? ! holesFirst : holesFirst;
52894
52895		// console.log("Holes first", holesFirst);
52896
52897		const betterShapeHoles = [];
52898		const newShapes = [];
52899		let newShapeHoles = [];
52900		let mainIdx = 0;
52901		let tmpPoints;
52902
52903		newShapes[ mainIdx ] = undefined;
52904		newShapeHoles[ mainIdx ] = [];
52905
52906		for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
52907
52908			tmpPath = subPaths[ i ];
52909			tmpPoints = tmpPath.getPoints();
52910			solid = isClockWise( tmpPoints );
52911			solid = isCCW ? ! solid : solid;
52912
52913			if ( solid ) {
52914
52915				if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )	mainIdx ++;
52916
52917				newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
52918				newShapes[ mainIdx ].s.curves = tmpPath.curves;
52919
52920				if ( holesFirst )	mainIdx ++;
52921				newShapeHoles[ mainIdx ] = [];
52922
52923				//console.log('cw', i);
52924
52925			} else {
52926
52927				newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
52928
52929				//console.log('ccw', i);
52930
52931			}
52932
52933		}
52934
52935		// only Holes? -> probably all Shapes with wrong orientation
52936		if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
52937
52938
52939		if ( newShapes.length > 1 ) {
52940
52941			let ambiguous = false;
52942			let toChange = 0;
52943
52944			for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52945
52946				betterShapeHoles[ sIdx ] = [];
52947
52948			}
52949
52950			for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52951
52952				const sho = newShapeHoles[ sIdx ];
52953
52954				for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
52955
52956					const ho = sho[ hIdx ];
52957					let hole_unassigned = true;
52958
52959					for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
52960
52961						if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
52962
52963							if ( sIdx !== s2Idx )	toChange ++;
52964
52965							if ( hole_unassigned ) {
52966
52967								hole_unassigned = false;
52968								betterShapeHoles[ s2Idx ].push( ho );
52969
52970							} else {
52971
52972								ambiguous = true;
52973
52974							}
52975
52976						}
52977
52978					}
52979
52980					if ( hole_unassigned ) {
52981
52982						betterShapeHoles[ sIdx ].push( ho );
52983
52984					}
52985
52986				}
52987
52988			}
52989
52990			if ( toChange > 0 && ambiguous === false ) {
52991
52992				newShapeHoles = betterShapeHoles;
52993
52994			}
52995
52996		}
52997
52998		let tmpHoles;
52999
53000		for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
53001
53002			tmpShape = newShapes[ i ].s;
53003			shapes.push( tmpShape );
53004			tmpHoles = newShapeHoles[ i ];
53005
53006			for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
53007
53008				tmpShape.holes.push( tmpHoles[ j ].h );
53009
53010			}
53011
53012		}
53013
53014		//console.log("shape", shapes);
53015
53016		return shapes;
53017
53018	}
53019
53020}
53021
53022if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
53023
53024	__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
53025		revision: REVISION,
53026	} } ) );
53027
53028}
53029
53030if ( typeof window !== 'undefined' ) {
53031
53032	if ( window.__THREE__ ) {
53033
53034		console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
53035
53036	} else {
53037
53038		window.__THREE__ = REVISION;
53039
53040	}
53041
53042}
53043
53044export { 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, C
53044onstantColorFactor, 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, OrthographicCamera, 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, Rever
53044seSubtractEquation, 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.