2 const REVISION = '125';
3 const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
4 const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
5 const CullFaceNone = 0;
6 const CullFaceBack = 1;
7 const CullFaceFront = 2;
8 const CullFaceFrontBack = 3;
9 const BasicShadowMap = 0;
10 const PCFShadowMap = 1;
11 const PCFSoftShadowMap = 2;
12 const VSMShadowMap = 3;
16 const FlatShading = 1;
17 const SmoothShading = 2;
19 const NormalBlending = 1;
20 const AdditiveBlending = 2;
21 const SubtractiveBlending = 3;
22 const MultiplyBlending = 4;
23 const CustomBlending = 5;
24 const AddEquation = 100;
25 const SubtractEquation = 101;
26 const ReverseSubtractEquation = 102;
27 const MinEquation = 103;
28 const MaxEquation = 104;
29 const ZeroFactor = 200;
30 const OneFactor = 201;
31 const SrcColorFactor = 202;
32 const OneMinusSrcColorFactor = 203;
33 const SrcAlphaFactor = 204;
34 const OneMinusSrcAlphaFactor = 205;
35 const DstAlphaFactor = 206;
36 const OneMinusDstAlphaFactor = 207;
37 const DstColorFactor = 208;
38 const OneMinusDstColorFactor = 209;
39 const SrcAlphaSaturateFactor = 210;
41 const AlwaysDepth = 1;
43 const LessEqualDepth = 3;
45 const GreaterEqualDepth = 5;
46 const GreaterDepth = 6;
47 const NotEqualDepth = 7;
48 const MultiplyOperation = 0;
49 const MixOperation = 1;
50 const AddOperation = 2;
51 const NoToneMapping = 0;
52 const LinearToneMapping = 1;
53 const ReinhardToneMapping = 2;
54 const CineonToneMapping = 3;
55 const ACESFilmicToneMapping = 4;
56 const CustomToneMapping = 5;
58 const UVMapping = 300;
59 const CubeReflectionMapping = 301;
60 const CubeRefractionMapping = 302;
61 const EquirectangularReflectionMapping = 303;
62 const EquirectangularRefractionMapping = 304;
63 const CubeUVReflectionMapping = 306;
64 const CubeUVRefractionMapping = 307;
65 const RepeatWrapping = 1000;
66 const ClampToEdgeWrapping = 1001;
67 const MirroredRepeatWrapping = 1002;
68 const NearestFilter = 1003;
69 const NearestMipmapNearestFilter = 1004;
70 const NearestMipMapNearestFilter = 1004;
71 const NearestMipmapLinearFilter = 1005;
72 const NearestMipMapLinearFilter = 1005;
73 const LinearFilter = 1006;
74 const LinearMipmapNearestFilter = 1007;
75 const LinearMipMapNearestFilter = 1007;
76 const LinearMipmapLinearFilter = 1008;
77 const LinearMipMapLinearFilter = 1008;
78 const UnsignedByteType = 1009;
79 const ByteType = 1010;
80 const ShortType = 1011;
81 const UnsignedShortType = 1012;
83 const UnsignedIntType = 1014;
84 const FloatType = 1015;
85 const HalfFloatType = 1016;
86 const UnsignedShort4444Type = 1017;
87 const UnsignedShort5551Type = 1018;
88 const UnsignedShort565Type = 1019;
89 const UnsignedInt248Type = 1020;
90 const AlphaFormat = 1021;
91 const RGBFormat = 1022;
92 const RGBAFormat = 1023;
93 const LuminanceFormat = 1024;
94 const LuminanceAlphaFormat = 1025;
95 const RGBEFormat = RGBAFormat;
96 const DepthFormat = 1026;
97 const DepthStencilFormat = 1027;
98 const RedFormat = 1028;
99 const RedIntegerFormat = 1029;
100 const RGFormat = 1030;
101 const RGIntegerFormat = 1031;
102 const RGBIntegerFormat = 1032;
103 const RGBAIntegerFormat = 1033;
105 const RGB_S3TC_DXT1_Format = 33776;
106 const RGBA_S3TC_DXT1_Format = 33777;
107 const RGBA_S3TC_DXT3_Format = 33778;
108 const RGBA_S3TC_DXT5_Format = 33779;
109 const RGB_PVRTC_4BPPV1_Format = 35840;
110 const RGB_PVRTC_2BPPV1_Format = 35841;
111 const RGBA_PVRTC_4BPPV1_Format = 35842;
112 const RGBA_PVRTC_2BPPV1_Format = 35843;
113 const RGB_ETC1_Format = 36196;
114 const RGB_ETC2_Format = 37492;
115 const RGBA_ETC2_EAC_Format = 37496;
116 const RGBA_ASTC_4x4_Format = 37808;
117 const RGBA_ASTC_5x4_Format = 37809;
118 const RGBA_ASTC_5x5_Format = 37810;
119 const RGBA_ASTC_6x5_Format = 37811;
120 const RGBA_ASTC_6x6_Format = 37812;
121 const RGBA_ASTC_8x5_Format = 37813;
122 const RGBA_ASTC_8x6_Format = 37814;
123 const RGBA_ASTC_8x8_Format = 37815;
124 const RGBA_ASTC_10x5_Format = 37816;
125 const RGBA_ASTC_10x6_Format = 37817;
126 const RGBA_ASTC_10x8_Format = 37818;
127 const RGBA_ASTC_10x10_Format = 37819;
128 const RGBA_ASTC_12x10_Format = 37820;
129 const RGBA_ASTC_12x12_Format = 37821;
130 const RGBA_BPTC_Format = 36492;
131 const SRGB8_ALPHA8_ASTC_4x4_Format = 37840;
132 const SRGB8_ALPHA8_ASTC_5x4_Format = 37841;
133 const SRGB8_ALPHA8_ASTC_5x5_Format = 37842;
134 const SRGB8_ALPHA8_ASTC_6x5_Format = 37843;
135 const SRGB8_ALPHA8_ASTC_6x6_Format = 37844;
136 const SRGB8_ALPHA8_ASTC_8x5_Format = 37845;
137 const SRGB8_ALPHA8_ASTC_8x6_Format = 37846;
138 const SRGB8_ALPHA8_ASTC_8x8_Format = 37847;
139 const SRGB8_ALPHA8_ASTC_10x5_Format = 37848;
140 const SRGB8_ALPHA8_ASTC_10x6_Format = 37849;
141 const SRGB8_ALPHA8_ASTC_10x8_Format = 37850;
142 const SRGB8_ALPHA8_ASTC_10x10_Format = 37851;
143 const SRGB8_ALPHA8_ASTC_12x10_Format = 37852;
144 const SRGB8_ALPHA8_ASTC_12x12_Format = 37853;
145 const LoopOnce = 2200;
146 const LoopRepeat = 2201;
147 const LoopPingPong = 2202;
148 const InterpolateDiscrete = 2300;
149 const InterpolateLinear = 2301;
150 const InterpolateSmooth = 2302;
151 const ZeroCurvatureEnding = 2400;
152 const ZeroSlopeEnding = 2401;
153 const WrapAroundEnding = 2402;
154 const NormalAnimationBlendMode = 2500;
155 const AdditiveAnimationBlendMode = 2501;
156 const TrianglesDrawMode = 0;
157 const TriangleStripDrawMode = 1;
158 const TriangleFanDrawMode = 2;
159 const LinearEncoding = 3000;
160 const sRGBEncoding = 3001;
161 const GammaEncoding = 3007;
162 const RGBEEncoding = 3002;
163 const LogLuvEncoding = 3003;
164 const RGBM7Encoding = 3004;
165 const RGBM16Encoding = 3005;
166 const RGBDEncoding = 3006;
167 const BasicDepthPacking = 3200;
168 const RGBADepthPacking = 3201;
169 const TangentSpaceNormalMap = 0;
170 const ObjectSpaceNormalMap = 1;
172 const ZeroStencilOp = 0;
173 const KeepStencilOp = 7680;
174 const ReplaceStencilOp = 7681;
175 const IncrementStencilOp = 7682;
176 const DecrementStencilOp = 7683;
177 const IncrementWrapStencilOp = 34055;
178 const DecrementWrapStencilOp = 34056;
179 const InvertStencilOp = 5386;
181 const NeverStencilFunc = 512;
182 const LessStencilFunc = 513;
183 const EqualStencilFunc = 514;
184 const LessEqualStencilFunc = 515;
185 const GreaterStencilFunc = 516;
186 const NotEqualStencilFunc = 517;
187 const GreaterEqualStencilFunc = 518;
188 const AlwaysStencilFunc = 519;
190 const StaticDrawUsage = 35044;
191 const DynamicDrawUsage = 35048;
192 const StreamDrawUsage = 35040;
193 const StaticReadUsage = 35045;
194 const DynamicReadUsage = 35049;
195 const StreamReadUsage = 35041;
196 const StaticCopyUsage = 35046;
197 const DynamicCopyUsage = 35050;
198 const StreamCopyUsage = 35042;
201 const GLSL3 = '300 es';
204 * https://github.com/mrdoob/eventdispatcher.js/
207 function EventDispatcher() {}
209 Object.assign( EventDispatcher.prototype, {
211 addEventListener: function ( type, listener ) {
213 if ( this._listeners === undefined ) this._listeners = {};
215 const listeners = this._listeners;
217 if ( listeners[ type ] === undefined ) {
219 listeners[ type ] = [];
223 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
225 listeners[ type ].push( listener );
231 hasEventListener: function ( type, listener ) {
233 if ( this._listeners === undefined ) return false;
235 const listeners = this._listeners;
237 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
241 removeEventListener: function ( type, listener ) {
243 if ( this._listeners === undefined ) return;
245 const listeners = this._listeners;
246 const listenerArray = listeners[ type ];
248 if ( listenerArray !== undefined ) {
250 const index = listenerArray.indexOf( listener );
252 if ( index !== - 1 ) {
254 listenerArray.splice( index, 1 );
262 dispatchEvent: function ( event ) {
264 if ( this._listeners === undefined ) return;
266 const listeners = this._listeners;
267 const listenerArray = listeners[ event.type ];
269 if ( listenerArray !== undefined ) {
273 // Make a copy, in case listeners are removed while iterating.
274 const array = listenerArray.slice( 0 );
276 for ( let i = 0, l = array.length; i < l; i ++ ) {
278 array[ i ].call( this, event );
290 for ( let i = 0; i < 256; i ++ ) {
292 _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
300 DEG2RAD: Math.PI / 180,
301 RAD2DEG: 180 / Math.PI,
303 generateUUID: function () {
305 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
307 const d0 = Math.random() * 0xffffffff | 0;
308 const d1 = Math.random() * 0xffffffff | 0;
309 const d2 = Math.random() * 0xffffffff | 0;
310 const d3 = Math.random() * 0xffffffff | 0;
311 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
312 _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
313 _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
314 _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
316 // .toUpperCase() here flattens concatenated strings to save heap memory space.
317 return uuid.toUpperCase();
321 clamp: function ( value, min, max ) {
323 return Math.max( min, Math.min( max, value ) );
327 // compute euclidian modulo of m % n
328 // https://en.wikipedia.org/wiki/Modulo_operation
330 euclideanModulo: function ( n, m ) {
332 return ( ( n % m ) + m ) % m;
336 // Linear mapping from range <a1, a2> to range <b1, b2>
338 mapLinear: function ( x, a1, a2, b1, b2 ) {
340 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
344 // https://en.wikipedia.org/wiki/Linear_interpolation
346 lerp: function ( x, y, t ) {
348 return ( 1 - t ) * x + t * y;
352 // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
354 damp: function ( x, y, lambda, dt ) {
356 return MathUtils.lerp( x, y, 1 - Math.exp( - lambda * dt ) );
360 // https://www.desmos.com/calculator/vcsjnyz7x4
362 pingpong: function ( x, length = 1 ) {
364 return length - Math.abs( MathUtils.euclideanModulo( x, length * 2 ) - length );
368 // http://en.wikipedia.org/wiki/Smoothstep
370 smoothstep: function ( x, min, max ) {
372 if ( x <= min ) return 0;
373 if ( x >= max ) return 1;
375 x = ( x - min ) / ( max - min );
377 return x * x * ( 3 - 2 * x );
381 smootherstep: function ( x, min, max ) {
383 if ( x <= min ) return 0;
384 if ( x >= max ) return 1;
386 x = ( x - min ) / ( max - min );
388 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
392 // Random integer from <low, high> interval
394 randInt: function ( low, high ) {
396 return low + Math.floor( Math.random() * ( high - low + 1 ) );
400 // Random float from <low, high> interval
402 randFloat: function ( low, high ) {
404 return low + Math.random() * ( high - low );
408 // Random float from <-range/2, range/2> interval
410 randFloatSpread: function ( range ) {
412 return range * ( 0.5 - Math.random() );
416 // Deterministic pseudo-random float in the interval [ 0, 1 ]
418 seededRandom: function ( s ) {
420 if ( s !== undefined ) _seed = s % 2147483647;
422 // Park-Miller algorithm
424 _seed = _seed * 16807 % 2147483647;
426 return ( _seed - 1 ) / 2147483646;
430 degToRad: function ( degrees ) {
432 return degrees * MathUtils.DEG2RAD;
436 radToDeg: function ( radians ) {
438 return radians * MathUtils.RAD2DEG;
442 isPowerOfTwo: function ( value ) {
444 return ( value & ( value - 1 ) ) === 0 && value !== 0;
448 ceilPowerOfTwo: function ( value ) {
450 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
454 floorPowerOfTwo: function ( value ) {
456 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
460 setQuaternionFromProperEuler: function ( q, a, b, c, order ) {
462 // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
464 // rotations are applied to the axes in the order specified by 'order'
465 // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
466 // angles are in radians
468 const cos = Math.cos;
469 const sin = Math.sin;
471 const c2 = cos( b / 2 );
472 const s2 = sin( b / 2 );
474 const c13 = cos( ( a + c ) / 2 );
475 const s13 = sin( ( a + c ) / 2 );
477 const c1_3 = cos( ( a - c ) / 2 );
478 const s1_3 = sin( ( a - c ) / 2 );
480 const c3_1 = cos( ( c - a ) / 2 );
481 const s3_1 = sin( ( c - a ) / 2 );
486 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
490 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
494 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
498 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
502 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
506 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
510 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
520 constructor( x = 0, y = 0 ) {
522 Object.defineProperty( this, 'isVector2', { value: true } );
547 set height( value ) {
562 setScalar( scalar ) {
587 setComponent( index, value ) {
591 case 0: this.x = value; break;
592 case 1: this.y = value; break;
593 default: throw new Error( 'index is out of range: ' + index );
601 getComponent( index ) {
605 case 0: return this.x;
606 case 1: return this.y;
607 default: throw new Error( 'index is out of range: ' + index );
615 return new this.constructor( this.x, this.y );
630 if ( w !== undefined ) {
632 console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
633 return this.addVectors( v, w );
662 addScaledVector( v, s ) {
673 if ( w !== undefined ) {
675 console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
676 return this.subVectors( v, w );
714 multiplyScalar( scalar ) {
732 divideScalar( scalar ) {
734 return this.multiplyScalar( 1 / scalar );
740 const x = this.x, y = this.y;
741 const e = m.elements;
743 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
744 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
752 this.x = Math.min( this.x, v.x );
753 this.y = Math.min( this.y, v.y );
761 this.x = Math.max( this.x, v.x );
762 this.y = Math.max( this.y, v.y );
770 // assumes min < max, componentwise
772 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
773 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
779 clampScalar( minVal, maxVal ) {
781 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
782 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
788 clampLength( min, max ) {
790 const length = this.length();
792 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
798 this.x = Math.floor( this.x );
799 this.y = Math.floor( this.y );
807 this.x = Math.ceil( this.x );
808 this.y = Math.ceil( this.y );
816 this.x = Math.round( this.x );
817 this.y = Math.round( this.y );
825 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
826 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
843 return this.x * v.x + this.y * v.y;
849 return this.x * v.y - this.y * v.x;
855 return this.x * this.x + this.y * this.y;
861 return Math.sqrt( this.x * this.x + this.y * this.y );
867 return Math.abs( this.x ) + Math.abs( this.y );
873 return this.divideScalar( this.length() || 1 );
879 // computes the angle in radians with respect to the positive x-axis
881 const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
889 return Math.sqrt( this.distanceToSquared( v ) );
893 distanceToSquared( v ) {
895 const dx = this.x - v.x, dy = this.y - v.y;
896 return dx * dx + dy * dy;
900 manhattanDistanceTo( v ) {
902 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
906 setLength( length ) {
908 return this.normalize().multiplyScalar( length );
914 this.x += ( v.x - this.x ) * alpha;
915 this.y += ( v.y - this.y ) * alpha;
921 lerpVectors( v1, v2, alpha ) {
923 this.x = v1.x + ( v2.x - v1.x ) * alpha;
924 this.y = v1.y + ( v2.y - v1.y ) * alpha;
932 return ( ( v.x === this.x ) && ( v.y === this.y ) );
936 fromArray( array, offset = 0 ) {
938 this.x = array[ offset ];
939 this.y = array[ offset + 1 ];
945 toArray( array = [], offset = 0 ) {
947 array[ offset ] = this.x;
948 array[ offset + 1 ] = this.y;
954 fromBufferAttribute( attribute, index, offset ) {
956 if ( offset !== undefined ) {
958 console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
962 this.x = attribute.getX( index );
963 this.y = attribute.getY( index );
969 rotateAround( center, angle ) {
971 const c = Math.cos( angle ), s = Math.sin( angle );
973 const x = this.x - center.x;
974 const y = this.y - center.y;
976 this.x = x * c - y * s + center.x;
977 this.y = x * s + y * c + center.y;
985 this.x = Math.random();
986 this.y = Math.random();
998 Object.defineProperty( this, 'isMatrix3', { value: true } );
1008 if ( arguments.length > 0 ) {
1010 console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
1016 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1018 const te = this.elements;
1020 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
1021 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
1022 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
1044 return new this.constructor().fromArray( this.elements );
1050 const te = this.elements;
1051 const me = m.elements;
1053 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
1054 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
1055 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
1061 extractBasis( xAxis, yAxis, zAxis ) {
1063 xAxis.setFromMatrix3Column( this, 0 );
1064 yAxis.setFromMatrix3Column( this, 1 );
1065 zAxis.setFromMatrix3Column( this, 2 );
1071 setFromMatrix4( m ) {
1073 const me = m.elements;
1077 me[ 0 ], me[ 4 ], me[ 8 ],
1078 me[ 1 ], me[ 5 ], me[ 9 ],
1079 me[ 2 ], me[ 6 ], me[ 10 ]
1089 return this.multiplyMatrices( this, m );
1095 return this.multiplyMatrices( m, this );
1099 multiplyMatrices( a, b ) {
1101 const ae = a.elements;
1102 const be = b.elements;
1103 const te = this.elements;
1105 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
1106 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
1107 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
1109 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
1110 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
1111 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
1113 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
1114 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
1115 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
1117 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
1118 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
1119 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
1121 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
1122 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
1123 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
1129 multiplyScalar( s ) {
1131 const te = this.elements;
1133 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
1134 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
1135 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
1143 const te = this.elements;
1145 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
1146 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
1147 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
1149 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
1155 const te = this.elements,
1157 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
1158 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
1159 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
1161 t11 = n33 * n22 - n32 * n23,
1162 t12 = n32 * n13 - n33 * n12,
1163 t13 = n23 * n12 - n22 * n13,
1165 det = n11 * t11 + n21 * t12 + n31 * t13;
1167 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1169 const detInv = 1 / det;
1171 te[ 0 ] = t11 * detInv;
1172 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
1173 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
1175 te[ 3 ] = t12 * detInv;
1176 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
1177 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
1179 te[ 6 ] = t13 * detInv;
1180 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
1181 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
1190 const m = this.elements;
1192 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
1193 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
1194 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
1200 getNormalMatrix( matrix4 ) {
1202 return this.setFromMatrix4( matrix4 ).copy( this ).invert().transpose();
1206 transposeIntoArray( r ) {
1208 const m = this.elements;
1224 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
1226 const c = Math.cos( rotation );
1227 const s = Math.sin( rotation );
1230 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
1231 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
1241 const te = this.elements;
1243 te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
1244 te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
1252 const c = Math.cos( theta );
1253 const s = Math.sin( theta );
1255 const te = this.elements;
1257 const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
1258 const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
1260 te[ 0 ] = c * a11 + s * a21;
1261 te[ 3 ] = c * a12 + s * a22;
1262 te[ 6 ] = c * a13 + s * a23;
1264 te[ 1 ] = - s * a11 + c * a21;
1265 te[ 4 ] = - s * a12 + c * a22;
1266 te[ 7 ] = - s * a13 + c * a23;
1272 translate( tx, ty ) {
1274 const te = this.elements;
1276 te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
1277 te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
1285 const te = this.elements;
1286 const me = matrix.elements;
1288 for ( let i = 0; i < 9; i ++ ) {
1290 if ( te[ i ] !== me[ i ] ) return false;
1298 fromArray( array, offset = 0 ) {
1300 for ( let i = 0; i < 9; i ++ ) {
1302 this.elements[ i ] = array[ i + offset ];
1310 toArray( array = [], offset = 0 ) {
1312 const te = this.elements;
1314 array[ offset ] = te[ 0 ];
1315 array[ offset + 1 ] = te[ 1 ];
1316 array[ offset + 2 ] = te[ 2 ];
1318 array[ offset + 3 ] = te[ 3 ];
1319 array[ offset + 4 ] = te[ 4 ];
1320 array[ offset + 5 ] = te[ 5 ];
1322 array[ offset + 6 ] = te[ 6 ];
1323 array[ offset + 7 ] = te[ 7 ];
1324 array[ offset + 8 ] = te[ 8 ];
1334 const ImageUtils = {
1336 getDataURL: function ( image ) {
1338 if ( /^data:/i.test( image.src ) ) {
1344 if ( typeof HTMLCanvasElement == 'undefined' ) {
1352 if ( image instanceof HTMLCanvasElement ) {
1358 if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
1360 _canvas.width = image.width;
1361 _canvas.height = image.height;
1363 const context = _canvas.getContext( '2d' );
1365 if ( image instanceof ImageData ) {
1367 context.putImageData( image, 0, 0 );
1371 context.drawImage( image, 0, 0, image.width, image.height );
1379 if ( canvas.width > 2048 || canvas.height > 2048 ) {
1381 return canvas.toDataURL( 'image/jpeg', 0.6 );
1385 return canvas.toDataURL( 'image/png' );
1395 function Texture( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) {
1397 Object.defineProperty( this, 'id', { value: textureId ++ } );
1399 this.uuid = MathUtils.generateUUID();
1406 this.mapping = mapping;
1411 this.magFilter = magFilter;
1412 this.minFilter = minFilter;
1414 this.anisotropy = anisotropy;
1416 this.format = format;
1417 this.internalFormat = null;
1420 this.offset = new Vector2( 0, 0 );
1421 this.repeat = new Vector2( 1, 1 );
1422 this.center = new Vector2( 0, 0 );
1425 this.matrixAutoUpdate = true;
1426 this.matrix = new Matrix3();
1428 this.generateMipmaps = true;
1429 this.premultiplyAlpha = false;
1431 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
1433 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
1435 // Also changing the encoding after already used by a Material will not automatically make the Material
1436 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
1437 this.encoding = encoding;
1440 this.onUpdate = null;
1444 Texture.DEFAULT_IMAGE = undefined;
1445 Texture.DEFAULT_MAPPING = UVMapping;
1447 Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
1449 constructor: Texture,
1453 updateMatrix: function () {
1455 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
1459 clone: function () {
1461 return new this.constructor().copy( this );
1465 copy: function ( source ) {
1467 this.name = source.name;
1469 this.image = source.image;
1470 this.mipmaps = source.mipmaps.slice( 0 );
1472 this.mapping = source.mapping;
1474 this.wrapS = source.wrapS;
1475 this.wrapT = source.wrapT;
1477 this.magFilter = source.magFilter;
1478 this.minFilter = source.minFilter;
1480 this.anisotropy = source.anisotropy;
1482 this.format = source.format;
1483 this.internalFormat = source.internalFormat;
1484 this.type = source.type;
1486 this.offset.copy( source.offset );
1487 this.repeat.copy( source.repeat );
1488 this.center.copy( source.center );
1489 this.rotation = source.rotation;
1491 this.matrixAutoUpdate = source.matrixAutoUpdate;
1492 this.matrix.copy( source.matrix );
1494 this.generateMipmaps = source.generateMipmaps;
1495 this.premultiplyAlpha = source.premultiplyAlpha;
1496 this.flipY = source.flipY;
1497 this.unpackAlignment = source.unpackAlignment;
1498 this.encoding = source.encoding;
1504 toJSON: function ( meta ) {
1506 const isRootObject = ( meta === undefined || typeof meta === 'string' );
1508 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
1510 return meta.textures[ this.uuid ];
1519 generator: 'Texture.toJSON'
1525 mapping: this.mapping,
1527 repeat: [ this.repeat.x, this.repeat.y ],
1528 offset: [ this.offset.x, this.offset.y ],
1529 center: [ this.center.x, this.center.y ],
1530 rotation: this.rotation,
1532 wrap: [ this.wrapS, this.wrapT ],
1534 format: this.format,
1536 encoding: this.encoding,
1538 minFilter: this.minFilter,
1539 magFilter: this.magFilter,
1540 anisotropy: this.anisotropy,
1544 premultiplyAlpha: this.premultiplyAlpha,
1545 unpackAlignment: this.unpackAlignment
1549 if ( this.image !== undefined ) {
1551 // TODO: Move to THREE.Image
1553 const image = this.image;
1555 if ( image.uuid === undefined ) {
1557 image.uuid = MathUtils.generateUUID(); // UGH
1561 if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
1565 if ( Array.isArray( image ) ) {
1567 // process array of images e.g. CubeTexture
1571 for ( let i = 0, l = image.length; i < l; i ++ ) {
1573 // check cube texture with data textures
1575 if ( image[ i ].isDataTexture ) {
1577 url.push( serializeImage( image[ i ].image ) );
1581 url.push( serializeImage( image[ i ] ) );
1589 // process single image
1591 url = serializeImage( image );
1595 meta.images[ image.uuid ] = {
1602 output.image = image.uuid;
1606 if ( ! isRootObject ) {
1608 meta.textures[ this.uuid ] = output;
1616 dispose: function () {
1618 this.dispatchEvent( { type: 'dispose' } );
1622 transformUv: function ( uv ) {
1624 if ( this.mapping !== UVMapping ) return uv;
1626 uv.applyMatrix3( this.matrix );
1628 if ( uv.x < 0 || uv.x > 1 ) {
1630 switch ( this.wrapS ) {
1632 case RepeatWrapping:
1634 uv.x = uv.x - Math.floor( uv.x );
1637 case ClampToEdgeWrapping:
1639 uv.x = uv.x < 0 ? 0 : 1;
1642 case MirroredRepeatWrapping:
1644 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
1646 uv.x = Math.ceil( uv.x ) - uv.x;
1650 uv.x = uv.x - Math.floor( uv.x );
1660 if ( uv.y < 0 || uv.y > 1 ) {
1662 switch ( this.wrapT ) {
1664 case RepeatWrapping:
1666 uv.y = uv.y - Math.floor( uv.y );
1669 case ClampToEdgeWrapping:
1671 uv.y = uv.y < 0 ? 0 : 1;
1674 case MirroredRepeatWrapping:
1676 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
1678 uv.y = Math.ceil( uv.y ) - uv.y;
1682 uv.y = uv.y - Math.floor( uv.y );
1704 Object.defineProperty( Texture.prototype, 'needsUpdate', {
1706 set: function ( value ) {
1708 if ( value === true ) this.version ++;
1714 function serializeImage( image ) {
1716 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1717 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
1718 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1722 return ImageUtils.getDataURL( image );
1728 // images of DataTexture
1731 data: Array.prototype.slice.call( image.data ),
1733 height: image.height,
1734 type: image.data.constructor.name
1739 console.warn( 'THREE.Texture: Unable to serialize Texture.' );
1750 constructor( x = 0, y = 0, z = 0, w = 1 ) {
1752 Object.defineProperty( this, 'isVector4', { value: true } );
1767 set width( value ) {
1779 set height( value ) {
1796 setScalar( scalar ) {
1839 setComponent( index, value ) {
1843 case 0: this.x = value; break;
1844 case 1: this.y = value; break;
1845 case 2: this.z = value; break;
1846 case 3: this.w = value; break;
1847 default: throw new Error( 'index is out of range: ' + index );
1855 getComponent( index ) {
1859 case 0: return this.x;
1860 case 1: return this.y;
1861 case 2: return this.z;
1862 case 3: return this.w;
1863 default: throw new Error( 'index is out of range: ' + index );
1871 return new this.constructor( this.x, this.y, this.z, this.w );
1880 this.w = ( v.w !== undefined ) ? v.w : 1;
1888 if ( w !== undefined ) {
1890 console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
1891 return this.addVectors( v, w );
1915 addVectors( a, b ) {
1926 addScaledVector( v, s ) {
1939 if ( w !== undefined ) {
1941 console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
1942 return this.subVectors( v, w );
1966 subVectors( a, b ) {
1988 multiplyScalar( scalar ) {
2001 const x = this.x, y = this.y, z = this.z, w = this.w;
2002 const e = m.elements;
2004 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
2005 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
2006 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
2007 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
2013 divideScalar( scalar ) {
2015 return this.multiplyScalar( 1 / scalar );
2019 setAxisAngleFromQuaternion( q ) {
2021 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
2023 // q is assumed to be normalized
2025 this.w = 2 * Math.acos( q.w );
2027 const s = Math.sqrt( 1 - q.w * q.w );
2047 setAxisAngleFromRotationMatrix( m ) {
2049 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
2051 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2053 let angle, x, y, z; // variables for result
2054 const epsilon = 0.01, // margin to allow for rounding errors
2055 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
2059 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2060 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2061 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
2063 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
2064 ( Math.abs( m13 - m31 ) < epsilon ) &&
2065 ( Math.abs( m23 - m32 ) < epsilon ) ) {
2067 // singularity found
2068 // first check for identity matrix which must have +1 for all terms
2069 // in leading diagonal and zero in other terms
2071 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
2072 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
2073 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
2074 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
2076 // this singularity is identity matrix so angle = 0
2078 this.set( 1, 0, 0, 0 );
2080 return this; // zero angle, arbitrary axis
2084 // otherwise this singularity is angle = 180
2088 const xx = ( m11 + 1 ) / 2;
2089 const yy = ( m22 + 1 ) / 2;
2090 const zz = ( m33 + 1 ) / 2;
2091 const xy = ( m12 + m21 ) / 4;
2092 const xz = ( m13 + m31 ) / 4;
2093 const yz = ( m23 + m32 ) / 4;
2095 if ( ( xx > yy ) && ( xx > zz ) ) {
2097 // m11 is the largest diagonal term
2099 if ( xx < epsilon ) {
2107 x = Math.sqrt( xx );
2113 } else if ( yy > zz ) {
2115 // m22 is the largest diagonal term
2117 if ( yy < epsilon ) {
2125 y = Math.sqrt( yy );
2133 // m33 is the largest diagonal term so base result on this
2135 if ( zz < epsilon ) {
2143 z = Math.sqrt( zz );
2151 this.set( x, y, z, angle );
2153 return this; // return 180 deg rotation
2157 // as we have reached here there are no singularities so we can handle normally
2159 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
2160 ( m13 - m31 ) * ( m13 - m31 ) +
2161 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
2163 if ( Math.abs( s ) < 0.001 ) s = 1;
2165 // prevent divide by zero, should not happen if matrix is orthogonal and should be
2166 // caught by singularity test above, but I've left it in just in case
2168 this.x = ( m32 - m23 ) / s;
2169 this.y = ( m13 - m31 ) / s;
2170 this.z = ( m21 - m12 ) / s;
2171 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
2179 this.x = Math.min( this.x, v.x );
2180 this.y = Math.min( this.y, v.y );
2181 this.z = Math.min( this.z, v.z );
2182 this.w = Math.min( this.w, v.w );
2190 this.x = Math.max( this.x, v.x );
2191 this.y = Math.max( this.y, v.y );
2192 this.z = Math.max( this.z, v.z );
2193 this.w = Math.max( this.w, v.w );
2201 // assumes min < max, componentwise
2203 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2204 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2205 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
2206 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
2212 clampScalar( minVal, maxVal ) {
2214 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
2215 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
2216 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
2217 this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
2223 clampLength( min, max ) {
2225 const length = this.length();
2227 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
2233 this.x = Math.floor( this.x );
2234 this.y = Math.floor( this.y );
2235 this.z = Math.floor( this.z );
2236 this.w = Math.floor( this.w );
2244 this.x = Math.ceil( this.x );
2245 this.y = Math.ceil( this.y );
2246 this.z = Math.ceil( this.z );
2247 this.w = Math.ceil( this.w );
2255 this.x = Math.round( this.x );
2256 this.y = Math.round( this.y );
2257 this.z = Math.round( this.z );
2258 this.w = Math.round( this.w );
2266 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
2267 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
2268 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
2269 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
2288 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
2294 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
2300 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
2306 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
2312 return this.divideScalar( this.length() || 1 );
2316 setLength( length ) {
2318 return this.normalize().multiplyScalar( length );
2324 this.x += ( v.x - this.x ) * alpha;
2325 this.y += ( v.y - this.y ) * alpha;
2326 this.z += ( v.z - this.z ) * alpha;
2327 this.w += ( v.w - this.w ) * alpha;
2333 lerpVectors( v1, v2, alpha ) {
2335 this.x = v1.x + ( v2.x - v1.x ) * alpha;
2336 this.y = v1.y + ( v2.y - v1.y ) * alpha;
2337 this.z = v1.z + ( v2.z - v1.z ) * alpha;
2338 this.w = v1.w + ( v2.w - v1.w ) * alpha;
2346 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
2350 fromArray( array, offset = 0 ) {
2352 this.x = array[ offset ];
2353 this.y = array[ offset + 1 ];
2354 this.z = array[ offset + 2 ];
2355 this.w = array[ offset + 3 ];
2361 toArray( array = [], offset = 0 ) {
2363 array[ offset ] = this.x;
2364 array[ offset + 1 ] = this.y;
2365 array[ offset + 2 ] = this.z;
2366 array[ offset + 3 ] = this.w;
2372 fromBufferAttribute( attribute, index, offset ) {
2374 if ( offset !== undefined ) {
2376 console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
2380 this.x = attribute.getX( index );
2381 this.y = attribute.getY( index );
2382 this.z = attribute.getZ( index );
2383 this.w = attribute.getW( index );
2391 this.x = Math.random();
2392 this.y = Math.random();
2393 this.z = Math.random();
2394 this.w = Math.random();
2403 In options, we can specify:
2404 * Texture parameters for an auto-generated target texture
2405 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
2407 class WebGLRenderTarget extends EventDispatcher {
2409 constructor( width, height, options ) {
2413 Object.defineProperty( this, 'isWebGLRenderTarget', { value: true } );
2416 this.height = height;
2418 this.scissor = new Vector4( 0, 0, width, height );
2419 this.scissorTest = false;
2421 this.viewport = new Vector4( 0, 0, width, height );
2423 options = options || {};
2425 this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
2427 this.texture.image = {};
2428 this.texture.image.width = width;
2429 this.texture.image.height = height;
2431 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
2432 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
2434 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
2435 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
2436 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
2440 setSize( width, height ) {
2442 if ( this.width !== width || this.height !== height ) {
2445 this.height = height;
2447 this.texture.image.width = width;
2448 this.texture.image.height = height;
2454 this.viewport.set( 0, 0, width, height );
2455 this.scissor.set( 0, 0, width, height );
2461 return new this.constructor().copy( this );
2467 this.width = source.width;
2468 this.height = source.height;
2470 this.viewport.copy( source.viewport );
2472 this.texture = source.texture.clone();
2474 this.depthBuffer = source.depthBuffer;
2475 this.stencilBuffer = source.stencilBuffer;
2476 this.depthTexture = source.depthTexture;
2484 this.dispatchEvent( { type: 'dispose' } );
2490 class WebGLMultisampleRenderTarget extends WebGLRenderTarget {
2492 constructor( width, height, options ) {
2494 super( width, height, options );
2496 Object.defineProperty( this, 'isWebGLMultisampleRenderTarget', { value: true } );
2504 super.copy.call( this, source );
2506 this.samples = source.samples;
2516 constructor( x = 0, y = 0, z = 0, w = 1 ) {
2518 Object.defineProperty( this, 'isQuaternion', { value: true } );
2527 static slerp( qa, qb, qm, t ) {
2529 return qm.copy( qa ).slerp( qb, t );
2533 static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
2535 // fuzz-free, array-based Quaternion SLERP operation
2537 let x0 = src0[ srcOffset0 + 0 ],
2538 y0 = src0[ srcOffset0 + 1 ],
2539 z0 = src0[ srcOffset0 + 2 ],
2540 w0 = src0[ srcOffset0 + 3 ];
2542 const x1 = src1[ srcOffset1 + 0 ],
2543 y1 = src1[ srcOffset1 + 1 ],
2544 z1 = src1[ srcOffset1 + 2 ],
2545 w1 = src1[ srcOffset1 + 3 ];
2547 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
2550 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
2551 dir = ( cos >= 0 ? 1 : - 1 ),
2552 sqrSin = 1 - cos * cos;
2554 // Skip the Slerp for tiny steps to avoid numeric problems:
2555 if ( sqrSin > Number.EPSILON ) {
2557 const sin = Math.sqrt( sqrSin ),
2558 len = Math.atan2( sin, cos * dir );
2560 s = Math.sin( s * len ) / sin;
2561 t = Math.sin( t * len ) / sin;
2565 const tDir = t * dir;
2567 x0 = x0 * s + x1 * tDir;
2568 y0 = y0 * s + y1 * tDir;
2569 z0 = z0 * s + z1 * tDir;
2570 w0 = w0 * s + w1 * tDir;
2572 // Normalize in case we just did a lerp:
2573 if ( s === 1 - t ) {
2575 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
2586 dst[ dstOffset ] = x0;
2587 dst[ dstOffset + 1 ] = y0;
2588 dst[ dstOffset + 2 ] = z0;
2589 dst[ dstOffset + 3 ] = w0;
2593 static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
2595 const x0 = src0[ srcOffset0 ];
2596 const y0 = src0[ srcOffset0 + 1 ];
2597 const z0 = src0[ srcOffset0 + 2 ];
2598 const w0 = src0[ srcOffset0 + 3 ];
2600 const x1 = src1[ srcOffset1 ];
2601 const y1 = src1[ srcOffset1 + 1 ];
2602 const z1 = src1[ srcOffset1 + 2 ];
2603 const w1 = src1[ srcOffset1 + 3 ];
2605 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
2606 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
2607 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
2608 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
2623 this._onChangeCallback();
2636 this._onChangeCallback();
2649 this._onChangeCallback();
2662 this._onChangeCallback();
2673 this._onChangeCallback();
2681 return new this.constructor( this._x, this._y, this._z, this._w );
2685 copy( quaternion ) {
2687 this._x = quaternion.x;
2688 this._y = quaternion.y;
2689 this._z = quaternion.z;
2690 this._w = quaternion.w;
2692 this._onChangeCallback();
2698 setFromEuler( euler, update ) {
2700 if ( ! ( euler && euler.isEuler ) ) {
2702 throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
2706 const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
2708 // http://www.mathworks.com/matlabcentral/fileexchange/
2709 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
2710 // content/SpinCalc.m
2712 const cos = Math.cos;
2713 const sin = Math.sin;
2715 const c1 = cos( x / 2 );
2716 const c2 = cos( y / 2 );
2717 const c3 = cos( z / 2 );
2719 const s1 = sin( x / 2 );
2720 const s2 = sin( y / 2 );
2721 const s3 = sin( z / 2 );
2726 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2727 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2728 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2729 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2733 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2734 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2735 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2736 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2740 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2741 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2742 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2743 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2747 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2748 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2749 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2750 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2754 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2755 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2756 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2757 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2761 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2762 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2763 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2764 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2768 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
2772 if ( update !== false ) this._onChangeCallback();
2778 setFromAxisAngle( axis, angle ) {
2780 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
2782 // assumes axis is normalized
2784 const halfAngle = angle / 2, s = Math.sin( halfAngle );
2786 this._x = axis.x * s;
2787 this._y = axis.y * s;
2788 this._z = axis.z * s;
2789 this._w = Math.cos( halfAngle );
2791 this._onChangeCallback();
2797 setFromRotationMatrix( m ) {
2799 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
2801 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2803 const te = m.elements,
2805 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2806 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2807 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
2809 trace = m11 + m22 + m33;
2813 const s = 0.5 / Math.sqrt( trace + 1.0 );
2816 this._x = ( m32 - m23 ) * s;
2817 this._y = ( m13 - m31 ) * s;
2818 this._z = ( m21 - m12 ) * s;
2820 } else if ( m11 > m22 && m11 > m33 ) {
2822 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
2824 this._w = ( m32 - m23 ) / s;
2826 this._y = ( m12 + m21 ) / s;
2827 this._z = ( m13 + m31 ) / s;
2829 } else if ( m22 > m33 ) {
2831 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
2833 this._w = ( m13 - m31 ) / s;
2834 this._x = ( m12 + m21 ) / s;
2836 this._z = ( m23 + m32 ) / s;
2840 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
2842 this._w = ( m21 - m12 ) / s;
2843 this._x = ( m13 + m31 ) / s;
2844 this._y = ( m23 + m32 ) / s;
2849 this._onChangeCallback();
2855 setFromUnitVectors( vFrom, vTo ) {
2857 // assumes direction vectors vFrom and vTo are normalized
2859 const EPS = 0.000001;
2861 let r = vFrom.dot( vTo ) + 1;
2867 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
2869 this._x = - vFrom.y;
2877 this._y = - vFrom.z;
2885 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
2887 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
2888 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
2889 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
2894 return this.normalize();
2900 return 2 * Math.acos( Math.abs( MathUtils.clamp( this.dot( q ), - 1, 1 ) ) );
2904 rotateTowards( q, step ) {
2906 const angle = this.angleTo( q );
2908 if ( angle === 0 ) return this;
2910 const t = Math.min( 1, step / angle );
2920 return this.set( 0, 0, 0, 1 );
2926 // quaternion is assumed to have unit length
2928 return this.conjugate();
2938 this._onChangeCallback();
2946 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
2952 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
2958 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
2964 let l = this.length();
2977 this._x = this._x * l;
2978 this._y = this._y * l;
2979 this._z = this._z * l;
2980 this._w = this._w * l;
2984 this._onChangeCallback();
2992 if ( p !== undefined ) {
2994 console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
2995 return this.multiplyQuaternions( q, p );
2999 return this.multiplyQuaternions( this, q );
3005 return this.multiplyQuaternions( q, this );
3009 multiplyQuaternions( a, b ) {
3011 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
3013 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
3014 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
3016 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
3017 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
3018 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
3019 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
3021 this._onChangeCallback();
3029 if ( t === 0 ) return this;
3030 if ( t === 1 ) return this.copy( qb );
3032 const x = this._x, y = this._y, z = this._z, w = this._w;
3034 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
3036 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
3038 if ( cosHalfTheta < 0 ) {
3045 cosHalfTheta = - cosHalfTheta;
3053 if ( cosHalfTheta >= 1.0 ) {
3064 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
3066 if ( sqrSinHalfTheta <= Number.EPSILON ) {
3069 this._w = s * w + t * this._w;
3070 this._x = s * x + t * this._x;
3071 this._y = s * y + t * this._y;
3072 this._z = s * z + t * this._z;
3075 this._onChangeCallback();
3081 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
3082 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
3083 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
3084 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
3086 this._w = ( w * ratioA + this._w * ratioB );
3087 this._x = ( x * ratioA + this._x * ratioB );
3088 this._y = ( y * ratioA + this._y * ratioB );
3089 this._z = ( z * ratioA + this._z * ratioB );
3091 this._onChangeCallback();
3097 equals( quaternion ) {
3099 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
3103 fromArray( array, offset = 0 ) {
3105 this._x = array[ offset ];
3106 this._y = array[ offset + 1 ];
3107 this._z = array[ offset + 2 ];
3108 this._w = array[ offset + 3 ];
3110 this._onChangeCallback();
3116 toArray( array = [], offset = 0 ) {
3118 array[ offset ] = this._x;
3119 array[ offset + 1 ] = this._y;
3120 array[ offset + 2 ] = this._z;
3121 array[ offset + 3 ] = this._w;
3127 fromBufferAttribute( attribute, index ) {
3129 this._x = attribute.getX( index );
3130 this._y = attribute.getY( index );
3131 this._z = attribute.getZ( index );
3132 this._w = attribute.getW( index );
3138 _onChange( callback ) {
3140 this._onChangeCallback = callback;
3146 _onChangeCallback() {}
3152 constructor( x = 0, y = 0, z = 0 ) {
3154 Object.defineProperty( this, 'isVector3', { value: true } );
3164 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
3174 setScalar( scalar ) {
3208 setComponent( index, value ) {
3212 case 0: this.x = value; break;
3213 case 1: this.y = value; break;
3214 case 2: this.z = value; break;
3215 default: throw new Error( 'index is out of range: ' + index );
3223 getComponent( index ) {
3227 case 0: return this.x;
3228 case 1: return this.y;
3229 case 2: return this.z;
3230 default: throw new Error( 'index is out of range: ' + index );
3238 return new this.constructor( this.x, this.y, this.z );
3254 if ( w !== undefined ) {
3256 console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
3257 return this.addVectors( v, w );
3279 addVectors( a, b ) {
3289 addScaledVector( v, s ) {
3301 if ( w !== undefined ) {
3303 console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
3304 return this.subVectors( v, w );
3326 subVectors( a, b ) {
3338 if ( w !== undefined ) {
3340 console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
3341 return this.multiplyVectors( v, w );
3353 multiplyScalar( scalar ) {
3363 multiplyVectors( a, b ) {
3373 applyEuler( euler ) {
3375 if ( ! ( euler && euler.isEuler ) ) {
3377 console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
3381 return this.applyQuaternion( _quaternion.setFromEuler( euler ) );
3385 applyAxisAngle( axis, angle ) {
3387 return this.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) );
3393 const x = this.x, y = this.y, z = this.z;
3394 const e = m.elements;
3396 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
3397 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
3398 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
3404 applyNormalMatrix( m ) {
3406 return this.applyMatrix3( m ).normalize();
3412 const x = this.x, y = this.y, z = this.z;
3413 const e = m.elements;
3415 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
3417 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
3418 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
3419 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
3425 applyQuaternion( q ) {
3427 const x = this.x, y = this.y, z = this.z;
3428 const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
3430 // calculate quat * vector
3432 const ix = qw * x + qy * z - qz * y;
3433 const iy = qw * y + qz * x - qx * z;
3434 const iz = qw * z + qx * y - qy * x;
3435 const iw = - qx * x - qy * y - qz * z;
3437 // calculate result * inverse quat
3439 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
3440 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
3441 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
3449 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
3453 unproject( camera ) {
3455 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
3459 transformDirection( m ) {
3461 // input: THREE.Matrix4 affine matrix
3462 // vector interpreted as a direction
3464 const x = this.x, y = this.y, z = this.z;
3465 const e = m.elements;
3467 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
3468 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
3469 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
3471 return this.normalize();
3485 divideScalar( scalar ) {
3487 return this.multiplyScalar( 1 / scalar );
3493 this.x = Math.min( this.x, v.x );
3494 this.y = Math.min( this.y, v.y );
3495 this.z = Math.min( this.z, v.z );
3503 this.x = Math.max( this.x, v.x );
3504 this.y = Math.max( this.y, v.y );
3505 this.z = Math.max( this.z, v.z );
3513 // assumes min < max, componentwise
3515 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
3516 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
3517 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
3523 clampScalar( minVal, maxVal ) {
3525 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
3526 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
3527 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
3533 clampLength( min, max ) {
3535 const length = this.length();
3537 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
3543 this.x = Math.floor( this.x );
3544 this.y = Math.floor( this.y );
3545 this.z = Math.floor( this.z );
3553 this.x = Math.ceil( this.x );
3554 this.y = Math.ceil( this.y );
3555 this.z = Math.ceil( this.z );
3563 this.x = Math.round( this.x );
3564 this.y = Math.round( this.y );
3565 this.z = Math.round( this.z );
3573 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
3574 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
3575 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
3593 return this.x * v.x + this.y * v.y + this.z * v.z;
3597 // TODO lengthSquared?
3601 return this.x * this.x + this.y * this.y + this.z * this.z;
3607 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
3613 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
3619 return this.divideScalar( this.length() || 1 );
3623 setLength( length ) {
3625 return this.normalize().multiplyScalar( length );
3631 this.x += ( v.x - this.x ) * alpha;
3632 this.y += ( v.y - this.y ) * alpha;
3633 this.z += ( v.z - this.z ) * alpha;
3639 lerpVectors( v1, v2, alpha ) {
3641 this.x = v1.x + ( v2.x - v1.x ) * alpha;
3642 this.y = v1.y + ( v2.y - v1.y ) * alpha;
3643 this.z = v1.z + ( v2.z - v1.z ) * alpha;
3651 if ( w !== undefined ) {
3653 console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
3654 return this.crossVectors( v, w );
3658 return this.crossVectors( this, v );
3662 crossVectors( a, b ) {
3664 const ax = a.x, ay = a.y, az = a.z;
3665 const bx = b.x, by = b.y, bz = b.z;
3667 this.x = ay * bz - az * by;
3668 this.y = az * bx - ax * bz;
3669 this.z = ax * by - ay * bx;
3675 projectOnVector( v ) {
3677 const denominator = v.lengthSq();
3679 if ( denominator === 0 ) return this.set( 0, 0, 0 );
3681 const scalar = v.dot( this ) / denominator;
3683 return this.copy( v ).multiplyScalar( scalar );
3687 projectOnPlane( planeNormal ) {
3689 _vector.copy( this ).projectOnVector( planeNormal );
3691 return this.sub( _vector );
3697 // reflect incident vector off plane orthogonal to normal
3698 // normal is assumed to have unit length
3700 return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
3706 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
3708 if ( denominator === 0 ) return Math.PI / 2;
3710 const theta = this.dot( v ) / denominator;
3712 // clamp, to handle numerical problems
3714 return Math.acos( MathUtils.clamp( theta, - 1, 1 ) );
3720 return Math.sqrt( this.distanceToSquared( v ) );
3724 distanceToSquared( v ) {
3726 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
3728 return dx * dx + dy * dy + dz * dz;
3732 manhattanDistanceTo( v ) {
3734 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
3738 setFromSpherical( s ) {
3740 return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
3744 setFromSphericalCoords( radius, phi, theta ) {
3746 const sinPhiRadius = Math.sin( phi ) * radius;
3748 this.x = sinPhiRadius * Math.sin( theta );
3749 this.y = Math.cos( phi ) * radius;
3750 this.z = sinPhiRadius * Math.cos( theta );
3756 setFromCylindrical( c ) {
3758 return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
3762 setFromCylindricalCoords( radius, theta, y ) {
3764 this.x = radius * Math.sin( theta );
3766 this.z = radius * Math.cos( theta );
3772 setFromMatrixPosition( m ) {
3774 const e = m.elements;
3784 setFromMatrixScale( m ) {
3786 const sx = this.setFromMatrixColumn( m, 0 ).length();
3787 const sy = this.setFromMatrixColumn( m, 1 ).length();
3788 const sz = this.setFromMatrixColumn( m, 2 ).length();
3798 setFromMatrixColumn( m, index ) {
3800 return this.fromArray( m.elements, index * 4 );
3804 setFromMatrix3Column( m, index ) {
3806 return this.fromArray( m.elements, index * 3 );
3812 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
3816 fromArray( array, offset = 0 ) {
3818 this.x = array[ offset ];
3819 this.y = array[ offset + 1 ];
3820 this.z = array[ offset + 2 ];
3826 toArray( array = [], offset = 0 ) {
3828 array[ offset ] = this.x;
3829 array[ offset + 1 ] = this.y;
3830 array[ offset + 2 ] = this.z;
3836 fromBufferAttribute( attribute, index, offset ) {
3838 if ( offset !== undefined ) {
3840 console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
3844 this.x = attribute.getX( index );
3845 this.y = attribute.getY( index );
3846 this.z = attribute.getZ( index );
3854 this.x = Math.random();
3855 this.y = Math.random();
3856 this.z = Math.random();
3864 const _vector = /*@__PURE__*/ new Vector3();
3865 const _quaternion = /*@__PURE__*/ new Quaternion();
3869 constructor( min, max ) {
3871 Object.defineProperty( this, 'isBox3', { value: true } );
3873 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
3874 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
3880 this.min.copy( min );
3881 this.max.copy( max );
3887 setFromArray( array ) {
3889 let minX = + Infinity;
3890 let minY = + Infinity;
3891 let minZ = + Infinity;
3893 let maxX = - Infinity;
3894 let maxY = - Infinity;
3895 let maxZ = - Infinity;
3897 for ( let i = 0, l = array.length; i < l; i += 3 ) {
3899 const x = array[ i ];
3900 const y = array[ i + 1 ];
3901 const z = array[ i + 2 ];
3903 if ( x < minX ) minX = x;
3904 if ( y < minY ) minY = y;
3905 if ( z < minZ ) minZ = z;
3907 if ( x > maxX ) maxX = x;
3908 if ( y > maxY ) maxY = y;
3909 if ( z > maxZ ) maxZ = z;
3913 this.min.set( minX, minY, minZ );
3914 this.max.set( maxX, maxY, maxZ );
3920 setFromBufferAttribute( attribute ) {
3922 let minX = + Infinity;
3923 let minY = + Infinity;
3924 let minZ = + Infinity;
3926 let maxX = - Infinity;
3927 let maxY = - Infinity;
3928 let maxZ = - Infinity;
3930 for ( let i = 0, l = attribute.count; i < l; i ++ ) {
3932 const x = attribute.getX( i );
3933 const y = attribute.getY( i );
3934 const z = attribute.getZ( i );
3936 if ( x < minX ) minX = x;
3937 if ( y < minY ) minY = y;
3938 if ( z < minZ ) minZ = z;
3940 if ( x > maxX ) maxX = x;
3941 if ( y > maxY ) maxY = y;
3942 if ( z > maxZ ) maxZ = z;
3946 this.min.set( minX, minY, minZ );
3947 this.max.set( maxX, maxY, maxZ );
3953 setFromPoints( points ) {
3957 for ( let i = 0, il = points.length; i < il; i ++ ) {
3959 this.expandByPoint( points[ i ] );
3967 setFromCenterAndSize( center, size ) {
3969 const halfSize = _vector$1.copy( size ).multiplyScalar( 0.5 );
3971 this.min.copy( center ).sub( halfSize );
3972 this.max.copy( center ).add( halfSize );
3978 setFromObject( object ) {
3982 return this.expandByObject( object );
3988 return new this.constructor().copy( this );
3994 this.min.copy( box.min );
3995 this.max.copy( box.max );
4003 this.min.x = this.min.y = this.min.z = + Infinity;
4004 this.max.x = this.max.y = this.max.z = - Infinity;
4012 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
4014 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
4018 getCenter( target ) {
4020 if ( target === undefined ) {
4022 console.warn( 'THREE.Box3: .getCenter() target is now required' );
4023 target = new Vector3();
4027 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
4033 if ( target === undefined ) {
4035 console.warn( 'THREE.Box3: .getSize() target is now required' );
4036 target = new Vector3();
4040 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
4044 expandByPoint( point ) {
4046 this.min.min( point );
4047 this.max.max( point );
4053 expandByVector( vector ) {
4055 this.min.sub( vector );
4056 this.max.add( vector );
4062 expandByScalar( scalar ) {
4064 this.min.addScalar( - scalar );
4065 this.max.addScalar( scalar );
4071 expandByObject( object ) {
4073 // Computes the world-axis-aligned bounding box of an object (including its children),
4074 // accounting for both the object's, and children's, world transforms
4076 object.updateWorldMatrix( false, false );
4078 const geometry = object.geometry;
4080 if ( geometry !== undefined ) {
4082 if ( geometry.boundingBox === null ) {
4084 geometry.computeBoundingBox();
4088 _box.copy( geometry.boundingBox );
4089 _box.applyMatrix4( object.matrixWorld );
4095 const children = object.children;
4097 for ( let i = 0, l = children.length; i < l; i ++ ) {
4099 this.expandByObject( children[ i ] );
4107 containsPoint( point ) {
4109 return point.x < this.min.x || point.x > this.max.x ||
4110 point.y < this.min.y || point.y > this.max.y ||
4111 point.z < this.min.z || point.z > this.max.z ? false : true;
4115 containsBox( box ) {
4117 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
4118 this.min.y <= box.min.y && box.max.y <= this.max.y &&
4119 this.min.z <= box.min.z && box.max.z <= this.max.z;
4123 getParameter( point, target ) {
4125 // This can potentially have a divide by zero if the box
4126 // has a size dimension of 0.
4128 if ( target === undefined ) {
4130 console.warn( 'THREE.Box3: .getParameter() target is now required' );
4131 target = new Vector3();
4136 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
4137 ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
4138 ( point.z - this.min.z ) / ( this.max.z - this.min.z )
4143 intersectsBox( box ) {
4145 // using 6 splitting planes to rule out intersections.
4146 return box.max.x < this.min.x || box.min.x > this.max.x ||
4147 box.max.y < this.min.y || box.min.y > this.max.y ||
4148 box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
4152 intersectsSphere( sphere ) {
4154 // Find the point on the AABB closest to the sphere center.
4155 this.clampPoint( sphere.center, _vector$1 );
4157 // If that point is inside the sphere, the AABB and sphere intersect.
4158 return _vector$1.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
4162 intersectsPlane( plane ) {
4164 // We compute the minimum and maximum dot product values. If those values
4165 // are on the same side (back or front) of the plane, then there is no intersection.
4169 if ( plane.normal.x > 0 ) {
4171 min = plane.normal.x * this.min.x;
4172 max = plane.normal.x * this.max.x;
4176 min = plane.normal.x * this.max.x;
4177 max = plane.normal.x * this.min.x;
4181 if ( plane.normal.y > 0 ) {
4183 min += plane.normal.y * this.min.y;
4184 max += plane.normal.y * this.max.y;
4188 min += plane.normal.y * this.max.y;
4189 max += plane.normal.y * this.min.y;
4193 if ( plane.normal.z > 0 ) {
4195 min += plane.normal.z * this.min.z;
4196 max += plane.normal.z * this.max.z;
4200 min += plane.normal.z * this.max.z;
4201 max += plane.normal.z * this.min.z;
4205 return ( min <= - plane.constant && max >= - plane.constant );
4209 intersectsTriangle( triangle ) {
4211 if ( this.isEmpty() ) {
4217 // compute box center and extents
4218 this.getCenter( _center );
4219 _extents.subVectors( this.max, _center );
4221 // translate triangle to aabb origin
4222 _v0.subVectors( triangle.a, _center );
4223 _v1.subVectors( triangle.b, _center );
4224 _v2.subVectors( triangle.c, _center );
4226 // compute edge vectors for triangle
4227 _f0.subVectors( _v1, _v0 );
4228 _f1.subVectors( _v2, _v1 );
4229 _f2.subVectors( _v0, _v2 );
4231 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
4232 // 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
4233 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
4235 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
4236 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
4237 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
4239 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
4245 // test 3 face normals from the aabb
4246 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
4247 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
4253 // finally testing the face normal of the triangle
4254 // use already existing triangle edge vectors here
4255 _triangleNormal.crossVectors( _f0, _f1 );
4256 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
4258 return satForAxes( axes, _v0, _v1, _v2, _extents );
4262 clampPoint( point, target ) {
4264 if ( target === undefined ) {
4266 console.warn( 'THREE.Box3: .clampPoint() target is now required' );
4267 target = new Vector3();
4271 return target.copy( point ).clamp( this.min, this.max );
4275 distanceToPoint( point ) {
4277 const clampedPoint = _vector$1.copy( point ).clamp( this.min, this.max );
4279 return clampedPoint.sub( point ).length();
4283 getBoundingSphere( target ) {
4285 if ( target === undefined ) {
4287 console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
4288 //target = new Sphere(); // removed to avoid cyclic dependency
4292 this.getCenter( target.center );
4294 target.radius = this.getSize( _vector$1 ).length() * 0.5;
4302 this.min.max( box.min );
4303 this.max.min( box.max );
4305 // 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.
4306 if ( this.isEmpty() ) this.makeEmpty();
4314 this.min.min( box.min );
4315 this.max.max( box.max );
4321 applyMatrix4( matrix ) {
4323 // transform of empty box is an empty box.
4324 if ( this.isEmpty() ) return this;
4326 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
4327 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
4328 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
4329 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
4330 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
4331 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
4332 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
4333 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
4334 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
4336 this.setFromPoints( _points );
4342 translate( offset ) {
4344 this.min.add( offset );
4345 this.max.add( offset );
4353 return box.min.equals( this.min ) && box.max.equals( this.max );
4359 function satForAxes( axes, v0, v1, v2, extents ) {
4361 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
4363 _testAxis.fromArray( axes, i );
4364 // project the aabb onto the seperating axis
4365 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
4366 // project all 3 vertices of the triangle onto the seperating axis
4367 const p0 = v0.dot( _testAxis );
4368 const p1 = v1.dot( _testAxis );
4369 const p2 = v2.dot( _testAxis );
4370 // actual test, basically see if either of the most extreme of the triangle points intersects r
4371 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
4373 // points of the projected triangle are outside the projected half-length of the aabb
4374 // the axis is seperating and we can exit
4386 /*@__PURE__*/ new Vector3(),
4387 /*@__PURE__*/ new Vector3(),
4388 /*@__PURE__*/ new Vector3(),
4389 /*@__PURE__*/ new Vector3(),
4390 /*@__PURE__*/ new Vector3(),
4391 /*@__PURE__*/ new Vector3(),
4392 /*@__PURE__*/ new Vector3(),
4393 /*@__PURE__*/ new Vector3()
4396 const _vector$1 = /*@__PURE__*/ new Vector3();
4398 const _box = /*@__PURE__*/ new Box3();
4400 // triangle centered vertices
4402 const _v0 = /*@__PURE__*/ new Vector3();
4403 const _v1 = /*@__PURE__*/ new Vector3();
4404 const _v2 = /*@__PURE__*/ new Vector3();
4406 // triangle edge vectors
4408 const _f0 = /*@__PURE__*/ new Vector3();
4409 const _f1 = /*@__PURE__*/ new Vector3();
4410 const _f2 = /*@__PURE__*/ new Vector3();
4412 const _center = /*@__PURE__*/ new Vector3();
4413 const _extents = /*@__PURE__*/ new Vector3();
4414 const _triangleNormal = /*@__PURE__*/ new Vector3();
4415 const _testAxis = /*@__PURE__*/ new Vector3();
4417 const _box$1 = /*@__PURE__*/ new Box3();
4421 constructor( center, radius ) {
4423 this.center = ( center !== undefined ) ? center : new Vector3();
4424 this.radius = ( radius !== undefined ) ? radius : - 1;
4428 set( center, radius ) {
4430 this.center.copy( center );
4431 this.radius = radius;
4437 setFromPoints( points, optionalCenter ) {
4439 const center = this.center;
4441 if ( optionalCenter !== undefined ) {
4443 center.copy( optionalCenter );
4447 _box$1.setFromPoints( points ).getCenter( center );
4451 let maxRadiusSq = 0;
4453 for ( let i = 0, il = points.length; i < il; i ++ ) {
4455 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
4459 this.radius = Math.sqrt( maxRadiusSq );
4467 return new this.constructor().copy( this );
4473 this.center.copy( sphere.center );
4474 this.radius = sphere.radius;
4482 return ( this.radius < 0 );
4488 this.center.set( 0, 0, 0 );
4495 containsPoint( point ) {
4497 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
4501 distanceToPoint( point ) {
4503 return ( point.distanceTo( this.center ) - this.radius );
4507 intersectsSphere( sphere ) {
4509 const radiusSum = this.radius + sphere.radius;
4511 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
4515 intersectsBox( box ) {
4517 return box.intersectsSphere( this );
4521 intersectsPlane( plane ) {
4523 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
4527 clampPoint( point, target ) {
4529 const deltaLengthSq = this.center.distanceToSquared( point );
4531 if ( target === undefined ) {
4533 console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
4534 target = new Vector3();
4538 target.copy( point );
4540 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
4542 target.sub( this.center ).normalize();
4543 target.multiplyScalar( this.radius ).add( this.center );
4551 getBoundingBox( target ) {
4553 if ( target === undefined ) {
4555 console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
4556 target = new Box3();
4560 if ( this.isEmpty() ) {
4562 // Empty sphere produces empty bounding box
4568 target.set( this.center, this.center );
4569 target.expandByScalar( this.radius );
4575 applyMatrix4( matrix ) {
4577 this.center.applyMatrix4( matrix );
4578 this.radius = this.radius * matrix.getMaxScaleOnAxis();
4584 translate( offset ) {
4586 this.center.add( offset );
4594 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
4600 const _vector$2 = /*@__PURE__*/ new Vector3();
4601 const _segCenter = /*@__PURE__*/ new Vector3();
4602 const _segDir = /*@__PURE__*/ new Vector3();
4603 const _diff = /*@__PURE__*/ new Vector3();
4605 const _edge1 = /*@__PURE__*/ new Vector3();
4606 const _edge2 = /*@__PURE__*/ new Vector3();
4607 const _normal = /*@__PURE__*/ new Vector3();
4611 constructor( origin, direction ) {
4613 this.origin = ( origin !== undefined ) ? origin : new Vector3();
4614 this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
4618 set( origin, direction ) {
4620 this.origin.copy( origin );
4621 this.direction.copy( direction );
4629 return new this.constructor().copy( this );
4635 this.origin.copy( ray.origin );
4636 this.direction.copy( ray.direction );
4644 if ( target === undefined ) {
4646 console.warn( 'THREE.Ray: .at() target is now required' );
4647 target = new Vector3();
4651 return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
4657 this.direction.copy( v ).sub( this.origin ).normalize();
4665 this.origin.copy( this.at( t, _vector$2 ) );
4671 closestPointToPoint( point, target ) {
4673 if ( target === undefined ) {
4675 console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
4676 target = new Vector3();
4680 target.subVectors( point, this.origin );
4682 const directionDistance = target.dot( this.direction );
4684 if ( directionDistance < 0 ) {
4686 return target.copy( this.origin );
4690 return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
4694 distanceToPoint( point ) {
4696 return Math.sqrt( this.distanceSqToPoint( point ) );
4700 distanceSqToPoint( point ) {
4702 const directionDistance = _vector$2.subVectors( point, this.origin ).dot( this.direction );
4704 // point behind the ray
4706 if ( directionDistance < 0 ) {
4708 return this.origin.distanceToSquared( point );
4712 _vector$2.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
4714 return _vector$2.distanceToSquared( point );
4718 distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
4720 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
4721 // It returns the min distance between the ray and the segment
4722 // defined by v0 and v1
4723 // It can also set two optional targets :
4724 // - The closest point on the ray
4725 // - The closest point on the segment
4727 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
4728 _segDir.copy( v1 ).sub( v0 ).normalize();
4729 _diff.copy( this.origin ).sub( _segCenter );
4731 const segExtent = v0.distanceTo( v1 ) * 0.5;
4732 const a01 = - this.direction.dot( _segDir );
4733 const b0 = _diff.dot( this.direction );
4734 const b1 = - _diff.dot( _segDir );
4735 const c = _diff.lengthSq();
4736 const det = Math.abs( 1 - a01 * a01 );
4737 let s0, s1, sqrDist, extDet;
4741 // The ray and segment are not parallel.
4745 extDet = segExtent * det;
4749 if ( s1 >= - extDet ) {
4751 if ( s1 <= extDet ) {
4754 // Minimum at interior points of ray and segment.
4756 const invDet = 1 / det;
4759 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
4766 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4767 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4776 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4777 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4783 if ( s1 <= - extDet ) {
4787 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
4788 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
4789 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4791 } else if ( s1 <= extDet ) {
4796 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
4797 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
4803 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
4804 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
4805 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4813 // Ray and segment are parallel.
4815 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
4816 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4817 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4821 if ( optionalPointOnRay ) {
4823 optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
4827 if ( optionalPointOnSegment ) {
4829 optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
4837 intersectSphere( sphere, target ) {
4839 _vector$2.subVectors( sphere.center, this.origin );
4840 const tca = _vector$2.dot( this.direction );
4841 const d2 = _vector$2.dot( _vector$2 ) - tca * tca;
4842 const radius2 = sphere.radius * sphere.radius;
4844 if ( d2 > radius2 ) return null;
4846 const thc = Math.sqrt( radius2 - d2 );
4848 // t0 = first intersect point - entrance on front of sphere
4849 const t0 = tca - thc;
4851 // t1 = second intersect point - exit point on back of sphere
4852 const t1 = tca + thc;
4854 // test to see if both t0 and t1 are behind the ray - if so, return null
4855 if ( t0 < 0 && t1 < 0 ) return null;
4857 // test to see if t0 is behind the ray:
4858 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
4859 // in order to always return an intersect point that is in front of the ray.
4860 if ( t0 < 0 ) return this.at( t1, target );
4862 // else t0 is in front of the ray, so return the first collision point scaled by t0
4863 return this.at( t0, target );
4867 intersectsSphere( sphere ) {
4869 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
4873 distanceToPlane( plane ) {
4875 const denominator = plane.normal.dot( this.direction );
4877 if ( denominator === 0 ) {
4879 // line is coplanar, return origin
4880 if ( plane.distanceToPoint( this.origin ) === 0 ) {
4886 // Null is preferable to undefined since undefined means.... it is undefined
4892 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
4894 // Return if the ray never intersects the plane
4896 return t >= 0 ? t : null;
4900 intersectPlane( plane, target ) {
4902 const t = this.distanceToPlane( plane );
4910 return this.at( t, target );
4914 intersectsPlane( plane ) {
4916 // check if the ray lies on the plane first
4918 const distToPoint = plane.distanceToPoint( this.origin );
4920 if ( distToPoint === 0 ) {
4926 const denominator = plane.normal.dot( this.direction );
4928 if ( denominator * distToPoint < 0 ) {
4934 // ray origin is behind the plane (and is pointing behind it)
4940 intersectBox( box, target ) {
4942 let tmin, tmax, tymin, tymax, tzmin, tzmax;
4944 const invdirx = 1 / this.direction.x,
4945 invdiry = 1 / this.direction.y,
4946 invdirz = 1 / this.direction.z;
4948 const origin = this.origin;
4950 if ( invdirx >= 0 ) {
4952 tmin = ( box.min.x - origin.x ) * invdirx;
4953 tmax = ( box.max.x - origin.x ) * invdirx;
4957 tmin = ( box.max.x - origin.x ) * invdirx;
4958 tmax = ( box.min.x - origin.x ) * invdirx;
4962 if ( invdiry >= 0 ) {
4964 tymin = ( box.min.y - origin.y ) * invdiry;
4965 tymax = ( box.max.y - origin.y ) * invdiry;
4969 tymin = ( box.max.y - origin.y ) * invdiry;
4970 tymax = ( box.min.y - origin.y ) * invdiry;
4974 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
4976 // These lines also handle the case where tmin or tmax is NaN
4977 // (result of 0 * Infinity). x !== x returns true if x is NaN
4979 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
4981 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
4983 if ( invdirz >= 0 ) {
4985 tzmin = ( box.min.z - origin.z ) * invdirz;
4986 tzmax = ( box.max.z - origin.z ) * invdirz;
4990 tzmin = ( box.max.z - origin.z ) * invdirz;
4991 tzmax = ( box.min.z - origin.z ) * invdirz;
4995 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
4997 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
4999 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
5001 //return point closest to the ray (positive side)
5003 if ( tmax < 0 ) return null;
5005 return this.at( tmin >= 0 ? tmin : tmax, target );
5009 intersectsBox( box ) {
5011 return this.intersectBox( box, _vector$2 ) !== null;
5015 intersectTriangle( a, b, c, backfaceCulling, target ) {
5017 // Compute the offset origin, edges, and normal.
5019 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
5021 _edge1.subVectors( b, a );
5022 _edge2.subVectors( c, a );
5023 _normal.crossVectors( _edge1, _edge2 );
5025 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
5026 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
5027 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
5028 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
5029 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
5030 let DdN = this.direction.dot( _normal );
5035 if ( backfaceCulling ) return null;
5038 } else if ( DdN < 0 ) {
5049 _diff.subVectors( this.origin, a );
5050 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
5052 // b1 < 0, no intersection
5059 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
5061 // b2 < 0, no intersection
5068 // b1+b2 > 1, no intersection
5069 if ( DdQxE2 + DdE1xQ > DdN ) {
5075 // Line intersects triangle, check if ray does.
5076 const QdN = - sign * _diff.dot( _normal );
5078 // t < 0, no intersection
5085 // Ray intersects triangle.
5086 return this.at( QdN / DdN, target );
5090 applyMatrix4( matrix4 ) {
5092 this.origin.applyMatrix4( matrix4 );
5093 this.direction.transformDirection( matrix4 );
5101 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
5111 Object.defineProperty( this, 'isMatrix4', { value: true } );
5122 if ( arguments.length > 0 ) {
5124 console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
5130 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5132 const te = this.elements;
5134 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
5135 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
5136 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
5137 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
5160 return new Matrix4().fromArray( this.elements );
5166 const te = this.elements;
5167 const me = m.elements;
5169 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
5170 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
5171 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
5172 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
5180 const te = this.elements, me = m.elements;
5182 te[ 12 ] = me[ 12 ];
5183 te[ 13 ] = me[ 13 ];
5184 te[ 14 ] = me[ 14 ];
5190 setFromMatrix3( m ) {
5192 const me = m.elements;
5196 me[ 0 ], me[ 3 ], me[ 6 ], 0,
5197 me[ 1 ], me[ 4 ], me[ 7 ], 0,
5198 me[ 2 ], me[ 5 ], me[ 8 ], 0,
5207 extractBasis( xAxis, yAxis, zAxis ) {
5209 xAxis.setFromMatrixColumn( this, 0 );
5210 yAxis.setFromMatrixColumn( this, 1 );
5211 zAxis.setFromMatrixColumn( this, 2 );
5217 makeBasis( xAxis, yAxis, zAxis ) {
5220 xAxis.x, yAxis.x, zAxis.x, 0,
5221 xAxis.y, yAxis.y, zAxis.y, 0,
5222 xAxis.z, yAxis.z, zAxis.z, 0,
5230 extractRotation( m ) {
5232 // this method does not support reflection matrices
5234 const te = this.elements;
5235 const me = m.elements;
5237 const scaleX = 1 / _v1$1.setFromMatrixColumn( m, 0 ).length();
5238 const scaleY = 1 / _v1$1.setFromMatrixColumn( m, 1 ).length();
5239 const scaleZ = 1 / _v1$1.setFromMatrixColumn( m, 2 ).length();
5241 te[ 0 ] = me[ 0 ] * scaleX;
5242 te[ 1 ] = me[ 1 ] * scaleX;
5243 te[ 2 ] = me[ 2 ] * scaleX;
5246 te[ 4 ] = me[ 4 ] * scaleY;
5247 te[ 5 ] = me[ 5 ] * scaleY;
5248 te[ 6 ] = me[ 6 ] * scaleY;
5251 te[ 8 ] = me[ 8 ] * scaleZ;
5252 te[ 9 ] = me[ 9 ] * scaleZ;
5253 te[ 10 ] = me[ 10 ] * scaleZ;
5265 makeRotationFromEuler( euler ) {
5267 if ( ! ( euler && euler.isEuler ) ) {
5269 console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
5273 const te = this.elements;
5275 const x = euler.x, y = euler.y, z = euler.z;
5276 const a = Math.cos( x ), b = Math.sin( x );
5277 const c = Math.cos( y ), d = Math.sin( y );
5278 const e = Math.cos( z ), f = Math.sin( z );
5280 if ( euler.order === 'XYZ' ) {
5282 const ae = a * e, af = a * f, be = b * e, bf = b * f;
5288 te[ 1 ] = af + be * d;
5289 te[ 5 ] = ae - bf * d;
5292 te[ 2 ] = bf - ae * d;
5293 te[ 6 ] = be + af * d;
5296 } else if ( euler.order === 'YXZ' ) {
5298 const ce = c * e, cf = c * f, de = d * e, df = d * f;
5300 te[ 0 ] = ce + df * b;
5301 te[ 4 ] = de * b - cf;
5308 te[ 2 ] = cf * b - de;
5309 te[ 6 ] = df + ce * b;
5312 } else if ( euler.order === 'ZXY' ) {
5314 const ce = c * e, cf = c * f, de = d * e, df = d * f;
5316 te[ 0 ] = ce - df * b;
5318 te[ 8 ] = de + cf * b;
5320 te[ 1 ] = cf + de * b;
5322 te[ 9 ] = df - ce * b;
5328 } else if ( euler.order === 'ZYX' ) {
5330 const ae = a * e, af = a * f, be = b * e, bf = b * f;
5333 te[ 4 ] = be * d - af;
5334 te[ 8 ] = ae * d + bf;
5337 te[ 5 ] = bf * d + ae;
5338 te[ 9 ] = af * d - be;
5344 } else if ( euler.order === 'YZX' ) {
5346 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
5349 te[ 4 ] = bd - ac * f;
5350 te[ 8 ] = bc * f + ad;
5357 te[ 6 ] = ad * f + bc;
5358 te[ 10 ] = ac - bd * f;
5360 } else if ( euler.order === 'XZY' ) {
5362 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
5368 te[ 1 ] = ac * f + bd;
5370 te[ 9 ] = ad * f - bc;
5372 te[ 2 ] = bc * f - ad;
5374 te[ 10 ] = bd * f + ac;
5393 makeRotationFromQuaternion( q ) {
5395 return this.compose( _zero, q, _one );
5399 lookAt( eye, target, up ) {
5401 const te = this.elements;
5403 _z.subVectors( eye, target );
5405 if ( _z.lengthSq() === 0 ) {
5407 // eye and target are in the same position
5414 _x.crossVectors( up, _z );
5416 if ( _x.lengthSq() === 0 ) {
5418 // up and z are parallel
5420 if ( Math.abs( up.z ) === 1 ) {
5431 _x.crossVectors( up, _z );
5436 _y.crossVectors( _z, _x );
5438 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
5439 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
5440 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
5448 if ( n !== undefined ) {
5450 console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
5451 return this.multiplyMatrices( m, n );
5455 return this.multiplyMatrices( this, m );
5461 return this.multiplyMatrices( m, this );
5465 multiplyMatrices( a, b ) {
5467 const ae = a.elements;
5468 const be = b.elements;
5469 const te = this.elements;
5471 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
5472 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
5473 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
5474 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
5476 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
5477 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
5478 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
5479 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
5481 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
5482 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
5483 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
5484 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
5486 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
5487 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
5488 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
5489 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
5491 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
5492 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
5493 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
5494 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
5496 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
5497 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
5498 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
5499 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
5505 multiplyScalar( s ) {
5507 const te = this.elements;
5509 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
5510 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
5511 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
5512 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
5520 const te = this.elements;
5522 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
5523 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
5524 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
5525 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
5527 //TODO: make this more efficient
5528 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
5570 const te = this.elements;
5573 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
5574 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
5575 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
5577 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
5578 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
5579 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
5585 setPosition( x, y, z ) {
5587 const te = this.elements;
5589 if ( x.isVector3 ) {
5609 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
5610 const te = this.elements,
5612 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
5613 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
5614 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
5615 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
5617 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
5618 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
5619 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
5620 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
5622 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
5624 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
5626 const detInv = 1 / det;
5628 te[ 0 ] = t11 * detInv;
5629 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
5630 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
5631 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
5633 te[ 4 ] = t12 * detInv;
5634 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
5635 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
5636 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
5638 te[ 8 ] = t13 * detInv;
5639 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
5640 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
5641 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
5643 te[ 12 ] = t14 * detInv;
5644 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
5645 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
5646 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
5654 const te = this.elements;
5655 const x = v.x, y = v.y, z = v.z;
5657 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
5658 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
5659 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
5660 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
5666 getMaxScaleOnAxis() {
5668 const te = this.elements;
5670 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
5671 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
5672 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
5674 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
5678 makeTranslation( x, y, z ) {
5693 makeRotationX( theta ) {
5695 const c = Math.cos( theta ), s = Math.sin( theta );
5710 makeRotationY( theta ) {
5712 const c = Math.cos( theta ), s = Math.sin( theta );
5727 makeRotationZ( theta ) {
5729 const c = Math.cos( theta ), s = Math.sin( theta );
5744 makeRotationAxis( axis, angle ) {
5746 // Based on http://www.gamedev.net/reference/articles/article1199.asp
5748 const c = Math.cos( angle );
5749 const s = Math.sin( angle );
5751 const x = axis.x, y = axis.y, z = axis.z;
5752 const tx = t * x, ty = t * y;
5756 tx * x + c, tx * y - s * z, tx * z + s * y, 0,
5757 tx * y + s * z, ty * y + c, ty * z - s * x, 0,
5758 tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
5767 makeScale( x, y, z ) {
5782 makeShear( x, y, z ) {
5797 compose( position, quaternion, scale ) {
5799 const te = this.elements;
5801 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
5802 const x2 = x + x, y2 = y + y, z2 = z + z;
5803 const xx = x * x2, xy = x * y2, xz = x * z2;
5804 const yy = y * y2, yz = y * z2, zz = z * z2;
5805 const wx = w * x2, wy = w * y2, wz = w * z2;
5807 const sx = scale.x, sy = scale.y, sz = scale.z;
5809 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
5810 te[ 1 ] = ( xy + wz ) * sx;
5811 te[ 2 ] = ( xz - wy ) * sx;
5814 te[ 4 ] = ( xy - wz ) * sy;
5815 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
5816 te[ 6 ] = ( yz + wx ) * sy;
5819 te[ 8 ] = ( xz + wy ) * sz;
5820 te[ 9 ] = ( yz - wx ) * sz;
5821 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
5824 te[ 12 ] = position.x;
5825 te[ 13 ] = position.y;
5826 te[ 14 ] = position.z;
5833 decompose( position, quaternion, scale ) {
5835 const te = this.elements;
5837 let sx = _v1$1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
5838 const sy = _v1$1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
5839 const sz = _v1$1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
5841 // if determine is negative, we need to invert one scale
5842 const det = this.determinant();
5843 if ( det < 0 ) sx = - sx;
5845 position.x = te[ 12 ];
5846 position.y = te[ 13 ];
5847 position.z = te[ 14 ];
5849 // scale the rotation part
5852 const invSX = 1 / sx;
5853 const invSY = 1 / sy;
5854 const invSZ = 1 / sz;
5856 _m1.elements[ 0 ] *= invSX;
5857 _m1.elements[ 1 ] *= invSX;
5858 _m1.elements[ 2 ] *= invSX;
5860 _m1.elements[ 4 ] *= invSY;
5861 _m1.elements[ 5 ] *= invSY;
5862 _m1.elements[ 6 ] *= invSY;
5864 _m1.elements[ 8 ] *= invSZ;
5865 _m1.elements[ 9 ] *= invSZ;
5866 _m1.elements[ 10 ] *= invSZ;
5868 quaternion.setFromRotationMatrix( _m1 );
5878 makePerspective( left, right, top, bottom, near, far ) {
5880 if ( far === undefined ) {
5882 console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
5886 const te = this.elements;
5887 const x = 2 * near / ( right - left );
5888 const y = 2 * near / ( top - bottom );
5890 const a = ( right + left ) / ( right - left );
5891 const b = ( top + bottom ) / ( top - bottom );
5892 const c = - ( far + near ) / ( far - near );
5893 const d = - 2 * far * near / ( far - near );
5895 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
5896 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
5897 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
5898 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
5904 makeOrthographic( left, right, top, bottom, near, far ) {
5906 const te = this.elements;
5907 const w = 1.0 / ( right - left );
5908 const h = 1.0 / ( top - bottom );
5909 const p = 1.0 / ( far - near );
5911 const x = ( right + left ) * w;
5912 const y = ( top + bottom ) * h;
5913 const z = ( far + near ) * p;
5915 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
5916 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
5917 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
5918 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
5926 const te = this.elements;
5927 const me = matrix.elements;
5929 for ( let i = 0; i < 16; i ++ ) {
5931 if ( te[ i ] !== me[ i ] ) return false;
5939 fromArray( array, offset = 0 ) {
5941 for ( let i = 0; i < 16; i ++ ) {
5943 this.elements[ i ] = array[ i + offset ];
5951 toArray( array = [], offset = 0 ) {
5953 const te = this.elements;
5955 array[ offset ] = te[ 0 ];
5956 array[ offset + 1 ] = te[ 1 ];
5957 array[ offset + 2 ] = te[ 2 ];
5958 array[ offset + 3 ] = te[ 3 ];
5960 array[ offset + 4 ] = te[ 4 ];
5961 array[ offset + 5 ] = te[ 5 ];
5962 array[ offset + 6 ] = te[ 6 ];
5963 array[ offset + 7 ] = te[ 7 ];
5965 array[ offset + 8 ] = te[ 8 ];
5966 array[ offset + 9 ] = te[ 9 ];
5967 array[ offset + 10 ] = te[ 10 ];
5968 array[ offset + 11 ] = te[ 11 ];
5970 array[ offset + 12 ] = te[ 12 ];
5971 array[ offset + 13 ] = te[ 13 ];
5972 array[ offset + 14 ] = te[ 14 ];
5973 array[ offset + 15 ] = te[ 15 ];
5981 const _v1$1 = /*@__PURE__*/ new Vector3();
5982 const _m1 = /*@__PURE__*/ new Matrix4();
5983 const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
5984 const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
5985 const _x = /*@__PURE__*/ new Vector3();
5986 const _y = /*@__PURE__*/ new Vector3();
5987 const _z = /*@__PURE__*/ new Vector3();
5991 constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) {
5993 Object.defineProperty( this, 'isEuler', { value: true } );
5998 this._order = order;
6011 this._onChangeCallback();
6024 this._onChangeCallback();
6037 this._onChangeCallback();
6047 set order( value ) {
6049 this._order = value;
6050 this._onChangeCallback();
6054 set( x, y, z, order ) {
6059 this._order = order || this._order;
6061 this._onChangeCallback();
6069 return new this.constructor( this._x, this._y, this._z, this._order );
6078 this._order = euler._order;
6080 this._onChangeCallback();
6086 setFromRotationMatrix( m, order, update ) {
6088 const clamp = MathUtils.clamp;
6090 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6092 const te = m.elements;
6093 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
6094 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
6095 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6097 order = order || this._order;
6103 this._y = Math.asin( clamp( m13, - 1, 1 ) );
6105 if ( Math.abs( m13 ) < 0.9999999 ) {
6107 this._x = Math.atan2( - m23, m33 );
6108 this._z = Math.atan2( - m12, m11 );
6112 this._x = Math.atan2( m32, m22 );
6121 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
6123 if ( Math.abs( m23 ) < 0.9999999 ) {
6125 this._y = Math.atan2( m13, m33 );
6126 this._z = Math.atan2( m21, m22 );
6130 this._y = Math.atan2( - m31, m11 );
6139 this._x = Math.asin( clamp( m32, - 1, 1 ) );
6141 if ( Math.abs( m32 ) < 0.9999999 ) {
6143 this._y = Math.atan2( - m31, m33 );
6144 this._z = Math.atan2( - m12, m22 );
6149 this._z = Math.atan2( m21, m11 );
6157 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
6159 if ( Math.abs( m31 ) < 0.9999999 ) {
6161 this._x = Math.atan2( m32, m33 );
6162 this._z = Math.atan2( m21, m11 );
6167 this._z = Math.atan2( - m12, m22 );
6175 this._z = Math.asin( clamp( m21, - 1, 1 ) );
6177 if ( Math.abs( m21 ) < 0.9999999 ) {
6179 this._x = Math.atan2( - m23, m22 );
6180 this._y = Math.atan2( - m31, m11 );
6185 this._y = Math.atan2( m13, m33 );
6193 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
6195 if ( Math.abs( m12 ) < 0.9999999 ) {
6197 this._x = Math.atan2( m32, m22 );
6198 this._y = Math.atan2( m13, m11 );
6202 this._x = Math.atan2( - m23, m33 );
6211 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
6215 this._order = order;
6217 if ( update !== false ) this._onChangeCallback();
6223 setFromQuaternion( q, order, update ) {
6225 _matrix.makeRotationFromQuaternion( q );
6227 return this.setFromRotationMatrix( _matrix, order, update );
6231 setFromVector3( v, order ) {
6233 return this.set( v.x, v.y, v.z, order || this._order );
6237 reorder( newOrder ) {
6239 // WARNING: this discards revolution information -bhouston
6241 _quaternion$1.setFromEuler( this );
6243 return this.setFromQuaternion( _quaternion$1, newOrder );
6249 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
6253 fromArray( array ) {
6255 this._x = array[ 0 ];
6256 this._y = array[ 1 ];
6257 this._z = array[ 2 ];
6258 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
6260 this._onChangeCallback();
6266 toArray( array = [], offset = 0 ) {
6268 array[ offset ] = this._x;
6269 array[ offset + 1 ] = this._y;
6270 array[ offset + 2 ] = this._z;
6271 array[ offset + 3 ] = this._order;
6277 toVector3( optionalResult ) {
6279 if ( optionalResult ) {
6281 return optionalResult.set( this._x, this._y, this._z );
6285 return new Vector3( this._x, this._y, this._z );
6291 _onChange( callback ) {
6293 this._onChangeCallback = callback;
6299 _onChangeCallback() {}
6303 Euler.DefaultOrder = 'XYZ';
6304 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
6306 const _matrix = /*@__PURE__*/ new Matrix4();
6307 const _quaternion$1 = /*@__PURE__*/ new Quaternion();
6319 this.mask = 1 << channel | 0;
6325 this.mask |= 1 << channel | 0;
6331 this.mask = 0xffffffff | 0;
6337 this.mask ^= 1 << channel | 0;
6341 disable( channel ) {
6343 this.mask &= ~ ( 1 << channel | 0 );
6355 return ( this.mask & layers.mask ) !== 0;
6361 let _object3DId = 0;
6363 const _v1$2 = new Vector3();
6364 const _q1 = new Quaternion();
6365 const _m1$1 = new Matrix4();
6366 const _target = new Vector3();
6368 const _position = new Vector3();
6369 const _scale = new Vector3();
6370 const _quaternion$2 = new Quaternion();
6372 const _xAxis = new Vector3( 1, 0, 0 );
6373 const _yAxis = new Vector3( 0, 1, 0 );
6374 const _zAxis = new Vector3( 0, 0, 1 );
6376 const _addedEvent = { type: 'added' };
6377 const _removedEvent = { type: 'removed' };
6379 function Object3D() {
6381 Object.defineProperty( this, 'id', { value: _object3DId ++ } );
6383 this.uuid = MathUtils.generateUUID();
6386 this.type = 'Object3D';
6391 this.up = Object3D.DefaultUp.clone();
6393 const position = new Vector3();
6394 const rotation = new Euler();
6395 const quaternion = new Quaternion();
6396 const scale = new Vector3( 1, 1, 1 );
6398 function onRotationChange() {
6400 quaternion.setFromEuler( rotation, false );
6404 function onQuaternionChange() {
6406 rotation.setFromQuaternion( quaternion, undefined, false );
6410 rotation._onChange( onRotationChange );
6411 quaternion._onChange( onQuaternionChange );
6413 Object.defineProperties( this, {
6435 value: new Matrix4()
6438 value: new Matrix3()
6442 this.matrix = new Matrix4();
6443 this.matrixWorld = new Matrix4();
6445 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
6446 this.matrixWorldNeedsUpdate = false;
6448 this.layers = new Layers();
6449 this.visible = true;
6451 this.castShadow = false;
6452 this.receiveShadow = false;
6454 this.frustumCulled = true;
6455 this.renderOrder = 0;
6457 this.animations = [];
6463 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
6464 Object3D.DefaultMatrixAutoUpdate = true;
6466 Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
6468 constructor: Object3D,
6472 onBeforeRender: function () {},
6473 onAfterRender: function () {},
6475 applyMatrix4: function ( matrix ) {
6477 if ( this.matrixAutoUpdate ) this.updateMatrix();
6479 this.matrix.premultiply( matrix );
6481 this.matrix.decompose( this.position, this.quaternion, this.scale );
6485 applyQuaternion: function ( q ) {
6487 this.quaternion.premultiply( q );
6493 setRotationFromAxisAngle: function ( axis, angle ) {
6495 // assumes axis is normalized
6497 this.quaternion.setFromAxisAngle( axis, angle );
6501 setRotationFromEuler: function ( euler ) {
6503 this.quaternion.setFromEuler( euler, true );
6507 setRotationFromMatrix: function ( m ) {
6509 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6511 this.quaternion.setFromRotationMatrix( m );
6515 setRotationFromQuaternion: function ( q ) {
6517 // assumes q is normalized
6519 this.quaternion.copy( q );
6523 rotateOnAxis: function ( axis, angle ) {
6525 // rotate object on axis in object space
6526 // axis is assumed to be normalized
6528 _q1.setFromAxisAngle( axis, angle );
6530 this.quaternion.multiply( _q1 );
6536 rotateOnWorldAxis: function ( axis, angle ) {
6538 // rotate object on axis in world space
6539 // axis is assumed to be normalized
6540 // method assumes no rotated parent
6542 _q1.setFromAxisAngle( axis, angle );
6544 this.quaternion.premultiply( _q1 );
6550 rotateX: function ( angle ) {
6552 return this.rotateOnAxis( _xAxis, angle );
6556 rotateY: function ( angle ) {
6558 return this.rotateOnAxis( _yAxis, angle );
6562 rotateZ: function ( angle ) {
6564 return this.rotateOnAxis( _zAxis, angle );
6568 translateOnAxis: function ( axis, distance ) {
6570 // translate object by distance along axis in object space
6571 // axis is assumed to be normalized
6573 _v1$2.copy( axis ).applyQuaternion( this.quaternion );
6575 this.position.add( _v1$2.multiplyScalar( distance ) );
6581 translateX: function ( distance ) {
6583 return this.translateOnAxis( _xAxis, distance );
6587 translateY: function ( distance ) {
6589 return this.translateOnAxis( _yAxis, distance );
6593 translateZ: function ( distance ) {
6595 return this.translateOnAxis( _zAxis, distance );
6599 localToWorld: function ( vector ) {
6601 return vector.applyMatrix4( this.matrixWorld );
6605 worldToLocal: function ( vector ) {
6607 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
6611 lookAt: function ( x, y, z ) {
6613 // This method does not support objects having non-uniformly-scaled parent(s)
6615 if ( x.isVector3 ) {
6621 _target.set( x, y, z );
6625 const parent = this.parent;
6627 this.updateWorldMatrix( true, false );
6629 _position.setFromMatrixPosition( this.matrixWorld );
6631 if ( this.isCamera || this.isLight ) {
6633 _m1$1.lookAt( _position, _target, this.up );
6637 _m1$1.lookAt( _target, _position, this.up );
6641 this.quaternion.setFromRotationMatrix( _m1$1 );
6645 _m1$1.extractRotation( parent.matrixWorld );
6646 _q1.setFromRotationMatrix( _m1$1 );
6647 this.quaternion.premultiply( _q1.invert() );
6653 add: function ( object ) {
6655 if ( arguments.length > 1 ) {
6657 for ( let i = 0; i < arguments.length; i ++ ) {
6659 this.add( arguments[ i ] );
6667 if ( object === this ) {
6669 console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
6674 if ( object && object.isObject3D ) {
6676 if ( object.parent !== null ) {
6678 object.parent.remove( object );
6682 object.parent = this;
6683 this.children.push( object );
6685 object.dispatchEvent( _addedEvent );
6689 console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
6697 remove: function ( object ) {
6699 if ( arguments.length > 1 ) {
6701 for ( let i = 0; i < arguments.length; i ++ ) {
6703 this.remove( arguments[ i ] );
6711 const index = this.children.indexOf( object );
6713 if ( index !== - 1 ) {
6715 object.parent = null;
6716 this.children.splice( index, 1 );
6718 object.dispatchEvent( _removedEvent );
6726 clear: function () {
6728 for ( let i = 0; i < this.children.length; i ++ ) {
6730 const object = this.children[ i ];
6732 object.parent = null;
6734 object.dispatchEvent( _removedEvent );
6738 this.children.length = 0;
6745 attach: function ( object ) {
6747 // adds object as a child of this, while maintaining the object's world transform
6749 this.updateWorldMatrix( true, false );
6751 _m1$1.copy( this.matrixWorld ).invert();
6753 if ( object.parent !== null ) {
6755 object.parent.updateWorldMatrix( true, false );
6757 _m1$1.multiply( object.parent.matrixWorld );
6761 object.applyMatrix4( _m1$1 );
6763 object.updateWorldMatrix( false, false );
6771 getObjectById: function ( id ) {
6773 return this.getObjectByProperty( 'id', id );
6777 getObjectByName: function ( name ) {
6779 return this.getObjectByProperty( 'name', name );
6783 getObjectByProperty: function ( name, value ) {
6785 if ( this[ name ] === value ) return this;
6787 for ( let i = 0, l = this.children.length; i < l; i ++ ) {
6789 const child = this.children[ i ];
6790 const object = child.getObjectByProperty( name, value );
6792 if ( object !== undefined ) {
6804 getWorldPosition: function ( target ) {
6806 if ( target === undefined ) {
6808 console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
6809 target = new Vector3();
6813 this.updateWorldMatrix( true, false );
6815 return target.setFromMatrixPosition( this.matrixWorld );
6819 getWorldQuaternion: function ( target ) {
6821 if ( target === undefined ) {
6823 console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
6824 target = new Quaternion();
6828 this.updateWorldMatrix( true, false );
6830 this.matrixWorld.decompose( _position, target, _scale );
6836 getWorldScale: function ( target ) {
6838 if ( target === undefined ) {
6840 console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
6841 target = new Vector3();
6845 this.updateWorldMatrix( true, false );
6847 this.matrixWorld.decompose( _position, _quaternion$2, target );
6853 getWorldDirection: function ( target ) {
6855 if ( target === undefined ) {
6857 console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' );
6858 target = new Vector3();
6862 this.updateWorldMatrix( true, false );
6864 const e = this.matrixWorld.elements;
6866 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
6870 raycast: function () {},
6872 traverse: function ( callback ) {
6876 const children = this.children;
6878 for ( let i = 0, l = children.length; i < l; i ++ ) {
6880 children[ i ].traverse( callback );
6886 traverseVisible: function ( callback ) {
6888 if ( this.visible === false ) return;
6892 const children = this.children;
6894 for ( let i = 0, l = children.length; i < l; i ++ ) {
6896 children[ i ].traverseVisible( callback );
6902 traverseAncestors: function ( callback ) {
6904 const parent = this.parent;
6906 if ( parent !== null ) {
6910 parent.traverseAncestors( callback );
6916 updateMatrix: function () {
6918 this.matrix.compose( this.position, this.quaternion, this.scale );
6920 this.matrixWorldNeedsUpdate = true;
6924 updateMatrixWorld: function ( force ) {
6926 if ( this.matrixAutoUpdate ) this.updateMatrix();
6928 if ( this.matrixWorldNeedsUpdate || force ) {
6930 if ( this.parent === null ) {
6932 this.matrixWorld.copy( this.matrix );
6936 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
6940 this.matrixWorldNeedsUpdate = false;
6948 const children = this.children;
6950 for ( let i = 0, l = children.length; i < l; i ++ ) {
6952 children[ i ].updateMatrixWorld( force );
6958 updateWorldMatrix: function ( updateParents, updateChildren ) {
6960 const parent = this.parent;
6962 if ( updateParents === true && parent !== null ) {
6964 parent.updateWorldMatrix( true, false );
6968 if ( this.matrixAutoUpdate ) this.updateMatrix();
6970 if ( this.parent === null ) {
6972 this.matrixWorld.copy( this.matrix );
6976 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
6982 if ( updateChildren === true ) {
6984 const children = this.children;
6986 for ( let i = 0, l = children.length; i < l; i ++ ) {
6988 children[ i ].updateWorldMatrix( false, true );
6996 toJSON: function ( meta ) {
6998 // meta is a string when called from JSON.stringify
6999 const isRootObject = ( meta === undefined || typeof meta === 'string' );
7003 // meta is a hash used to collect geometries, materials.
7004 // not providing it implies that this is the root object
7005 // being serialized.
7006 if ( isRootObject ) {
7008 // initialize meta obj
7022 generator: 'Object3D.toJSON'
7027 // standard Object3D serialization
7031 object.uuid = this.uuid;
7032 object.type = this.type;
7034 if ( this.name !== '' ) object.name = this.name;
7035 if ( this.castShadow === true ) object.castShadow = true;
7036 if ( this.receiveShadow === true ) object.receiveShadow = true;
7037 if ( this.visible === false ) object.visible = false;
7038 if ( this.frustumCulled === false ) object.frustumCulled = false;
7039 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
7040 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
7042 object.layers = this.layers.mask;
7043 object.matrix = this.matrix.toArray();
7045 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
7047 // object specific properties
7049 if ( this.isInstancedMesh ) {
7051 object.type = 'InstancedMesh';
7052 object.count = this.count;
7053 object.instanceMatrix = this.instanceMatrix.toJSON();
7059 function serialize( library, element ) {
7061 if ( library[ element.uuid ] === undefined ) {
7063 library[ element.uuid ] = element.toJSON( meta );
7067 return element.uuid;
7071 if ( this.isMesh || this.isLine || this.isPoints ) {
7073 object.geometry = serialize( meta.geometries, this.geometry );
7075 const parameters = this.geometry.parameters;
7077 if ( parameters !== undefined && parameters.shapes !== undefined ) {
7079 const shapes = parameters.shapes;
7081 if ( Array.isArray( shapes ) ) {
7083 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
7085 const shape = shapes[ i ];
7087 serialize( meta.shapes, shape );
7093 serialize( meta.shapes, shapes );
7101 if ( this.isSkinnedMesh ) {
7103 object.bindMode = this.bindMode;
7104 object.bindMatrix = this.bindMatrix.toArray();
7106 if ( this.skeleton !== undefined ) {
7108 serialize( meta.skeletons, this.skeleton );
7110 object.skeleton = this.skeleton.uuid;
7116 if ( this.material !== undefined ) {
7118 if ( Array.isArray( this.material ) ) {
7122 for ( let i = 0, l = this.material.length; i < l; i ++ ) {
7124 uuids.push( serialize( meta.materials, this.material[ i ] ) );
7128 object.material = uuids;
7132 object.material = serialize( meta.materials, this.material );
7140 if ( this.children.length > 0 ) {
7142 object.children = [];
7144 for ( let i = 0; i < this.children.length; i ++ ) {
7146 object.children.push( this.children[ i ].toJSON( meta ).object );
7154 if ( this.animations.length > 0 ) {
7156 object.animations = [];
7158 for ( let i = 0; i < this.animations.length; i ++ ) {
7160 const animation = this.animations[ i ];
7162 object.animations.push( serialize( meta.animations, animation ) );
7168 if ( isRootObject ) {
7170 const geometries = extractFromCache( meta.geometries );
7171 const materials = extractFromCache( meta.materials );
7172 const textures = extractFromCache( meta.textures );
7173 const images = extractFromCache( meta.images );
7174 const shapes = extractFromCache( meta.shapes );
7175 const skeletons = extractFromCache( meta.skeletons );
7176 const animations = extractFromCache( meta.animations );
7178 if ( geometries.length > 0 ) output.geometries = geometries;
7179 if ( materials.length > 0 ) output.materials = materials;
7180 if ( textures.length > 0 ) output.textures = textures;
7181 if ( images.length > 0 ) output.images = images;
7182 if ( shapes.length > 0 ) output.shapes = shapes;
7183 if ( skeletons.length > 0 ) output.skeletons = skeletons;
7184 if ( animations.length > 0 ) output.animations = animations;
7188 output.object = object;
7192 // extract data from the cache hash
7193 // remove metadata on each item
7194 // and return as array
7195 function extractFromCache( cache ) {
7198 for ( const key in cache ) {
7200 const data = cache[ key ];
7201 delete data.metadata;
7202 values.push( data );
7212 clone: function ( recursive ) {
7214 return new this.constructor().copy( this, recursive );
7218 copy: function ( source, recursive = true ) {
7220 this.name = source.name;
7222 this.up.copy( source.up );
7224 this.position.copy( source.position );
7225 this.rotation.order = source.rotation.order;
7226 this.quaternion.copy( source.quaternion );
7227 this.scale.copy( source.scale );
7229 this.matrix.copy( source.matrix );
7230 this.matrixWorld.copy( source.matrixWorld );
7232 this.matrixAutoUpdate = source.matrixAutoUpdate;
7233 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
7235 this.layers.mask = source.layers.mask;
7236 this.visible = source.visible;
7238 this.castShadow = source.castShadow;
7239 this.receiveShadow = source.receiveShadow;
7241 this.frustumCulled = source.frustumCulled;
7242 this.renderOrder = source.renderOrder;
7244 this.userData = JSON.parse( JSON.stringify( source.userData ) );
7246 if ( recursive === true ) {
7248 for ( let i = 0; i < source.children.length; i ++ ) {
7250 const child = source.children[ i ];
7251 this.add( child.clone() );
7263 const _vector1 = /*@__PURE__*/ new Vector3();
7264 const _vector2 = /*@__PURE__*/ new Vector3();
7265 const _normalMatrix = /*@__PURE__*/ new Matrix3();
7269 constructor( normal, constant ) {
7271 Object.defineProperty( this, 'isPlane', { value: true } );
7273 // normal is assumed to be normalized
7275 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
7276 this.constant = ( constant !== undefined ) ? constant : 0;
7280 set( normal, constant ) {
7282 this.normal.copy( normal );
7283 this.constant = constant;
7289 setComponents( x, y, z, w ) {
7291 this.normal.set( x, y, z );
7298 setFromNormalAndCoplanarPoint( normal, point ) {
7300 this.normal.copy( normal );
7301 this.constant = - point.dot( this.normal );
7307 setFromCoplanarPoints( a, b, c ) {
7309 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
7311 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
7313 this.setFromNormalAndCoplanarPoint( normal, a );
7321 return new this.constructor().copy( this );
7327 this.normal.copy( plane.normal );
7328 this.constant = plane.constant;
7336 // Note: will lead to a divide by zero if the plane is invalid.
7338 const inverseNormalLength = 1.0 / this.normal.length();
7339 this.normal.multiplyScalar( inverseNormalLength );
7340 this.constant *= inverseNormalLength;
7348 this.constant *= - 1;
7349 this.normal.negate();
7355 distanceToPoint( point ) {
7357 return this.normal.dot( point ) + this.constant;
7361 distanceToSphere( sphere ) {
7363 return this.distanceToPoint( sphere.center ) - sphere.radius;
7367 projectPoint( point, target ) {
7369 if ( target === undefined ) {
7371 console.warn( 'THREE.Plane: .projectPoint() target is now required' );
7372 target = new Vector3();
7376 return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
7380 intersectLine( line, target ) {
7382 if ( target === undefined ) {
7384 console.warn( 'THREE.Plane: .intersectLine() target is now required' );
7385 target = new Vector3();
7389 const direction = line.delta( _vector1 );
7391 const denominator = this.normal.dot( direction );
7393 if ( denominator === 0 ) {
7395 // line is coplanar, return origin
7396 if ( this.distanceToPoint( line.start ) === 0 ) {
7398 return target.copy( line.start );
7402 // Unsure if this is the correct method to handle this case.
7407 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
7409 if ( t < 0 || t > 1 ) {
7415 return target.copy( direction ).multiplyScalar( t ).add( line.start );
7419 intersectsLine( line ) {
7421 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
7423 const startSign = this.distanceToPoint( line.start );
7424 const endSign = this.distanceToPoint( line.end );
7426 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
7430 intersectsBox( box ) {
7432 return box.intersectsPlane( this );
7436 intersectsSphere( sphere ) {
7438 return sphere.intersectsPlane( this );
7442 coplanarPoint( target ) {
7444 if ( target === undefined ) {
7446 console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
7447 target = new Vector3();
7451 return target.copy( this.normal ).multiplyScalar( - this.constant );
7455 applyMatrix4( matrix, optionalNormalMatrix ) {
7457 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
7459 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
7461 const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
7463 this.constant = - referencePoint.dot( normal );
7469 translate( offset ) {
7471 this.constant -= offset.dot( this.normal );
7479 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
7485 const _v0$1 = /*@__PURE__*/ new Vector3();
7486 const _v1$3 = /*@__PURE__*/ new Vector3();
7487 const _v2$1 = /*@__PURE__*/ new Vector3();
7488 const _v3 = /*@__PURE__*/ new Vector3();
7490 const _vab = /*@__PURE__*/ new Vector3();
7491 const _vac = /*@__PURE__*/ new Vector3();
7492 const _vbc = /*@__PURE__*/ new Vector3();
7493 const _vap = /*@__PURE__*/ new Vector3();
7494 const _vbp = /*@__PURE__*/ new Vector3();
7495 const _vcp = /*@__PURE__*/ new Vector3();
7499 constructor( a, b, c ) {
7501 this.a = ( a !== undefined ) ? a : new Vector3();
7502 this.b = ( b !== undefined ) ? b : new Vector3();
7503 this.c = ( c !== undefined ) ? c : new Vector3();
7507 static getNormal( a, b, c, target ) {
7509 if ( target === undefined ) {
7511 console.warn( 'THREE.Triangle: .getNormal() target is now required' );
7512 target = new Vector3();
7516 target.subVectors( c, b );
7517 _v0$1.subVectors( a, b );
7518 target.cross( _v0$1 );
7520 const targetLengthSq = target.lengthSq();
7521 if ( targetLengthSq > 0 ) {
7523 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
7527 return target.set( 0, 0, 0 );
7531 // static/instance method to calculate barycentric coordinates
7532 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
7533 static getBarycoord( point, a, b, c, target ) {
7535 _v0$1.subVectors( c, a );
7536 _v1$3.subVectors( b, a );
7537 _v2$1.subVectors( point, a );
7539 const dot00 = _v0$1.dot( _v0$1 );
7540 const dot01 = _v0$1.dot( _v1$3 );
7541 const dot02 = _v0$1.dot( _v2$1 );
7542 const dot11 = _v1$3.dot( _v1$3 );
7543 const dot12 = _v1$3.dot( _v2$1 );
7545 const denom = ( dot00 * dot11 - dot01 * dot01 );
7547 if ( target === undefined ) {
7549 console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
7550 target = new Vector3();
7554 // collinear or singular triangle
7555 if ( denom === 0 ) {
7557 // arbitrary location outside of triangle?
7558 // not sure if this is the best idea, maybe should be returning undefined
7559 return target.set( - 2, - 1, - 1 );
7563 const invDenom = 1 / denom;
7564 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
7565 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
7567 // barycentric coordinates must always sum to 1
7568 return target.set( 1 - u - v, v, u );
7572 static containsPoint( point, a, b, c ) {
7574 this.getBarycoord( point, a, b, c, _v3 );
7576 return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
7580 static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
7582 this.getBarycoord( point, p1, p2, p3, _v3 );
7585 target.addScaledVector( uv1, _v3.x );
7586 target.addScaledVector( uv2, _v3.y );
7587 target.addScaledVector( uv3, _v3.z );
7593 static isFrontFacing( a, b, c, direction ) {
7595 _v0$1.subVectors( c, b );
7596 _v1$3.subVectors( a, b );
7598 // strictly front facing
7599 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
7613 setFromPointsAndIndices( points, i0, i1, i2 ) {
7615 this.a.copy( points[ i0 ] );
7616 this.b.copy( points[ i1 ] );
7617 this.c.copy( points[ i2 ] );
7625 return new this.constructor().copy( this );
7631 this.a.copy( triangle.a );
7632 this.b.copy( triangle.b );
7633 this.c.copy( triangle.c );
7641 _v0$1.subVectors( this.c, this.b );
7642 _v1$3.subVectors( this.a, this.b );
7644 return _v0$1.cross( _v1$3 ).length() * 0.5;
7648 getMidpoint( target ) {
7650 if ( target === undefined ) {
7652 console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
7653 target = new Vector3();
7657 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
7661 getNormal( target ) {
7663 return Triangle.getNormal( this.a, this.b, this.c, target );
7667 getPlane( target ) {
7669 if ( target === undefined ) {
7671 console.warn( 'THREE.Triangle: .getPlane() target is now required' );
7672 target = new Plane();
7676 return target.setFromCoplanarPoints( this.a, this.b, this.c );
7680 getBarycoord( point, target ) {
7682 return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
7686 getUV( point, uv1, uv2, uv3, target ) {
7688 return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
7692 containsPoint( point ) {
7694 return Triangle.containsPoint( point, this.a, this.b, this.c );
7698 isFrontFacing( direction ) {
7700 return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
7704 intersectsBox( box ) {
7706 return box.intersectsTriangle( this );
7710 closestPointToPoint( p, target ) {
7712 if ( target === undefined ) {
7714 console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
7715 target = new Vector3();
7719 const a = this.a, b = this.b, c = this.c;
7722 // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
7723 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
7724 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
7725 // basically, we're distinguishing which of the voronoi regions of the triangle
7726 // the point lies in with the minimum amount of redundant computation.
7728 _vab.subVectors( b, a );
7729 _vac.subVectors( c, a );
7730 _vap.subVectors( p, a );
7731 const d1 = _vab.dot( _vap );
7732 const d2 = _vac.dot( _vap );
7733 if ( d1 <= 0 && d2 <= 0 ) {
7735 // vertex region of A; barycentric coords (1, 0, 0)
7736 return target.copy( a );
7740 _vbp.subVectors( p, b );
7741 const d3 = _vab.dot( _vbp );
7742 const d4 = _vac.dot( _vbp );
7743 if ( d3 >= 0 && d4 <= d3 ) {
7745 // vertex region of B; barycentric coords (0, 1, 0)
7746 return target.copy( b );
7750 const vc = d1 * d4 - d3 * d2;
7751 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
7753 v = d1 / ( d1 - d3 );
7754 // edge region of AB; barycentric coords (1-v, v, 0)
7755 return target.copy( a ).addScaledVector( _vab, v );
7759 _vcp.subVectors( p, c );
7760 const d5 = _vab.dot( _vcp );
7761 const d6 = _vac.dot( _vcp );
7762 if ( d6 >= 0 && d5 <= d6 ) {
7764 // vertex region of C; barycentric coords (0, 0, 1)
7765 return target.copy( c );
7769 const vb = d5 * d2 - d1 * d6;
7770 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
7772 w = d2 / ( d2 - d6 );
7773 // edge region of AC; barycentric coords (1-w, 0, w)
7774 return target.copy( a ).addScaledVector( _vac, w );
7778 const va = d3 * d6 - d5 * d4;
7779 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
7781 _vbc.subVectors( c, b );
7782 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
7783 // edge region of BC; barycentric coords (0, 1-w, w)
7784 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
7789 const denom = 1 / ( va + vb + vc );
7794 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
7798 equals( triangle ) {
7800 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
7806 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
7807 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
7808 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
7809 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
7810 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
7811 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
7812 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
7813 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
7814 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
7815 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
7816 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
7817 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
7818 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
7819 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
7820 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
7821 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
7822 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
7823 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
7824 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
7825 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
7826 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
7827 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
7828 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
7829 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
7831 const _hslA = { h: 0, s: 0, l: 0 };
7832 const _hslB = { h: 0, s: 0, l: 0 };
7834 function hue2rgb( p, q, t ) {
7836 if ( t < 0 ) t += 1;
7837 if ( t > 1 ) t -= 1;
7838 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
7839 if ( t < 1 / 2 ) return q;
7840 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
7845 function SRGBToLinear( c ) {
7847 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
7851 function LinearToSRGB( c ) {
7853 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
7859 constructor( r, g, b ) {
7861 Object.defineProperty( this, 'isColor', { value: true } );
7863 if ( g === undefined && b === undefined ) {
7865 // r is THREE.Color, hex or string
7866 return this.set( r );
7870 return this.setRGB( r, g, b );
7876 if ( value && value.isColor ) {
7880 } else if ( typeof value === 'number' ) {
7882 this.setHex( value );
7884 } else if ( typeof value === 'string' ) {
7886 this.setStyle( value );
7894 setScalar( scalar ) {
7906 hex = Math.floor( hex );
7908 this.r = ( hex >> 16 & 255 ) / 255;
7909 this.g = ( hex >> 8 & 255 ) / 255;
7910 this.b = ( hex & 255 ) / 255;
7928 // h,s,l ranges are in 0.0 - 1.0
7929 h = MathUtils.euclideanModulo( h, 1 );
7930 s = MathUtils.clamp( s, 0, 1 );
7931 l = MathUtils.clamp( l, 0, 1 );
7935 this.r = this.g = this.b = l;
7939 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
7940 const q = ( 2 * l ) - p;
7942 this.r = hue2rgb( q, p, h + 1 / 3 );
7943 this.g = hue2rgb( q, p, h );
7944 this.b = hue2rgb( q, p, h - 1 / 3 );
7954 function handleAlpha( string ) {
7956 if ( string === undefined ) return;
7958 if ( parseFloat( string ) < 1 ) {
7960 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
7969 if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) {
7974 const name = m[ 1 ];
7975 const components = m[ 2 ];
7982 if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
7984 // rgb(255,0,0) rgba(255,0,0,0.5)
7985 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
7986 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
7987 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
7989 handleAlpha( color[ 4 ] );
7995 if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
7997 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
7998 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
7999 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
8000 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
8002 handleAlpha( color[ 4 ] );
8013 if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8015 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
8016 const h = parseFloat( color[ 1 ] ) / 360;
8017 const s = parseInt( color[ 2 ], 10 ) / 100;
8018 const l = parseInt( color[ 3 ], 10 ) / 100;
8020 handleAlpha( color[ 4 ] );
8022 return this.setHSL( h, s, l );
8030 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
8035 const size = hex.length;
8040 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
8041 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
8042 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
8046 } else if ( size === 6 ) {
8049 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
8050 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
8051 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
8059 if ( style && style.length > 0 ) {
8061 return this.setColorName( style );
8069 setColorName( style ) {
8072 const hex = _colorKeywords[ style ];
8074 if ( hex !== undefined ) {
8082 console.warn( 'THREE.Color: Unknown color ' + style );
8092 return new this.constructor( this.r, this.g, this.b );
8106 copyGammaToLinear( color, gammaFactor = 2.0 ) {
8108 this.r = Math.pow( color.r, gammaFactor );
8109 this.g = Math.pow( color.g, gammaFactor );
8110 this.b = Math.pow( color.b, gammaFactor );
8116 copyLinearToGamma( color, gammaFactor = 2.0 ) {
8118 const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
8120 this.r = Math.pow( color.r, safeInverse );
8121 this.g = Math.pow( color.g, safeInverse );
8122 this.b = Math.pow( color.b, safeInverse );
8128 convertGammaToLinear( gammaFactor ) {
8130 this.copyGammaToLinear( this, gammaFactor );
8136 convertLinearToGamma( gammaFactor ) {
8138 this.copyLinearToGamma( this, gammaFactor );
8144 copySRGBToLinear( color ) {
8146 this.r = SRGBToLinear( color.r );
8147 this.g = SRGBToLinear( color.g );
8148 this.b = SRGBToLinear( color.b );
8154 copyLinearToSRGB( color ) {
8156 this.r = LinearToSRGB( color.r );
8157 this.g = LinearToSRGB( color.g );
8158 this.b = LinearToSRGB( color.b );
8164 convertSRGBToLinear() {
8166 this.copySRGBToLinear( this );
8172 convertLinearToSRGB() {
8174 this.copyLinearToSRGB( this );
8182 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
8188 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
8194 // h,s,l ranges are in 0.0 - 1.0
8196 if ( target === undefined ) {
8198 console.warn( 'THREE.Color: .getHSL() target is now required' );
8199 target = { h: 0, s: 0, l: 0 };
8203 const r = this.r, g = this.g, b = this.b;
8205 const max = Math.max( r, g, b );
8206 const min = Math.min( r, g, b );
8208 let hue, saturation;
8209 const lightness = ( min + max ) / 2.0;
8211 if ( min === max ) {
8218 const delta = max - min;
8220 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
8224 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
8225 case g: hue = ( b - r ) / delta + 2; break;
8226 case b: hue = ( r - g ) / delta + 4; break;
8235 target.s = saturation;
8236 target.l = lightness;
8244 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
8248 offsetHSL( h, s, l ) {
8250 this.getHSL( _hslA );
8252 _hslA.h += h; _hslA.s += s; _hslA.l += l;
8254 this.setHSL( _hslA.h, _hslA.s, _hslA.l );
8270 addColors( color1, color2 ) {
8272 this.r = color1.r + color2.r;
8273 this.g = color1.g + color2.g;
8274 this.b = color1.b + color2.b;
8292 this.r = Math.max( 0, this.r - color.r );
8293 this.g = Math.max( 0, this.g - color.g );
8294 this.b = Math.max( 0, this.b - color.b );
8310 multiplyScalar( s ) {
8320 lerp( color, alpha ) {
8322 this.r += ( color.r - this.r ) * alpha;
8323 this.g += ( color.g - this.g ) * alpha;
8324 this.b += ( color.b - this.b ) * alpha;
8330 lerpColors( color1, color2, alpha ) {
8332 this.r = color1.r + ( color2.r - color1.r ) * alpha;
8333 this.g = color1.g + ( color2.g - color1.g ) * alpha;
8334 this.b = color1.b + ( color2.b - color1.b ) * alpha;
8340 lerpHSL( color, alpha ) {
8342 this.getHSL( _hslA );
8343 color.getHSL( _hslB );
8345 const h = MathUtils.lerp( _hslA.h, _hslB.h, alpha );
8346 const s = MathUtils.lerp( _hslA.s, _hslB.s, alpha );
8347 const l = MathUtils.lerp( _hslA.l, _hslB.l, alpha );
8349 this.setHSL( h, s, l );
8357 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
8361 fromArray( array, offset = 0 ) {
8363 this.r = array[ offset ];
8364 this.g = array[ offset + 1 ];
8365 this.b = array[ offset + 2 ];
8371 toArray( array = [], offset = 0 ) {
8373 array[ offset ] = this.r;
8374 array[ offset + 1 ] = this.g;
8375 array[ offset + 2 ] = this.b;
8381 fromBufferAttribute( attribute, index ) {
8383 this.r = attribute.getX( index );
8384 this.g = attribute.getY( index );
8385 this.b = attribute.getZ( index );
8387 if ( attribute.normalized === true ) {
8389 // assuming Uint8Array
8403 return this.getHex();
8409 Color.NAMES = _colorKeywords;
8410 Color.prototype.r = 1;
8411 Color.prototype.g = 1;
8412 Color.prototype.b = 1;
8416 constructor( a, b, c, normal, color, materialIndex = 0 ) {
8422 this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
8423 this.vertexNormals = Array.isArray( normal ) ? normal : [];
8425 this.color = ( color && color.isColor ) ? color : new Color();
8426 this.vertexColors = Array.isArray( color ) ? color : [];
8428 this.materialIndex = materialIndex;
8434 return new this.constructor().copy( this );
8444 this.normal.copy( source.normal );
8445 this.color.copy( source.color );
8447 this.materialIndex = source.materialIndex;
8449 for ( let i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
8451 this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
8455 for ( let i = 0, il = source.vertexColors.length; i < il; i ++ ) {
8457 this.vertexColors[ i ] = source.vertexColors[ i ].clone();
8469 function Material() {
8471 Object.defineProperty( this, 'id', { value: materialId ++ } );
8473 this.uuid = MathUtils.generateUUID();
8476 this.type = 'Material';
8480 this.blending = NormalBlending;
8481 this.side = FrontSide;
8482 this.flatShading = false;
8483 this.vertexColors = false;
8486 this.transparent = false;
8488 this.blendSrc = SrcAlphaFactor;
8489 this.blendDst = OneMinusSrcAlphaFactor;
8490 this.blendEquation = AddEquation;
8491 this.blendSrcAlpha = null;
8492 this.blendDstAlpha = null;
8493 this.blendEquationAlpha = null;
8495 this.depthFunc = LessEqualDepth;
8496 this.depthTest = true;
8497 this.depthWrite = true;
8499 this.stencilWriteMask = 0xff;
8500 this.stencilFunc = AlwaysStencilFunc;
8501 this.stencilRef = 0;
8502 this.stencilFuncMask = 0xff;
8503 this.stencilFail = KeepStencilOp;
8504 this.stencilZFail = KeepStencilOp;
8505 this.stencilZPass = KeepStencilOp;
8506 this.stencilWrite = false;
8508 this.clippingPlanes = null;
8509 this.clipIntersection = false;
8510 this.clipShadows = false;
8512 this.shadowSide = null;
8514 this.colorWrite = true;
8516 this.precision = null; // override the renderer's default precision for this material
8518 this.polygonOffset = false;
8519 this.polygonOffsetFactor = 0;
8520 this.polygonOffsetUnits = 0;
8522 this.dithering = false;
8525 this.premultipliedAlpha = false;
8527 this.visible = true;
8529 this.toneMapped = true;
8537 Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
8539 constructor: Material,
8543 onBeforeCompile: function ( /* shaderobject, renderer */ ) {},
8545 customProgramCacheKey: function () {
8547 return this.onBeforeCompile.toString();
8551 setValues: function ( values ) {
8553 if ( values === undefined ) return;
8555 for ( const key in values ) {
8557 const newValue = values[ key ];
8559 if ( newValue === undefined ) {
8561 console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
8566 // for backward compatability if shading is set in the constructor
8567 if ( key === 'shading' ) {
8569 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
8570 this.flatShading = ( newValue === FlatShading ) ? true : false;
8575 const currentValue = this[ key ];
8577 if ( currentValue === undefined ) {
8579 console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' );
8584 if ( currentValue && currentValue.isColor ) {
8586 currentValue.set( newValue );
8588 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
8590 currentValue.copy( newValue );
8594 this[ key ] = newValue;
8602 toJSON: function ( meta ) {
8604 const isRoot = ( meta === undefined || typeof meta === 'string' );
8619 generator: 'Material.toJSON'
8623 // standard Material serialization
8624 data.uuid = this.uuid;
8625 data.type = this.type;
8627 if ( this.name !== '' ) data.name = this.name;
8629 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
8631 if ( this.roughness !== undefined ) data.roughness = this.roughness;
8632 if ( this.metalness !== undefined ) data.metalness = this.metalness;
8634 if ( this.sheen && this.sheen.isColor ) data.sheen = this.sheen.getHex();
8635 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
8636 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
8638 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
8639 if ( this.shininess !== undefined ) data.shininess = this.shininess;
8640 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
8641 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
8643 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
8645 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
8649 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
8651 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
8655 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
8657 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
8658 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
8662 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
8663 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
8664 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
8665 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
8667 if ( this.aoMap && this.aoMap.isTexture ) {
8669 data.aoMap = this.aoMap.toJSON( meta ).uuid;
8670 data.aoMapIntensity = this.aoMapIntensity;
8674 if ( this.bumpMap && this.bumpMap.isTexture ) {
8676 data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
8677 data.bumpScale = this.bumpScale;
8681 if ( this.normalMap && this.normalMap.isTexture ) {
8683 data.normalMap = this.normalMap.toJSON( meta ).uuid;
8684 data.normalMapType = this.normalMapType;
8685 data.normalScale = this.normalScale.toArray();
8689 if ( this.displacementMap && this.displacementMap.isTexture ) {
8691 data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
8692 data.displacementScale = this.displacementScale;
8693 data.displacementBias = this.displacementBias;
8697 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
8698 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
8700 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
8701 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
8703 if ( this.envMap && this.envMap.isTexture ) {
8705 data.envMap = this.envMap.toJSON( meta ).uuid;
8706 data.reflectivity = this.reflectivity; // Scale behind envMap
8707 data.refractionRatio = this.refractionRatio;
8709 if ( this.combine !== undefined ) data.combine = this.combine;
8710 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
8714 if ( this.gradientMap && this.gradientMap.isTexture ) {
8716 data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
8720 if ( this.size !== undefined ) data.size = this.size;
8721 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
8723 if ( this.blending !== NormalBlending ) data.blending = this.blending;
8724 if ( this.flatShading === true ) data.flatShading = this.flatShading;
8725 if ( this.side !== FrontSide ) data.side = this.side;
8726 if ( this.vertexColors ) data.vertexColors = true;
8728 if ( this.opacity < 1 ) data.opacity = this.opacity;
8729 if ( this.transparent === true ) data.transparent = this.transparent;
8731 data.depthFunc = this.depthFunc;
8732 data.depthTest = this.depthTest;
8733 data.depthWrite = this.depthWrite;
8735 data.stencilWrite = this.stencilWrite;
8736 data.stencilWriteMask = this.stencilWriteMask;
8737 data.stencilFunc = this.stencilFunc;
8738 data.stencilRef = this.stencilRef;
8739 data.stencilFuncMask = this.stencilFuncMask;
8740 data.stencilFail = this.stencilFail;
8741 data.stencilZFail = this.stencilZFail;
8742 data.stencilZPass = this.stencilZPass;
8744 // rotation (SpriteMaterial)
8745 if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation;
8747 if ( this.polygonOffset === true ) data.polygonOffset = true;
8748 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
8749 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
8751 if ( this.linewidth && this.linewidth !== 1 ) data.linewidth = this.linewidth;
8752 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
8753 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
8754 if ( this.scale !== undefined ) data.scale = this.scale;
8756 if ( this.dithering === true ) data.dithering = true;
8758 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
8759 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
8761 if ( this.wireframe === true ) data.wireframe = this.wireframe;
8762 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
8763 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
8764 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
8766 if ( this.morphTargets === true ) data.morphTargets = true;
8767 if ( this.morphNormals === true ) data.morphNormals = true;
8768 if ( this.skinning === true ) data.skinning = true;
8770 if ( this.visible === false ) data.visible = false;
8772 if ( this.toneMapped === false ) data.toneMapped = false;
8774 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
8776 // TODO: Copied from Object3D.toJSON
8778 function extractFromCache( cache ) {
8782 for ( const key in cache ) {
8784 const data = cache[ key ];
8785 delete data.metadata;
8786 values.push( data );
8796 const textures = extractFromCache( meta.textures );
8797 const images = extractFromCache( meta.images );
8799 if ( textures.length > 0 ) data.textures = textures;
8800 if ( images.length > 0 ) data.images = images;
8808 clone: function () {
8810 return new this.constructor().copy( this );
8814 copy: function ( source ) {
8816 this.name = source.name;
8818 this.fog = source.fog;
8820 this.blending = source.blending;
8821 this.side = source.side;
8822 this.flatShading = source.flatShading;
8823 this.vertexColors = source.vertexColors;
8825 this.opacity = source.opacity;
8826 this.transparent = source.transparent;
8828 this.blendSrc = source.blendSrc;
8829 this.blendDst = source.blendDst;
8830 this.blendEquation = source.blendEquation;
8831 this.blendSrcAlpha = source.blendSrcAlpha;
8832 this.blendDstAlpha = source.blendDstAlpha;
8833 this.blendEquationAlpha = source.blendEquationAlpha;
8835 this.depthFunc = source.depthFunc;
8836 this.depthTest = source.depthTest;
8837 this.depthWrite = source.depthWrite;
8839 this.stencilWriteMask = source.stencilWriteMask;
8840 this.stencilFunc = source.stencilFunc;
8841 this.stencilRef = source.stencilRef;
8842 this.stencilFuncMask = source.stencilFuncMask;
8843 this.stencilFail = source.stencilFail;
8844 this.stencilZFail = source.stencilZFail;
8845 this.stencilZPass = source.stencilZPass;
8846 this.stencilWrite = source.stencilWrite;
8848 const srcPlanes = source.clippingPlanes;
8849 let dstPlanes = null;
8851 if ( srcPlanes !== null ) {
8853 const n = srcPlanes.length;
8854 dstPlanes = new Array( n );
8856 for ( let i = 0; i !== n; ++ i ) {
8858 dstPlanes[ i ] = srcPlanes[ i ].clone();
8864 this.clippingPlanes = dstPlanes;
8865 this.clipIntersection = source.clipIntersection;
8866 this.clipShadows = source.clipShadows;
8868 this.shadowSide = source.shadowSide;
8870 this.colorWrite = source.colorWrite;
8872 this.precision = source.precision;
8874 this.polygonOffset = source.polygonOffset;
8875 this.polygonOffsetFactor = source.polygonOffsetFactor;
8876 this.polygonOffsetUnits = source.polygonOffsetUnits;
8878 this.dithering = source.dithering;
8880 this.alphaTest = source.alphaTest;
8881 this.premultipliedAlpha = source.premultipliedAlpha;
8883 this.visible = source.visible;
8885 this.toneMapped = source.toneMapped;
8887 this.userData = JSON.parse( JSON.stringify( source.userData ) );
8893 dispose: function () {
8895 this.dispatchEvent( { type: 'dispose' } );
8901 Object.defineProperty( Material.prototype, 'needsUpdate', {
8903 set: function ( value ) {
8905 if ( value === true ) this.version ++;
8915 * map: new THREE.Texture( <Image> ),
8917 * lightMap: new THREE.Texture( <Image> ),
8918 * lightMapIntensity: <float>
8920 * aoMap: new THREE.Texture( <Image> ),
8921 * aoMapIntensity: <float>
8923 * specularMap: new THREE.Texture( <Image> ),
8925 * alphaMap: new THREE.Texture( <Image> ),
8927 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
8928 * combine: THREE.Multiply,
8929 * reflectivity: <float>,
8930 * refractionRatio: <float>,
8932 * depthTest: <bool>,
8933 * depthWrite: <bool>,
8935 * wireframe: <boolean>,
8936 * wireframeLinewidth: <float>,
8939 * morphTargets: <bool>
8943 function MeshBasicMaterial( parameters ) {
8945 Material.call( this );
8947 this.type = 'MeshBasicMaterial';
8949 this.color = new Color( 0xffffff ); // emissive
8953 this.lightMap = null;
8954 this.lightMapIntensity = 1.0;
8957 this.aoMapIntensity = 1.0;
8959 this.specularMap = null;
8961 this.alphaMap = null;
8964 this.combine = MultiplyOperation;
8965 this.reflectivity = 1;
8966 this.refractionRatio = 0.98;
8968 this.wireframe = false;
8969 this.wireframeLinewidth = 1;
8970 this.wireframeLinecap = 'round';
8971 this.wireframeLinejoin = 'round';
8973 this.skinning = false;
8974 this.morphTargets = false;
8976 this.setValues( parameters );
8980 MeshBasicMaterial.prototype = Object.create( Material.prototype );
8981 MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
8983 MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
8985 MeshBasicMaterial.prototype.copy = function ( source ) {
8987 Material.prototype.copy.call( this, source );
8989 this.color.copy( source.color );
8991 this.map = source.map;
8993 this.lightMap = source.lightMap;
8994 this.lightMapIntensity = source.lightMapIntensity;
8996 this.aoMap = source.aoMap;
8997 this.aoMapIntensity = source.aoMapIntensity;
8999 this.specularMap = source.specularMap;
9001 this.alphaMap = source.alphaMap;
9003 this.envMap = source.envMap;
9004 this.combine = source.combine;
9005 this.reflectivity = source.reflectivity;
9006 this.refractionRatio = source.refractionRatio;
9008 this.wireframe = source.wireframe;
9009 this.wireframeLinewidth = source.wireframeLinewidth;
9010 this.wireframeLinecap = source.wireframeLinecap;
9011 this.wireframeLinejoin = source.wireframeLinejoin;
9013 this.skinning = source.skinning;
9014 this.morphTargets = source.morphTargets;
9020 const _vector$3 = new Vector3();
9021 const _vector2$1 = new Vector2();
9023 function BufferAttribute( array, itemSize, normalized ) {
9025 if ( Array.isArray( array ) ) {
9027 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
9034 this.itemSize = itemSize;
9035 this.count = array !== undefined ? array.length / itemSize : 0;
9036 this.normalized = normalized === true;
9038 this.usage = StaticDrawUsage;
9039 this.updateRange = { offset: 0, count: - 1 };
9045 Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
9047 set: function ( value ) {
9049 if ( value === true ) this.version ++;
9055 Object.assign( BufferAttribute.prototype, {
9057 isBufferAttribute: true,
9059 onUploadCallback: function () {},
9061 setUsage: function ( value ) {
9069 copy: function ( source ) {
9071 this.name = source.name;
9072 this.array = new source.array.constructor( source.array );
9073 this.itemSize = source.itemSize;
9074 this.count = source.count;
9075 this.normalized = source.normalized;
9077 this.usage = source.usage;
9083 copyAt: function ( index1, attribute, index2 ) {
9085 index1 *= this.itemSize;
9086 index2 *= attribute.itemSize;
9088 for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
9090 this.array[ index1 + i ] = attribute.array[ index2 + i ];
9098 copyArray: function ( array ) {
9100 this.array.set( array );
9106 copyColorsArray: function ( colors ) {
9108 const array = this.array;
9111 for ( let i = 0, l = colors.length; i < l; i ++ ) {
9113 let color = colors[ i ];
9115 if ( color === undefined ) {
9117 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
9118 color = new Color();
9122 array[ offset ++ ] = color.r;
9123 array[ offset ++ ] = color.g;
9124 array[ offset ++ ] = color.b;
9132 copyVector2sArray: function ( vectors ) {
9134 const array = this.array;
9137 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9139 let vector = vectors[ i ];
9141 if ( vector === undefined ) {
9143 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
9144 vector = new Vector2();
9148 array[ offset ++ ] = vector.x;
9149 array[ offset ++ ] = vector.y;
9157 copyVector3sArray: function ( vectors ) {
9159 const array = this.array;
9162 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9164 let vector = vectors[ i ];
9166 if ( vector === undefined ) {
9168 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
9169 vector = new Vector3();
9173 array[ offset ++ ] = vector.x;
9174 array[ offset ++ ] = vector.y;
9175 array[ offset ++ ] = vector.z;
9183 copyVector4sArray: function ( vectors ) {
9185 const array = this.array;
9188 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9190 let vector = vectors[ i ];
9192 if ( vector === undefined ) {
9194 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
9195 vector = new Vector4();
9199 array[ offset ++ ] = vector.x;
9200 array[ offset ++ ] = vector.y;
9201 array[ offset ++ ] = vector.z;
9202 array[ offset ++ ] = vector.w;
9210 applyMatrix3: function ( m ) {
9212 if ( this.itemSize === 2 ) {
9214 for ( let i = 0, l = this.count; i < l; i ++ ) {
9216 _vector2$1.fromBufferAttribute( this, i );
9217 _vector2$1.applyMatrix3( m );
9219 this.setXY( i, _vector2$1.x, _vector2$1.y );
9223 } else if ( this.itemSize === 3 ) {
9225 for ( let i = 0, l = this.count; i < l; i ++ ) {
9227 _vector$3.fromBufferAttribute( this, i );
9228 _vector$3.applyMatrix3( m );
9230 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9240 applyMatrix4: function ( m ) {
9242 for ( let i = 0, l = this.count; i < l; i ++ ) {
9244 _vector$3.x = this.getX( i );
9245 _vector$3.y = this.getY( i );
9246 _vector$3.z = this.getZ( i );
9248 _vector$3.applyMatrix4( m );
9250 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9258 applyNormalMatrix: function ( m ) {
9260 for ( let i = 0, l = this.count; i < l; i ++ ) {
9262 _vector$3.x = this.getX( i );
9263 _vector$3.y = this.getY( i );
9264 _vector$3.z = this.getZ( i );
9266 _vector$3.applyNormalMatrix( m );
9268 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9276 transformDirection: function ( m ) {
9278 for ( let i = 0, l = this.count; i < l; i ++ ) {
9280 _vector$3.x = this.getX( i );
9281 _vector$3.y = this.getY( i );
9282 _vector$3.z = this.getZ( i );
9284 _vector$3.transformDirection( m );
9286 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9294 set: function ( value, offset = 0 ) {
9296 this.array.set( value, offset );
9302 getX: function ( index ) {
9304 return this.array[ index * this.itemSize ];
9308 setX: function ( index, x ) {
9310 this.array[ index * this.itemSize ] = x;
9316 getY: function ( index ) {
9318 return this.array[ index * this.itemSize + 1 ];
9322 setY: function ( index, y ) {
9324 this.array[ index * this.itemSize + 1 ] = y;
9330 getZ: function ( index ) {
9332 return this.array[ index * this.itemSize + 2 ];
9336 setZ: function ( index, z ) {
9338 this.array[ index * this.itemSize + 2 ] = z;
9344 getW: function ( index ) {
9346 return this.array[ index * this.itemSize + 3 ];
9350 setW: function ( index, w ) {
9352 this.array[ index * this.itemSize + 3 ] = w;
9358 setXY: function ( index, x, y ) {
9360 index *= this.itemSize;
9362 this.array[ index + 0 ] = x;
9363 this.array[ index + 1 ] = y;
9369 setXYZ: function ( index, x, y, z ) {
9371 index *= this.itemSize;
9373 this.array[ index + 0 ] = x;
9374 this.array[ index + 1 ] = y;
9375 this.array[ index + 2 ] = z;
9381 setXYZW: function ( index, x, y, z, w ) {
9383 index *= this.itemSize;
9385 this.array[ index + 0 ] = x;
9386 this.array[ index + 1 ] = y;
9387 this.array[ index + 2 ] = z;
9388 this.array[ index + 3 ] = w;
9394 onUpload: function ( callback ) {
9396 this.onUploadCallback = callback;
9402 clone: function () {
9404 return new this.constructor( this.array, this.itemSize ).copy( this );
9408 toJSON: function () {
9411 itemSize: this.itemSize,
9412 type: this.array.constructor.name,
9413 array: Array.prototype.slice.call( this.array ),
9414 normalized: this.normalized
9423 function Int8BufferAttribute( array, itemSize, normalized ) {
9425 BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
9429 Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9430 Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
9433 function Uint8BufferAttribute( array, itemSize, normalized ) {
9435 BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
9439 Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9440 Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
9443 function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
9445 BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
9449 Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9450 Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
9453 function Int16BufferAttribute( array, itemSize, normalized ) {
9455 BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
9459 Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9460 Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
9463 function Uint16BufferAttribute( array, itemSize, normalized ) {
9465 BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
9469 Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9470 Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
9473 function Int32BufferAttribute( array, itemSize, normalized ) {
9475 BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
9479 Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9480 Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
9483 function Uint32BufferAttribute( array, itemSize, normalized ) {
9485 BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
9489 Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9490 Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
9492 function Float16BufferAttribute( array, itemSize, normalized ) {
9494 BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
9498 Float16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9499 Float16BufferAttribute.prototype.constructor = Float16BufferAttribute;
9500 Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
9502 function Float32BufferAttribute( array, itemSize, normalized ) {
9504 BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
9508 Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9509 Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
9512 function Float64BufferAttribute( array, itemSize, normalized ) {
9514 BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
9518 Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9519 Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
9521 function arrayMax( array ) {
9523 if ( array.length === 0 ) return - Infinity;
9525 let max = array[ 0 ];
9527 for ( let i = 1, l = array.length; i < l; ++ i ) {
9529 if ( array[ i ] > max ) max = array[ i ];
9537 const TYPED_ARRAYS = {
9538 Int8Array: Int8Array,
9539 Uint8Array: Uint8Array,
9540 // Workaround for IE11 pre KB2929437. See #11440
9541 Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
9542 Int16Array: Int16Array,
9543 Uint16Array: Uint16Array,
9544 Int32Array: Int32Array,
9545 Uint32Array: Uint32Array,
9546 Float32Array: Float32Array,
9547 Float64Array: Float64Array
9550 function getTypedArray( type, buffer ) {
9552 return new TYPED_ARRAYS[ type ]( buffer );
9558 const _m1$2 = new Matrix4();
9559 const _obj = new Object3D();
9560 const _offset = new Vector3();
9561 const _box$2 = new Box3();
9562 const _boxMorphTargets = new Box3();
9563 const _vector$4 = new Vector3();
9565 function BufferGeometry() {
9567 Object.defineProperty( this, 'id', { value: _id ++ } );
9569 this.uuid = MathUtils.generateUUID();
9572 this.type = 'BufferGeometry';
9575 this.attributes = {};
9577 this.morphAttributes = {};
9578 this.morphTargetsRelative = false;
9582 this.boundingBox = null;
9583 this.boundingSphere = null;
9585 this.drawRange = { start: 0, count: Infinity };
9591 BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
9593 constructor: BufferGeometry,
9595 isBufferGeometry: true,
9597 getIndex: function () {
9603 setIndex: function ( index ) {
9605 if ( Array.isArray( index ) ) {
9607 this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
9619 getAttribute: function ( name ) {
9621 return this.attributes[ name ];
9625 setAttribute: function ( name, attribute ) {
9627 this.attributes[ name ] = attribute;
9633 deleteAttribute: function ( name ) {
9635 delete this.attributes[ name ];
9641 hasAttribute: function ( name ) {
9643 return this.attributes[ name ] !== undefined;
9647 addGroup: function ( start, count, materialIndex = 0 ) {
9653 materialIndex: materialIndex
9659 clearGroups: function () {
9665 setDrawRange: function ( start, count ) {
9667 this.drawRange.start = start;
9668 this.drawRange.count = count;
9672 applyMatrix4: function ( matrix ) {
9674 const position = this.attributes.position;
9676 if ( position !== undefined ) {
9678 position.applyMatrix4( matrix );
9680 position.needsUpdate = true;
9684 const normal = this.attributes.normal;
9686 if ( normal !== undefined ) {
9688 const normalMatrix = new Matrix3().getNormalMatrix( matrix );
9690 normal.applyNormalMatrix( normalMatrix );
9692 normal.needsUpdate = true;
9696 const tangent = this.attributes.tangent;
9698 if ( tangent !== undefined ) {
9700 tangent.transformDirection( matrix );
9702 tangent.needsUpdate = true;
9706 if ( this.boundingBox !== null ) {
9708 this.computeBoundingBox();
9712 if ( this.boundingSphere !== null ) {
9714 this.computeBoundingSphere();
9722 rotateX: function ( angle ) {
9724 // rotate geometry around world x-axis
9726 _m1$2.makeRotationX( angle );
9728 this.applyMatrix4( _m1$2 );
9734 rotateY: function ( angle ) {
9736 // rotate geometry around world y-axis
9738 _m1$2.makeRotationY( angle );
9740 this.applyMatrix4( _m1$2 );
9746 rotateZ: function ( angle ) {
9748 // rotate geometry around world z-axis
9750 _m1$2.makeRotationZ( angle );
9752 this.applyMatrix4( _m1$2 );
9758 translate: function ( x, y, z ) {
9760 // translate geometry
9762 _m1$2.makeTranslation( x, y, z );
9764 this.applyMatrix4( _m1$2 );
9770 scale: function ( x, y, z ) {
9774 _m1$2.makeScale( x, y, z );
9776 this.applyMatrix4( _m1$2 );
9782 lookAt: function ( vector ) {
9784 _obj.lookAt( vector );
9786 _obj.updateMatrix();
9788 this.applyMatrix4( _obj.matrix );
9794 center: function () {
9796 this.computeBoundingBox();
9798 this.boundingBox.getCenter( _offset ).negate();
9800 this.translate( _offset.x, _offset.y, _offset.z );
9806 setFromPoints: function ( points ) {
9808 const position = [];
9810 for ( let i = 0, l = points.length; i < l; i ++ ) {
9812 const point = points[ i ];
9813 position.push( point.x, point.y, point.z || 0 );
9817 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
9823 computeBoundingBox: function () {
9825 if ( this.boundingBox === null ) {
9827 this.boundingBox = new Box3();
9831 const position = this.attributes.position;
9832 const morphAttributesPosition = this.morphAttributes.position;
9834 if ( position && position.isGLBufferAttribute ) {
9836 console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
9838 this.boundingBox.set(
9839 new Vector3( - Infinity, - Infinity, - Infinity ),
9840 new Vector3( + Infinity, + Infinity, + Infinity )
9847 if ( position !== undefined ) {
9849 this.boundingBox.setFromBufferAttribute( position );
9851 // process morph attributes if present
9853 if ( morphAttributesPosition ) {
9855 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
9857 const morphAttribute = morphAttributesPosition[ i ];
9858 _box$2.setFromBufferAttribute( morphAttribute );
9860 if ( this.morphTargetsRelative ) {
9862 _vector$4.addVectors( this.boundingBox.min, _box$2.min );
9863 this.boundingBox.expandByPoint( _vector$4 );
9865 _vector$4.addVectors( this.boundingBox.max, _box$2.max );
9866 this.boundingBox.expandByPoint( _vector$4 );
9870 this.boundingBox.expandByPoint( _box$2.min );
9871 this.boundingBox.expandByPoint( _box$2.max );
9881 this.boundingBox.makeEmpty();
9885 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
9887 console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
9893 computeBoundingSphere: function () {
9895 if ( this.boundingSphere === null ) {
9897 this.boundingSphere = new Sphere();
9901 const position = this.attributes.position;
9902 const morphAttributesPosition = this.morphAttributes.position;
9904 if ( position && position.isGLBufferAttribute ) {
9906 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
9908 this.boundingSphere.set( new Vector3(), Infinity );
9916 // first, find the center of the bounding sphere
9918 const center = this.boundingSphere.center;
9920 _box$2.setFromBufferAttribute( position );
9922 // process morph attributes if present
9924 if ( morphAttributesPosition ) {
9926 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
9928 const morphAttribute = morphAttributesPosition[ i ];
9929 _boxMorphTargets.setFromBufferAttribute( morphAttribute );
9931 if ( this.morphTargetsRelative ) {
9933 _vector$4.addVectors( _box$2.min, _boxMorphTargets.min );
9934 _box$2.expandByPoint( _vector$4 );
9936 _vector$4.addVectors( _box$2.max, _boxMorphTargets.max );
9937 _box$2.expandByPoint( _vector$4 );
9941 _box$2.expandByPoint( _boxMorphTargets.min );
9942 _box$2.expandByPoint( _boxMorphTargets.max );
9950 _box$2.getCenter( center );
9952 // second, try to find a boundingSphere with a radius smaller than the
9953 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
9955 let maxRadiusSq = 0;
9957 for ( let i = 0, il = position.count; i < il; i ++ ) {
9959 _vector$4.fromBufferAttribute( position, i );
9961 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
9965 // process morph attributes if present
9967 if ( morphAttributesPosition ) {
9969 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
9971 const morphAttribute = morphAttributesPosition[ i ];
9972 const morphTargetsRelative = this.morphTargetsRelative;
9974 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
9976 _vector$4.fromBufferAttribute( morphAttribute, j );
9978 if ( morphTargetsRelative ) {
9980 _offset.fromBufferAttribute( position, j );
9981 _vector$4.add( _offset );
9985 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
9993 this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
9995 if ( isNaN( this.boundingSphere.radius ) ) {
9997 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
10005 computeFaceNormals: function () {
10007 // backwards compatibility
10011 computeTangents: function () {
10013 const index = this.index;
10014 const attributes = this.attributes;
10016 // based on http://www.terathon.com/code/tangent.html
10017 // (per vertex tangents)
10019 if ( index === null ||
10020 attributes.position === undefined ||
10021 attributes.normal === undefined ||
10022 attributes.uv === undefined ) {
10024 console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
10029 const indices = index.array;
10030 const positions = attributes.position.array;
10031 const normals = attributes.normal.array;
10032 const uvs = attributes.uv.array;
10034 const nVertices = positions.length / 3;
10036 if ( attributes.tangent === undefined ) {
10038 this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
10042 const tangents = attributes.tangent.array;
10044 const tan1 = [], tan2 = [];
10046 for ( let i = 0; i < nVertices; i ++ ) {
10048 tan1[ i ] = new Vector3();
10049 tan2[ i ] = new Vector3();
10053 const vA = new Vector3(),
10054 vB = new Vector3(),
10055 vC = new Vector3(),
10057 uvA = new Vector2(),
10058 uvB = new Vector2(),
10059 uvC = new Vector2(),
10061 sdir = new Vector3(),
10062 tdir = new Vector3();
10064 function handleTriangle( a, b, c ) {
10066 vA.fromArray( positions, a * 3 );
10067 vB.fromArray( positions, b * 3 );
10068 vC.fromArray( positions, c * 3 );
10070 uvA.fromArray( uvs, a * 2 );
10071 uvB.fromArray( uvs, b * 2 );
10072 uvC.fromArray( uvs, c * 2 );
10080 const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
10082 // silently ignore degenerate uv triangles having coincident or colinear vertices
10084 if ( ! isFinite( r ) ) return;
10086 sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
10087 tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
10089 tan1[ a ].add( sdir );
10090 tan1[ b ].add( sdir );
10091 tan1[ c ].add( sdir );
10093 tan2[ a ].add( tdir );
10094 tan2[ b ].add( tdir );
10095 tan2[ c ].add( tdir );
10099 let groups = this.groups;
10101 if ( groups.length === 0 ) {
10105 count: indices.length
10110 for ( let i = 0, il = groups.length; i < il; ++ i ) {
10112 const group = groups[ i ];
10114 const start = group.start;
10115 const count = group.count;
10117 for ( let j = start, jl = start + count; j < jl; j += 3 ) {
10129 const tmp = new Vector3(), tmp2 = new Vector3();
10130 const n = new Vector3(), n2 = new Vector3();
10132 function handleVertex( v ) {
10134 n.fromArray( normals, v * 3 );
10137 const t = tan1[ v ];
10139 // Gram-Schmidt orthogonalize
10142 tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
10144 // Calculate handedness
10146 tmp2.crossVectors( n2, t );
10147 const test = tmp2.dot( tan2[ v ] );
10148 const w = ( test < 0.0 ) ? - 1.0 : 1.0;
10150 tangents[ v * 4 ] = tmp.x;
10151 tangents[ v * 4 + 1 ] = tmp.y;
10152 tangents[ v * 4 + 2 ] = tmp.z;
10153 tangents[ v * 4 + 3 ] = w;
10157 for ( let i = 0, il = groups.length; i < il; ++ i ) {
10159 const group = groups[ i ];
10161 const start = group.start;
10162 const count = group.count;
10164 for ( let j = start, jl = start + count; j < jl; j += 3 ) {
10166 handleVertex( indices[ j + 0 ] );
10167 handleVertex( indices[ j + 1 ] );
10168 handleVertex( indices[ j + 2 ] );
10176 computeVertexNormals: function () {
10178 const index = this.index;
10179 const positionAttribute = this.getAttribute( 'position' );
10181 if ( positionAttribute !== undefined ) {
10183 let normalAttribute = this.getAttribute( 'normal' );
10185 if ( normalAttribute === undefined ) {
10187 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
10188 this.setAttribute( 'normal', normalAttribute );
10192 // reset existing normals to zero
10194 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
10196 normalAttribute.setXYZ( i, 0, 0, 0 );
10202 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
10203 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
10204 const cb = new Vector3(), ab = new Vector3();
10206 // indexed elements
10210 for ( let i = 0, il = index.count; i < il; i += 3 ) {
10212 const vA = index.getX( i + 0 );
10213 const vB = index.getX( i + 1 );
10214 const vC = index.getX( i + 2 );
10216 pA.fromBufferAttribute( positionAttribute, vA );
10217 pB.fromBufferAttribute( positionAttribute, vB );
10218 pC.fromBufferAttribute( positionAttribute, vC );
10220 cb.subVectors( pC, pB );
10221 ab.subVectors( pA, pB );
10224 nA.fromBufferAttribute( normalAttribute, vA );
10225 nB.fromBufferAttribute( normalAttribute, vB );
10226 nC.fromBufferAttribute( normalAttribute, vC );
10232 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
10233 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
10234 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
10240 // non-indexed elements (unconnected triangle soup)
10242 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
10244 pA.fromBufferAttribute( positionAttribute, i + 0 );
10245 pB.fromBufferAttribute( positionAttribute, i + 1 );
10246 pC.fromBufferAttribute( positionAttribute, i + 2 );
10248 cb.subVectors( pC, pB );
10249 ab.subVectors( pA, pB );
10252 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
10253 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
10254 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
10260 this.normalizeNormals();
10262 normalAttribute.needsUpdate = true;
10268 merge: function ( geometry, offset ) {
10270 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
10272 console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
10277 if ( offset === undefined ) {
10282 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
10283 + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
10288 const attributes = this.attributes;
10290 for ( const key in attributes ) {
10292 if ( geometry.attributes[ key ] === undefined ) continue;
10294 const attribute1 = attributes[ key ];
10295 const attributeArray1 = attribute1.array;
10297 const attribute2 = geometry.attributes[ key ];
10298 const attributeArray2 = attribute2.array;
10300 const attributeOffset = attribute2.itemSize * offset;
10301 const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
10303 for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
10305 attributeArray1[ j ] = attributeArray2[ i ];
10315 normalizeNormals: function () {
10317 const normals = this.attributes.normal;
10319 for ( let i = 0, il = normals.count; i < il; i ++ ) {
10321 _vector$4.fromBufferAttribute( normals, i );
10323 _vector$4.normalize();
10325 normals.setXYZ( i, _vector$4.x, _vector$4.y, _vector$4.z );
10331 toNonIndexed: function () {
10333 function convertBufferAttribute( attribute, indices ) {
10335 const array = attribute.array;
10336 const itemSize = attribute.itemSize;
10337 const normalized = attribute.normalized;
10339 const array2 = new array.constructor( indices.length * itemSize );
10341 let index = 0, index2 = 0;
10343 for ( let i = 0, l = indices.length; i < l; i ++ ) {
10345 index = indices[ i ] * itemSize;
10347 for ( let j = 0; j < itemSize; j ++ ) {
10349 array2[ index2 ++ ] = array[ index ++ ];
10355 return new BufferAttribute( array2, itemSize, normalized );
10361 if ( this.index === null ) {
10363 console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
10368 const geometry2 = new BufferGeometry();
10370 const indices = this.index.array;
10371 const attributes = this.attributes;
10375 for ( const name in attributes ) {
10377 const attribute = attributes[ name ];
10379 const newAttribute = convertBufferAttribute( attribute, indices );
10381 geometry2.setAttribute( name, newAttribute );
10385 // morph attributes
10387 const morphAttributes = this.morphAttributes;
10389 for ( const name in morphAttributes ) {
10391 const morphArray = [];
10392 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
10394 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
10396 const attribute = morphAttribute[ i ];
10398 const newAttribute = convertBufferAttribute( attribute, indices );
10400 morphArray.push( newAttribute );
10404 geometry2.morphAttributes[ name ] = morphArray;
10408 geometry2.morphTargetsRelative = this.morphTargetsRelative;
10412 const groups = this.groups;
10414 for ( let i = 0, l = groups.length; i < l; i ++ ) {
10416 const group = groups[ i ];
10417 geometry2.addGroup( group.start, group.count, group.materialIndex );
10425 toJSON: function () {
10430 type: 'BufferGeometry',
10431 generator: 'BufferGeometry.toJSON'
10435 // standard BufferGeometry serialization
10437 data.uuid = this.uuid;
10438 data.type = this.type;
10439 if ( this.name !== '' ) data.name = this.name;
10440 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
10442 if ( this.parameters !== undefined ) {
10444 const parameters = this.parameters;
10446 for ( const key in parameters ) {
10448 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
10456 data.data = { attributes: {} };
10458 const index = this.index;
10460 if ( index !== null ) {
10462 data.data.index = {
10463 type: index.array.constructor.name,
10464 array: Array.prototype.slice.call( index.array )
10469 const attributes = this.attributes;
10471 for ( const key in attributes ) {
10473 const attribute = attributes[ key ];
10475 const attributeData = attribute.toJSON( data.data );
10477 if ( attribute.name !== '' ) attributeData.name = attribute.name;
10479 data.data.attributes[ key ] = attributeData;
10483 const morphAttributes = {};
10484 let hasMorphAttributes = false;
10486 for ( const key in this.morphAttributes ) {
10488 const attributeArray = this.morphAttributes[ key ];
10492 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
10494 const attribute = attributeArray[ i ];
10496 const attributeData = attribute.toJSON( data.data );
10498 if ( attribute.name !== '' ) attributeData.name = attribute.name;
10500 array.push( attributeData );
10504 if ( array.length > 0 ) {
10506 morphAttributes[ key ] = array;
10508 hasMorphAttributes = true;
10514 if ( hasMorphAttributes ) {
10516 data.data.morphAttributes = morphAttributes;
10517 data.data.morphTargetsRelative = this.morphTargetsRelative;
10521 const groups = this.groups;
10523 if ( groups.length > 0 ) {
10525 data.data.groups = JSON.parse( JSON.stringify( groups ) );
10529 const boundingSphere = this.boundingSphere;
10531 if ( boundingSphere !== null ) {
10533 data.data.boundingSphere = {
10534 center: boundingSphere.center.toArray(),
10535 radius: boundingSphere.radius
10544 clone: function () {
10547 // Handle primitives
10549 const parameters = this.parameters;
10551 if ( parameters !== undefined ) {
10555 for ( const key in parameters ) {
10557 values.push( parameters[ key ] );
10561 const geometry = Object.create( this.constructor.prototype );
10562 this.constructor.apply( geometry, values );
10567 return new this.constructor().copy( this );
10570 return new BufferGeometry().copy( this );
10574 copy: function ( source ) {
10579 this.attributes = {};
10580 this.morphAttributes = {};
10582 this.boundingBox = null;
10583 this.boundingSphere = null;
10585 // used for storing cloned, shared data
10591 this.name = source.name;
10595 const index = source.index;
10597 if ( index !== null ) {
10599 this.setIndex( index.clone( data ) );
10605 const attributes = source.attributes;
10607 for ( const name in attributes ) {
10609 const attribute = attributes[ name ];
10610 this.setAttribute( name, attribute.clone( data ) );
10614 // morph attributes
10616 const morphAttributes = source.morphAttributes;
10618 for ( const name in morphAttributes ) {
10621 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
10623 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
10625 array.push( morphAttribute[ i ].clone( data ) );
10629 this.morphAttributes[ name ] = array;
10633 this.morphTargetsRelative = source.morphTargetsRelative;
10637 const groups = source.groups;
10639 for ( let i = 0, l = groups.length; i < l; i ++ ) {
10641 const group = groups[ i ];
10642 this.addGroup( group.start, group.count, group.materialIndex );
10648 const boundingBox = source.boundingBox;
10650 if ( boundingBox !== null ) {
10652 this.boundingBox = boundingBox.clone();
10658 const boundingSphere = source.boundingSphere;
10660 if ( boundingSphere !== null ) {
10662 this.boundingSphere = boundingSphere.clone();
10668 this.drawRange.start = source.drawRange.start;
10669 this.drawRange.count = source.drawRange.count;
10673 this.userData = source.userData;
10679 dispose: function () {
10681 this.dispatchEvent( { type: 'dispose' } );
10687 const _inverseMatrix = new Matrix4();
10688 const _ray = new Ray();
10689 const _sphere = new Sphere();
10691 const _vA = new Vector3();
10692 const _vB = new Vector3();
10693 const _vC = new Vector3();
10695 const _tempA = new Vector3();
10696 const _tempB = new Vector3();
10697 const _tempC = new Vector3();
10699 const _morphA = new Vector3();
10700 const _morphB = new Vector3();
10701 const _morphC = new Vector3();
10703 const _uvA = new Vector2();
10704 const _uvB = new Vector2();
10705 const _uvC = new Vector2();
10707 const _intersectionPoint = new Vector3();
10708 const _intersectionPointWorld = new Vector3();
10710 function Mesh( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
10712 Object3D.call( this );
10714 this.type = 'Mesh';
10716 this.geometry = geometry;
10717 this.material = material;
10719 this.updateMorphTargets();
10723 Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
10729 copy: function ( source ) {
10731 Object3D.prototype.copy.call( this, source );
10733 if ( source.morphTargetInfluences !== undefined ) {
10735 this.morphTargetInfluences = source.morphTargetInfluences.slice();
10739 if ( source.morphTargetDictionary !== undefined ) {
10741 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
10745 this.material = source.material;
10746 this.geometry = source.geometry;
10752 updateMorphTargets: function () {
10754 const geometry = this.geometry;
10756 if ( geometry.isBufferGeometry ) {
10758 const morphAttributes = geometry.morphAttributes;
10759 const keys = Object.keys( morphAttributes );
10761 if ( keys.length > 0 ) {
10763 const morphAttribute = morphAttributes[ keys[ 0 ] ];
10765 if ( morphAttribute !== undefined ) {
10767 this.morphTargetInfluences = [];
10768 this.morphTargetDictionary = {};
10770 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
10772 const name = morphAttribute[ m ].name || String( m );
10774 this.morphTargetInfluences.push( 0 );
10775 this.morphTargetDictionary[ name ] = m;
10785 const morphTargets = geometry.morphTargets;
10787 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
10789 console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
10797 raycast: function ( raycaster, intersects ) {
10799 const geometry = this.geometry;
10800 const material = this.material;
10801 const matrixWorld = this.matrixWorld;
10803 if ( material === undefined ) return;
10805 // Checking boundingSphere distance to ray
10807 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
10809 _sphere.copy( geometry.boundingSphere );
10810 _sphere.applyMatrix4( matrixWorld );
10812 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
10816 _inverseMatrix.copy( matrixWorld ).invert();
10817 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
10819 // Check boundingBox before continuing
10821 if ( geometry.boundingBox !== null ) {
10823 if ( _ray.intersectsBox( geometry.boundingBox ) === false ) return;
10829 if ( geometry.isBufferGeometry ) {
10831 const index = geometry.index;
10832 const position = geometry.attributes.position;
10833 const morphPosition = geometry.morphAttributes.position;
10834 const morphTargetsRelative = geometry.morphTargetsRelative;
10835 const uv = geometry.attributes.uv;
10836 const uv2 = geometry.attributes.uv2;
10837 const groups = geometry.groups;
10838 const drawRange = geometry.drawRange;
10840 if ( index !== null ) {
10842 // indexed buffer geometry
10844 if ( Array.isArray( material ) ) {
10846 for ( let i = 0, il = groups.length; i < il; i ++ ) {
10848 const group = groups[ i ];
10849 const groupMaterial = material[ group.materialIndex ];
10851 const start = Math.max( group.start, drawRange.start );
10852 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
10854 for ( let j = start, jl = end; j < jl; j += 3 ) {
10856 const a = index.getX( j );
10857 const b = index.getX( j + 1 );
10858 const c = index.getX( j + 2 );
10860 intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
10862 if ( intersection ) {
10864 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
10865 intersection.face.materialIndex = group.materialIndex;
10866 intersects.push( intersection );
10876 const start = Math.max( 0, drawRange.start );
10877 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
10879 for ( let i = start, il = end; i < il; i += 3 ) {
10881 const a = index.getX( i );
10882 const b = index.getX( i + 1 );
10883 const c = index.getX( i + 2 );
10885 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
10887 if ( intersection ) {
10889 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
10890 intersects.push( intersection );
10898 } else if ( position !== undefined ) {
10900 // non-indexed buffer geometry
10902 if ( Array.isArray( material ) ) {
10904 for ( let i = 0, il = groups.length; i < il; i ++ ) {
10906 const group = groups[ i ];
10907 const groupMaterial = material[ group.materialIndex ];
10909 const start = Math.max( group.start, drawRange.start );
10910 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
10912 for ( let j = start, jl = end; j < jl; j += 3 ) {
10918 intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
10920 if ( intersection ) {
10922 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
10923 intersection.face.materialIndex = group.materialIndex;
10924 intersects.push( intersection );
10934 const start = Math.max( 0, drawRange.start );
10935 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
10937 for ( let i = start, il = end; i < il; i += 3 ) {
10943 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
10945 if ( intersection ) {
10947 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
10948 intersects.push( intersection );
10958 } else if ( geometry.isGeometry ) {
10960 console.error( 'THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
10968 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
10972 if ( material.side === BackSide ) {
10974 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
10978 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
10982 if ( intersect === null ) return null;
10984 _intersectionPointWorld.copy( point );
10985 _intersectionPointWorld.applyMatrix4( object.matrixWorld );
10987 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
10989 if ( distance < raycaster.near || distance > raycaster.far ) return null;
10992 distance: distance,
10993 point: _intersectionPointWorld.clone(),
10999 function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
11001 _vA.fromBufferAttribute( position, a );
11002 _vB.fromBufferAttribute( position, b );
11003 _vC.fromBufferAttribute( position, c );
11005 const morphInfluences = object.morphTargetInfluences;
11007 if ( material.morphTargets && morphPosition && morphInfluences ) {
11009 _morphA.set( 0, 0, 0 );
11010 _morphB.set( 0, 0, 0 );
11011 _morphC.set( 0, 0, 0 );
11013 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
11015 const influence = morphInfluences[ i ];
11016 const morphAttribute = morphPosition[ i ];
11018 if ( influence === 0 ) continue;
11020 _tempA.fromBufferAttribute( morphAttribute, a );
11021 _tempB.fromBufferAttribute( morphAttribute, b );
11022 _tempC.fromBufferAttribute( morphAttribute, c );
11024 if ( morphTargetsRelative ) {
11026 _morphA.addScaledVector( _tempA, influence );
11027 _morphB.addScaledVector( _tempB, influence );
11028 _morphC.addScaledVector( _tempC, influence );
11032 _morphA.addScaledVector( _tempA.sub( _vA ), influence );
11033 _morphB.addScaledVector( _tempB.sub( _vB ), influence );
11034 _morphC.addScaledVector( _tempC.sub( _vC ), influence );
11040 _vA.add( _morphA );
11041 _vB.add( _morphB );
11042 _vC.add( _morphC );
11046 if ( object.isSkinnedMesh ) {
11048 object.boneTransform( a, _vA );
11049 object.boneTransform( b, _vB );
11050 object.boneTransform( c, _vC );
11054 const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
11056 if ( intersection ) {
11060 _uvA.fromBufferAttribute( uv, a );
11061 _uvB.fromBufferAttribute( uv, b );
11062 _uvC.fromBufferAttribute( uv, c );
11064 intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
11070 _uvA.fromBufferAttribute( uv2, a );
11071 _uvB.fromBufferAttribute( uv2, b );
11072 _uvC.fromBufferAttribute( uv2, c );
11074 intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
11078 const face = new Face3( a, b, c );
11079 Triangle.getNormal( _vA, _vB, _vC, face.normal );
11081 intersection.face = face;
11085 return intersection;
11089 class BoxGeometry extends BufferGeometry {
11091 constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
11095 this.type = 'BoxGeometry';
11097 this.parameters = {
11101 widthSegments: widthSegments,
11102 heightSegments: heightSegments,
11103 depthSegments: depthSegments
11106 const scope = this;
11110 widthSegments = Math.floor( widthSegments );
11111 heightSegments = Math.floor( heightSegments );
11112 depthSegments = Math.floor( depthSegments );
11116 const indices = [];
11117 const vertices = [];
11118 const normals = [];
11121 // helper variables
11123 let numberOfVertices = 0;
11124 let groupStart = 0;
11126 // build each side of the box geometry
11128 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
11129 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
11130 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
11131 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
11132 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
11133 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
11137 this.setIndex( indices );
11138 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
11139 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
11140 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
11142 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
11144 const segmentWidth = width / gridX;
11145 const segmentHeight = height / gridY;
11147 const widthHalf = width / 2;
11148 const heightHalf = height / 2;
11149 const depthHalf = depth / 2;
11151 const gridX1 = gridX + 1;
11152 const gridY1 = gridY + 1;
11154 let vertexCounter = 0;
11155 let groupCount = 0;
11157 const vector = new Vector3();
11159 // generate vertices, normals and uvs
11161 for ( let iy = 0; iy < gridY1; iy ++ ) {
11163 const y = iy * segmentHeight - heightHalf;
11165 for ( let ix = 0; ix < gridX1; ix ++ ) {
11167 const x = ix * segmentWidth - widthHalf;
11169 // set values to correct vector component
11171 vector[ u ] = x * udir;
11172 vector[ v ] = y * vdir;
11173 vector[ w ] = depthHalf;
11175 // now apply vector to vertex buffer
11177 vertices.push( vector.x, vector.y, vector.z );
11179 // set values to correct vector component
11183 vector[ w ] = depth > 0 ? 1 : - 1;
11185 // now apply vector to normal buffer
11187 normals.push( vector.x, vector.y, vector.z );
11191 uvs.push( ix / gridX );
11192 uvs.push( 1 - ( iy / gridY ) );
11196 vertexCounter += 1;
11204 // 1. you need three indices to draw a single face
11205 // 2. a single segment consists of two faces
11206 // 3. so we need to generate six (2*3) indices per segment
11208 for ( let iy = 0; iy < gridY; iy ++ ) {
11210 for ( let ix = 0; ix < gridX; ix ++ ) {
11212 const a = numberOfVertices + ix + gridX1 * iy;
11213 const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
11214 const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
11215 const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
11219 indices.push( a, b, d );
11220 indices.push( b, c, d );
11222 // increase counter
11230 // add a group to the geometry. this will ensure multi material support
11232 scope.addGroup( groupStart, groupCount, materialIndex );
11234 // calculate new start value for groups
11236 groupStart += groupCount;
11238 // update total number of vertices
11240 numberOfVertices += vertexCounter;
11249 * Uniform Utilities
11252 function cloneUniforms( src ) {
11256 for ( const u in src ) {
11260 for ( const p in src[ u ] ) {
11262 const property = src[ u ][ p ];
11264 if ( property && ( property.isColor ||
11265 property.isMatrix3 || property.isMatrix4 ||
11266 property.isVector2 || property.isVector3 || property.isVector4 ||
11267 property.isTexture ) ) {
11269 dst[ u ][ p ] = property.clone();
11271 } else if ( Array.isArray( property ) ) {
11273 dst[ u ][ p ] = property.slice();
11277 dst[ u ][ p ] = property;
11289 function mergeUniforms( uniforms ) {
11293 for ( let u = 0; u < uniforms.length; u ++ ) {
11295 const tmp = cloneUniforms( uniforms[ u ] );
11297 for ( const p in tmp ) {
11299 merged[ p ] = tmp[ p ];
11311 const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
11313 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
11315 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
11319 * defines: { "label" : "value" },
11320 * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
11322 * fragmentShader: <string>,
11323 * vertexShader: <string>,
11325 * wireframe: <boolean>,
11326 * wireframeLinewidth: <float>,
11330 * skinning: <bool>,
11331 * morphTargets: <bool>,
11332 * morphNormals: <bool>
11336 function ShaderMaterial( parameters ) {
11338 Material.call( this );
11340 this.type = 'ShaderMaterial';
11343 this.uniforms = {};
11345 this.vertexShader = default_vertex;
11346 this.fragmentShader = default_fragment;
11348 this.linewidth = 1;
11350 this.wireframe = false;
11351 this.wireframeLinewidth = 1;
11353 this.fog = false; // set to use scene fog
11354 this.lights = false; // set to use scene lights
11355 this.clipping = false; // set to use user-defined clipping planes
11357 this.skinning = false; // set to use skinning attribute streams
11358 this.morphTargets = false; // set to use morph targets
11359 this.morphNormals = false; // set to use morph normals
11361 this.extensions = {
11362 derivatives: false, // set to use derivatives
11363 fragDepth: false, // set to use fragment depth values
11364 drawBuffers: false, // set to use draw buffers
11365 shaderTextureLOD: false // set to use shader texture LOD
11368 // When rendered geometry doesn't include these attributes but the material does,
11369 // use these default values in WebGL. This avoids errors when buffer data is missing.
11370 this.defaultAttributeValues = {
11371 'color': [ 1, 1, 1 ],
11376 this.index0AttributeName = undefined;
11377 this.uniformsNeedUpdate = false;
11379 this.glslVersion = null;
11381 if ( parameters !== undefined ) {
11383 if ( parameters.attributes !== undefined ) {
11385 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
11389 this.setValues( parameters );
11395 ShaderMaterial.prototype = Object.create( Material.prototype );
11396 ShaderMaterial.prototype.constructor = ShaderMaterial;
11398 ShaderMaterial.prototype.isShaderMaterial = true;
11400 ShaderMaterial.prototype.copy = function ( source ) {
11402 Material.prototype.copy.call( this, source );
11404 this.fragmentShader = source.fragmentShader;
11405 this.vertexShader = source.vertexShader;
11407 this.uniforms = cloneUniforms( source.uniforms );
11409 this.defines = Object.assign( {}, source.defines );
11411 this.wireframe = source.wireframe;
11412 this.wireframeLinewidth = source.wireframeLinewidth;
11414 this.lights = source.lights;
11415 this.clipping = source.clipping;
11417 this.skinning = source.skinning;
11419 this.morphTargets = source.morphTargets;
11420 this.morphNormals = source.morphNormals;
11422 this.extensions = Object.assign( {}, source.extensions );
11424 this.glslVersion = source.glslVersion;
11430 ShaderMaterial.prototype.toJSON = function ( meta ) {
11432 const data = Material.prototype.toJSON.call( this, meta );
11434 data.glslVersion = this.glslVersion;
11435 data.uniforms = {};
11437 for ( const name in this.uniforms ) {
11439 const uniform = this.uniforms[ name ];
11440 const value = uniform.value;
11442 if ( value && value.isTexture ) {
11444 data.uniforms[ name ] = {
11446 value: value.toJSON( meta ).uuid
11449 } else if ( value && value.isColor ) {
11451 data.uniforms[ name ] = {
11453 value: value.getHex()
11456 } else if ( value && value.isVector2 ) {
11458 data.uniforms[ name ] = {
11460 value: value.toArray()
11463 } else if ( value && value.isVector3 ) {
11465 data.uniforms[ name ] = {
11467 value: value.toArray()
11470 } else if ( value && value.isVector4 ) {
11472 data.uniforms[ name ] = {
11474 value: value.toArray()
11477 } else if ( value && value.isMatrix3 ) {
11479 data.uniforms[ name ] = {
11481 value: value.toArray()
11484 } else if ( value && value.isMatrix4 ) {
11486 data.uniforms[ name ] = {
11488 value: value.toArray()
11493 data.uniforms[ name ] = {
11497 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
11503 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
11505 data.vertexShader = this.vertexShader;
11506 data.fragmentShader = this.fragmentShader;
11508 const extensions = {};
11510 for ( const key in this.extensions ) {
11512 if ( this.extensions[ key ] === true ) extensions[ key ] = true;
11516 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
11522 function Camera() {
11524 Object3D.call( this );
11526 this.type = 'Camera';
11528 this.matrixWorldInverse = new Matrix4();
11530 this.projectionMatrix = new Matrix4();
11531 this.projectionMatrixInverse = new Matrix4();
11535 Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
11537 constructor: Camera,
11541 copy: function ( source, recursive ) {
11543 Object3D.prototype.copy.call( this, source, recursive );
11545 this.matrixWorldInverse.copy( source.matrixWorldInverse );
11547 this.projectionMatrix.copy( source.projectionMatrix );
11548 this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
11554 getWorldDirection: function ( target ) {
11556 if ( target === undefined ) {
11558 console.warn( 'THREE.Camera: .getWorldDirection() target is now required' );
11559 target = new Vector3();
11563 this.updateWorldMatrix( true, false );
11565 const e = this.matrixWorld.elements;
11567 return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize();
11571 updateMatrixWorld: function ( force ) {
11573 Object3D.prototype.updateMatrixWorld.call( this, force );
11575 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
11579 updateWorldMatrix: function ( updateParents, updateChildren ) {
11581 Object3D.prototype.updateWorldMatrix.call( this, updateParents, updateChildren );
11583 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
11587 clone: function () {
11589 return new this.constructor().copy( this );
11595 function PerspectiveCamera( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
11597 Camera.call( this );
11599 this.type = 'PerspectiveCamera';
11608 this.aspect = aspect;
11611 this.filmGauge = 35; // width of the film (default in millimeters)
11612 this.filmOffset = 0; // horizontal film offset (same unit as gauge)
11614 this.updateProjectionMatrix();
11618 PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
11620 constructor: PerspectiveCamera,
11622 isPerspectiveCamera: true,
11624 copy: function ( source, recursive ) {
11626 Camera.prototype.copy.call( this, source, recursive );
11628 this.fov = source.fov;
11629 this.zoom = source.zoom;
11631 this.near = source.near;
11632 this.far = source.far;
11633 this.focus = source.focus;
11635 this.aspect = source.aspect;
11636 this.view = source.view === null ? null : Object.assign( {}, source.view );
11638 this.filmGauge = source.filmGauge;
11639 this.filmOffset = source.filmOffset;
11646 * Sets the FOV by focal length in respect to the current .filmGauge.
11648 * The default film gauge is 35, so that the focal length can be specified for
11649 * a 35mm (full frame) camera.
11651 * Values for focal length and film gauge must have the same unit.
11653 setFocalLength: function ( focalLength ) {
11655 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
11656 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
11658 this.fov = MathUtils.RAD2DEG * 2 * Math.atan( vExtentSlope );
11659 this.updateProjectionMatrix();
11664 * Calculates the focal length from the current .fov and .filmGauge.
11666 getFocalLength: function () {
11668 const vExtentSlope = Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov );
11670 return 0.5 * this.getFilmHeight() / vExtentSlope;
11674 getEffectiveFOV: function () {
11676 return MathUtils.RAD2DEG * 2 * Math.atan(
11677 Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom );
11681 getFilmWidth: function () {
11683 // film not completely covered in portrait format (aspect < 1)
11684 return this.filmGauge * Math.min( this.aspect, 1 );
11688 getFilmHeight: function () {
11690 // film not completely covered in landscape format (aspect > 1)
11691 return this.filmGauge / Math.max( this.aspect, 1 );
11696 * Sets an offset in a larger frustum. This is useful for multi-window or
11697 * multi-monitor/multi-machine setups.
11699 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
11700 * the monitors are in grid like this
11708 * then for each monitor you would call it like this
11712 * const fullWidth = w * 3;
11713 * const fullHeight = h * 2;
11716 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
11718 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
11720 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
11722 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
11724 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
11726 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
11728 * Note there is no reason monitors have to be the same size or in a grid.
11730 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
11732 this.aspect = fullWidth / fullHeight;
11734 if ( this.view === null ) {
11748 this.view.enabled = true;
11749 this.view.fullWidth = fullWidth;
11750 this.view.fullHeight = fullHeight;
11751 this.view.offsetX = x;
11752 this.view.offsetY = y;
11753 this.view.width = width;
11754 this.view.height = height;
11756 this.updateProjectionMatrix();
11760 clearViewOffset: function () {
11762 if ( this.view !== null ) {
11764 this.view.enabled = false;
11768 this.updateProjectionMatrix();
11772 updateProjectionMatrix: function () {
11774 const near = this.near;
11775 let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
11776 let height = 2 * top;
11777 let width = this.aspect * height;
11778 let left = - 0.5 * width;
11779 const view = this.view;
11781 if ( this.view !== null && this.view.enabled ) {
11783 const fullWidth = view.fullWidth,
11784 fullHeight = view.fullHeight;
11786 left += view.offsetX * width / fullWidth;
11787 top -= view.offsetY * height / fullHeight;
11788 width *= view.width / fullWidth;
11789 height *= view.height / fullHeight;
11793 const skew = this.filmOffset;
11794 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
11796 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
11798 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
11802 toJSON: function ( meta ) {
11804 const data = Object3D.prototype.toJSON.call( this, meta );
11806 data.object.fov = this.fov;
11807 data.object.zoom = this.zoom;
11809 data.object.near = this.near;
11810 data.object.far = this.far;
11811 data.object.focus = this.focus;
11813 data.object.aspect = this.aspect;
11815 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
11817 data.object.filmGauge = this.filmGauge;
11818 data.object.filmOffset = this.filmOffset;
11826 const fov = 90, aspect = 1;
11828 function CubeCamera( near, far, renderTarget ) {
11830 Object3D.call( this );
11832 this.type = 'CubeCamera';
11834 if ( renderTarget.isWebGLCubeRenderTarget !== true ) {
11836 console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' );
11841 this.renderTarget = renderTarget;
11843 const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
11844 cameraPX.layers = this.layers;
11845 cameraPX.up.set( 0, - 1, 0 );
11846 cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
11847 this.add( cameraPX );
11849 const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
11850 cameraNX.layers = this.layers;
11851 cameraNX.up.set( 0, - 1, 0 );
11852 cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
11853 this.add( cameraNX );
11855 const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
11856 cameraPY.layers = this.layers;
11857 cameraPY.up.set( 0, 0, 1 );
11858 cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
11859 this.add( cameraPY );
11861 const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
11862 cameraNY.layers = this.layers;
11863 cameraNY.up.set( 0, 0, - 1 );
11864 cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
11865 this.add( cameraNY );
11867 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
11868 cameraPZ.layers = this.layers;
11869 cameraPZ.up.set( 0, - 1, 0 );
11870 cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
11871 this.add( cameraPZ );
11873 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
11874 cameraNZ.layers = this.layers;
11875 cameraNZ.up.set( 0, - 1, 0 );
11876 cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
11877 this.add( cameraNZ );
11879 this.update = function ( renderer, scene ) {
11881 if ( this.parent === null ) this.updateMatrixWorld();
11883 const currentXrEnabled = renderer.xr.enabled;
11884 const currentRenderTarget = renderer.getRenderTarget();
11886 renderer.xr.enabled = false;
11888 const generateMipmaps = renderTarget.texture.generateMipmaps;
11890 renderTarget.texture.generateMipmaps = false;
11892 renderer.setRenderTarget( renderTarget, 0 );
11893 renderer.render( scene, cameraPX );
11895 renderer.setRenderTarget( renderTarget, 1 );
11896 renderer.render( scene, cameraNX );
11898 renderer.setRenderTarget( renderTarget, 2 );
11899 renderer.render( scene, cameraPY );
11901 renderer.setRenderTarget( renderTarget, 3 );
11902 renderer.render( scene, cameraNY );
11904 renderer.setRenderTarget( renderTarget, 4 );
11905 renderer.render( scene, cameraPZ );
11907 renderTarget.texture.generateMipmaps = generateMipmaps;
11909 renderer.setRenderTarget( renderTarget, 5 );
11910 renderer.render( scene, cameraNZ );
11912 renderer.setRenderTarget( currentRenderTarget );
11914 renderer.xr.enabled = currentXrEnabled;
11920 CubeCamera.prototype = Object.create( Object3D.prototype );
11921 CubeCamera.prototype.constructor = CubeCamera;
11923 function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
11925 images = images !== undefined ? images : [];
11926 mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
11927 format = format !== undefined ? format : RGBFormat;
11929 Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
11931 this.flipY = false;
11933 // Why CubeTexture._needsFlipEnvMap is necessary:
11935 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
11936 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
11937 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
11939 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
11940 // and the flag _needsFlipEnvMap controls this conversion. The flip is not required (and thus _needsFlipEnvMap is set to false)
11941 // when using WebGLCubeRenderTarget.texture as a cube texture.
11943 this._needsFlipEnvMap = true;
11947 CubeTexture.prototype = Object.create( Texture.prototype );
11948 CubeTexture.prototype.constructor = CubeTexture;
11950 CubeTexture.prototype.isCubeTexture = true;
11952 Object.defineProperty( CubeTexture.prototype, 'images', {
11960 set: function ( value ) {
11962 this.image = value;
11968 class WebGLCubeRenderTarget extends WebGLRenderTarget {
11970 constructor( size, options, dummy ) {
11972 if ( Number.isInteger( options ) ) {
11974 console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' );
11980 super( size, size, options );
11982 Object.defineProperty( this, 'isWebGLCubeRenderTarget', { value: true } );
11984 options = options || {};
11986 this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
11988 this.texture._needsFlipEnvMap = false;
11992 fromEquirectangularTexture( renderer, texture ) {
11994 this.texture.type = texture.type;
11995 this.texture.format = RGBAFormat; // see #18859
11996 this.texture.encoding = texture.encoding;
11998 this.texture.generateMipmaps = texture.generateMipmaps;
11999 this.texture.minFilter = texture.minFilter;
12000 this.texture.magFilter = texture.magFilter;
12005 tEquirect: { value: null },
12008 vertexShader: /* glsl */`
12010 varying vec3 vWorldDirection;
12012 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
12014 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
12020 vWorldDirection = transformDirection( position, modelMatrix );
12022 #include <begin_vertex>
12023 #include <project_vertex>
12028 fragmentShader: /* glsl */`
12030 uniform sampler2D tEquirect;
12032 varying vec3 vWorldDirection;
12038 vec3 direction = normalize( vWorldDirection );
12040 vec2 sampleUV = equirectUv( direction );
12042 gl_FragColor = texture2D( tEquirect, sampleUV );
12048 const geometry = new BoxGeometry( 5, 5, 5 );
12050 const material = new ShaderMaterial( {
12052 name: 'CubemapFromEquirect',
12054 uniforms: cloneUniforms( shader.uniforms ),
12055 vertexShader: shader.vertexShader,
12056 fragmentShader: shader.fragmentShader,
12058 blending: NoBlending
12062 material.uniforms.tEquirect.value = texture;
12064 const mesh = new Mesh( geometry, material );
12066 const currentMinFilter = texture.minFilter;
12068 // Avoid blurred poles
12069 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
12071 const camera = new CubeCamera( 1, 10, this );
12072 camera.update( renderer, mesh );
12074 texture.minFilter = currentMinFilter;
12076 mesh.geometry.dispose();
12077 mesh.material.dispose();
12083 clear( renderer, color, depth, stencil ) {
12085 const currentRenderTarget = renderer.getRenderTarget();
12087 for ( let i = 0; i < 6; i ++ ) {
12089 renderer.setRenderTarget( this, i );
12091 renderer.clear( color, depth, stencil );
12095 renderer.setRenderTarget( currentRenderTarget );
12101 function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
12103 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
12105 this.image = { data: data || null, width: width || 1, height: height || 1 };
12107 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
12108 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
12110 this.generateMipmaps = false;
12111 this.flipY = false;
12112 this.unpackAlignment = 1;
12114 this.needsUpdate = true;
12118 DataTexture.prototype = Object.create( Texture.prototype );
12119 DataTexture.prototype.constructor = DataTexture;
12121 DataTexture.prototype.isDataTexture = true;
12123 const _sphere$1 = /*@__PURE__*/ new Sphere();
12124 const _vector$5 = /*@__PURE__*/ new Vector3();
12128 constructor( p0, p1, p2, p3, p4, p5 ) {
12132 ( p0 !== undefined ) ? p0 : new Plane(),
12133 ( p1 !== undefined ) ? p1 : new Plane(),
12134 ( p2 !== undefined ) ? p2 : new Plane(),
12135 ( p3 !== undefined ) ? p3 : new Plane(),
12136 ( p4 !== undefined ) ? p4 : new Plane(),
12137 ( p5 !== undefined ) ? p5 : new Plane()
12143 set( p0, p1, p2, p3, p4, p5 ) {
12145 const planes = this.planes;
12147 planes[ 0 ].copy( p0 );
12148 planes[ 1 ].copy( p1 );
12149 planes[ 2 ].copy( p2 );
12150 planes[ 3 ].copy( p3 );
12151 planes[ 4 ].copy( p4 );
12152 planes[ 5 ].copy( p5 );
12160 return new this.constructor().copy( this );
12166 const planes = this.planes;
12168 for ( let i = 0; i < 6; i ++ ) {
12170 planes[ i ].copy( frustum.planes[ i ] );
12178 setFromProjectionMatrix( m ) {
12180 const planes = this.planes;
12181 const me = m.elements;
12182 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
12183 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
12184 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
12185 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
12187 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
12188 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
12189 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
12190 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
12191 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
12192 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
12198 intersectsObject( object ) {
12200 const geometry = object.geometry;
12202 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
12204 _sphere$1.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
12206 return this.intersectsSphere( _sphere$1 );
12210 intersectsSprite( sprite ) {
12212 _sphere$1.center.set( 0, 0, 0 );
12213 _sphere$1.radius = 0.7071067811865476;
12214 _sphere$1.applyMatrix4( sprite.matrixWorld );
12216 return this.intersectsSphere( _sphere$1 );
12220 intersectsSphere( sphere ) {
12222 const planes = this.planes;
12223 const center = sphere.center;
12224 const negRadius = - sphere.radius;
12226 for ( let i = 0; i < 6; i ++ ) {
12228 const distance = planes[ i ].distanceToPoint( center );
12230 if ( distance < negRadius ) {
12242 intersectsBox( box ) {
12244 const planes = this.planes;
12246 for ( let i = 0; i < 6; i ++ ) {
12248 const plane = planes[ i ];
12250 // corner at max distance
12252 _vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x;
12253 _vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y;
12254 _vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z;
12256 if ( plane.distanceToPoint( _vector$5 ) < 0 ) {
12268 containsPoint( point ) {
12270 const planes = this.planes;
12272 for ( let i = 0; i < 6; i ++ ) {
12274 if ( planes[ i ].distanceToPoint( point ) < 0 ) {
12288 function WebGLAnimation() {
12290 let context = null;
12291 let isAnimating = false;
12292 let animationLoop = null;
12293 let requestId = null;
12295 function onAnimationFrame( time, frame ) {
12297 animationLoop( time, frame );
12299 requestId = context.requestAnimationFrame( onAnimationFrame );
12305 start: function () {
12307 if ( isAnimating === true ) return;
12308 if ( animationLoop === null ) return;
12310 requestId = context.requestAnimationFrame( onAnimationFrame );
12312 isAnimating = true;
12316 stop: function () {
12318 context.cancelAnimationFrame( requestId );
12320 isAnimating = false;
12324 setAnimationLoop: function ( callback ) {
12326 animationLoop = callback;
12330 setContext: function ( value ) {
12340 function WebGLAttributes( gl, capabilities ) {
12342 const isWebGL2 = capabilities.isWebGL2;
12344 const buffers = new WeakMap();
12346 function createBuffer( attribute, bufferType ) {
12348 const array = attribute.array;
12349 const usage = attribute.usage;
12351 const buffer = gl.createBuffer();
12353 gl.bindBuffer( bufferType, buffer );
12354 gl.bufferData( bufferType, array, usage );
12356 attribute.onUploadCallback();
12360 if ( array instanceof Float32Array ) {
12364 } else if ( array instanceof Float64Array ) {
12366 console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
12368 } else if ( array instanceof Uint16Array ) {
12370 if ( attribute.isFloat16BufferAttribute ) {
12378 console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
12388 } else if ( array instanceof Int16Array ) {
12392 } else if ( array instanceof Uint32Array ) {
12396 } else if ( array instanceof Int32Array ) {
12400 } else if ( array instanceof Int8Array ) {
12404 } else if ( array instanceof Uint8Array ) {
12413 bytesPerElement: array.BYTES_PER_ELEMENT,
12414 version: attribute.version
12419 function updateBuffer( buffer, attribute, bufferType ) {
12421 const array = attribute.array;
12422 const updateRange = attribute.updateRange;
12424 gl.bindBuffer( bufferType, buffer );
12426 if ( updateRange.count === - 1 ) {
12428 // Not using update ranges
12430 gl.bufferSubData( bufferType, 0, array );
12436 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
12437 array, updateRange.offset, updateRange.count );
12441 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
12442 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
12446 updateRange.count = - 1; // reset range
12454 function get( attribute ) {
12456 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12458 return buffers.get( attribute );
12462 function remove( attribute ) {
12464 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12466 const data = buffers.get( attribute );
12470 gl.deleteBuffer( data.buffer );
12472 buffers.delete( attribute );
12478 function update( attribute, bufferType ) {
12480 if ( attribute.isGLBufferAttribute ) {
12482 const cached = buffers.get( attribute );
12484 if ( ! cached || cached.version < attribute.version ) {
12486 buffers.set( attribute, {
12487 buffer: attribute.buffer,
12488 type: attribute.type,
12489 bytesPerElement: attribute.elementSize,
12490 version: attribute.version
12499 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12501 const data = buffers.get( attribute );
12503 if ( data === undefined ) {
12505 buffers.set( attribute, createBuffer( attribute, bufferType ) );
12507 } else if ( data.version < attribute.version ) {
12509 updateBuffer( data.buffer, attribute, bufferType );
12511 data.version = attribute.version;
12527 class PlaneGeometry extends BufferGeometry {
12529 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
12532 this.type = 'PlaneGeometry';
12534 this.parameters = {
12537 widthSegments: widthSegments,
12538 heightSegments: heightSegments
12541 const width_half = width / 2;
12542 const height_half = height / 2;
12544 const gridX = Math.floor( widthSegments );
12545 const gridY = Math.floor( heightSegments );
12547 const gridX1 = gridX + 1;
12548 const gridY1 = gridY + 1;
12550 const segment_width = width / gridX;
12551 const segment_height = height / gridY;
12555 const indices = [];
12556 const vertices = [];
12557 const normals = [];
12560 for ( let iy = 0; iy < gridY1; iy ++ ) {
12562 const y = iy * segment_height - height_half;
12564 for ( let ix = 0; ix < gridX1; ix ++ ) {
12566 const x = ix * segment_width - width_half;
12568 vertices.push( x, - y, 0 );
12570 normals.push( 0, 0, 1 );
12572 uvs.push( ix / gridX );
12573 uvs.push( 1 - ( iy / gridY ) );
12579 for ( let iy = 0; iy < gridY; iy ++ ) {
12581 for ( let ix = 0; ix < gridX; ix ++ ) {
12583 const a = ix + gridX1 * iy;
12584 const b = ix + gridX1 * ( iy + 1 );
12585 const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
12586 const d = ( ix + 1 ) + gridX1 * iy;
12588 indices.push( a, b, d );
12589 indices.push( b, c, d );
12595 this.setIndex( indices );
12596 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
12597 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
12598 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
12604 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
12606 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
12608 var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif";
12610 var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif";
12612 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
12614 var begin_vertex = "vec3 transformed = vec3( position );";
12616 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
12618 var bsdfs = "vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\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\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_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}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * 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}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat 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_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif";
12620 var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\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 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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";
12622 var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
12624 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
12626 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
12628 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
12630 var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
12632 var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
12634 var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
12636 var color_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor.xyz *= color.xyz;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
12638 var 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; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\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 max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\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};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\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}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\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 linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.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}";
12640 var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.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\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\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\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + 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 ), m0, cubeUV_maxMipLevel );\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";
12642 var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
12644 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
12646 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
12648 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
12650 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
12652 var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
12654 var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( 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 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}";
12656 var 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#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\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";
12658 var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\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";
12660 var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\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";
12662 var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\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";
12664 var 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";
12666 var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif";
12668 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif";
12670 var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
12672 var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\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";
12674 var 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 texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}";
12676 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif";
12678 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
12680 var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif";
12682 var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\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 GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\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 getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.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 getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.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 getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.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 GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif";
12684 var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif";
12686 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
12688 var lights_toon_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)";
12690 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
12692 var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\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 GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)";
12694 var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).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_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif";
12696 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\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.specularRoughness;\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 GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * 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}";
12698 var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\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\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( 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, geometry, 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\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\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, 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\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( 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, geometry, 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, geometry, 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\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\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 ], geometry );\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";
12700 var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif";
12702 var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif";
12704 var 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";
12706 var 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";
12708 var 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";
12710 var 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";
12712 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
12714 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
12716 var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif";
12718 var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
12720 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
12722 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
12724 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif";
12726 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
12728 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif";
12730 var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;";
12732 var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).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 * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
12734 var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
12736 var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
12738 var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif";
12740 var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif";
12742 var 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}\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 linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( 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 invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}";
12744 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
12746 var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;";
12748 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
12750 var 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";
12752 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
12754 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
12756 var shadowmap_pars_fragment = "#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\tvarying vec4 vSpotShadowCoord[ 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\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\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";
12758 var shadowmap_pars_vertex = "#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\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ 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 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";
12760 var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif";
12762 var 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, vSpotShadowCoord[ 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}";
12764 var 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";
12766 var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif";
12768 var 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";
12770 var 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";
12772 var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
12774 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
12776 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
12778 var 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 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}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
12780 var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif";
12782 var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif";
12784 var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
12786 var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif";
12788 var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
12790 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
12792 var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif";
12794 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
12796 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
12798 var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
12800 var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
12802 var cube_frag = "#include <envmap_common_pars_fragment>\nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include <envmap_fragment>\n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
12804 var cube_vert = "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}";
12806 var depth_frag = "#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 <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 <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}";
12808 var depth_vert = "#include <common>\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 <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}";
12810 var distanceRGBA_frag = "#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 <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\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}";
12812 var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\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 <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}";
12814 var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
12816 var equirect_vert = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
12818 var linedashed_frag = "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 <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 <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
12820 var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\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>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <color_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}";
12822 var meshbasic_frag = "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 <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_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 <cube_uv_reflection_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 <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\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12824 var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_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 <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\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 <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}";
12826 var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_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 <cube_uv_reflection_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_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 <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12828 var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <color_pars_vertex>\n#include <fog_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 <uv2_vertex>\n\t#include <color_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 <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
12830 var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\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 <fog_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 <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12832 var meshmatcap_vert = "#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_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 <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
12834 var meshtoon_frag = "#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 <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_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 <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 <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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12836 var meshtoon_vert = "#define TOON\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_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 <uv2_vertex>\n\t#include <color_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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#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\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
12838 var meshphong_frag = "#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 <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_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 <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\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 <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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12840 var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_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 <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#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\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
12842 var meshphysical_frag = "#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSMISSION\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSMISSION\n\tuniform float transmission;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#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\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <transmissionmap_pars_fragment>\n#include <bsdfs>\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 <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_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#ifdef TRANSMISSION\n\t\tfloat totalTransmission = transmission;\n\t#endif\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 <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 <transmissionmap_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 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSMISSION\n\t\tdiffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
12844 var meshphysical_vert = "#define STANDARD\nvarying vec3 vViewPosition;\n#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\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_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 <uv2_vertex>\n\t#include <color_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#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\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}";
12846 var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#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\n#include <packing>\n#include <uv_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}";
12848 var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#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\n#include <common>\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>\nvoid main() {\n\t#include <uv_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#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\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( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}";
12850 var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_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\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
12852 var points_vert = "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>\nvoid main() {\n\t#include <color_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}";
12854 var shadow_frag = "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 <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
12856 var shadow_vert = "#include <common>\n#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_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 <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
12858 var sprite_frag = "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 <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\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
12860 var sprite_vert = "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}";
12862 const ShaderChunk = {
12863 alphamap_fragment: alphamap_fragment,
12864 alphamap_pars_fragment: alphamap_pars_fragment,
12865 alphatest_fragment: alphatest_fragment,
12866 aomap_fragment: aomap_fragment,
12867 aomap_pars_fragment: aomap_pars_fragment,
12868 begin_vertex: begin_vertex,
12869 beginnormal_vertex: beginnormal_vertex,
12871 bumpmap_pars_fragment: bumpmap_pars_fragment,
12872 clipping_planes_fragment: clipping_planes_fragment,
12873 clipping_planes_pars_fragment: clipping_planes_pars_fragment,
12874 clipping_planes_pars_vertex: clipping_planes_pars_vertex,
12875 clipping_planes_vertex: clipping_planes_vertex,
12876 color_fragment: color_fragment,
12877 color_pars_fragment: color_pars_fragment,
12878 color_pars_vertex: color_pars_vertex,
12879 color_vertex: color_vertex,
12881 cube_uv_reflection_fragment: cube_uv_reflection_fragment,
12882 defaultnormal_vertex: defaultnormal_vertex,
12883 displacementmap_pars_vertex: displacementmap_pars_vertex,
12884 displacementmap_vertex: displacementmap_vertex,
12885 emissivemap_fragment: emissivemap_fragment,
12886 emissivemap_pars_fragment: emissivemap_pars_fragment,
12887 encodings_fragment: encodings_fragment,
12888 encodings_pars_fragment: encodings_pars_fragment,
12889 envmap_fragment: envmap_fragment,
12890 envmap_common_pars_fragment: envmap_common_pars_fragment,
12891 envmap_pars_fragment: envmap_pars_fragment,
12892 envmap_pars_vertex: envmap_pars_vertex,
12893 envmap_physical_pars_fragment: envmap_physical_pars_fragment,
12894 envmap_vertex: envmap_vertex,
12895 fog_vertex: fog_vertex,
12896 fog_pars_vertex: fog_pars_vertex,
12897 fog_fragment: fog_fragment,
12898 fog_pars_fragment: fog_pars_fragment,
12899 gradientmap_pars_fragment: gradientmap_pars_fragment,
12900 lightmap_fragment: lightmap_fragment,
12901 lightmap_pars_fragment: lightmap_pars_fragment,
12902 lights_lambert_vertex: lights_lambert_vertex,
12903 lights_pars_begin: lights_pars_begin,
12904 lights_toon_fragment: lights_toon_fragment,
12905 lights_toon_pars_fragment: lights_toon_pars_fragment,
12906 lights_phong_fragment: lights_phong_fragment,
12907 lights_phong_pars_fragment: lights_phong_pars_fragment,
12908 lights_physical_fragment: lights_physical_fragment,
12909 lights_physical_pars_fragment: lights_physical_pars_fragment,
12910 lights_fragment_begin: lights_fragment_begin,
12911 lights_fragment_maps: lights_fragment_maps,
12912 lights_fragment_end: lights_fragment_end,
12913 logdepthbuf_fragment: logdepthbuf_fragment,
12914 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
12915 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
12916 logdepthbuf_vertex: logdepthbuf_vertex,
12917 map_fragment: map_fragment,
12918 map_pars_fragment: map_pars_fragment,
12919 map_particle_fragment: map_particle_fragment,
12920 map_particle_pars_fragment: map_particle_pars_fragment,
12921 metalnessmap_fragment: metalnessmap_fragment,
12922 metalnessmap_pars_fragment: metalnessmap_pars_fragment,
12923 morphnormal_vertex: morphnormal_vertex,
12924 morphtarget_pars_vertex: morphtarget_pars_vertex,
12925 morphtarget_vertex: morphtarget_vertex,
12926 normal_fragment_begin: normal_fragment_begin,
12927 normal_fragment_maps: normal_fragment_maps,
12928 normalmap_pars_fragment: normalmap_pars_fragment,
12929 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
12930 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
12931 clearcoat_pars_fragment: clearcoat_pars_fragment,
12933 premultiplied_alpha_fragment: premultiplied_alpha_fragment,
12934 project_vertex: project_vertex,
12935 dithering_fragment: dithering_fragment,
12936 dithering_pars_fragment: dithering_pars_fragment,
12937 roughnessmap_fragment: roughnessmap_fragment,
12938 roughnessmap_pars_fragment: roughnessmap_pars_fragment,
12939 shadowmap_pars_fragment: shadowmap_pars_fragment,
12940 shadowmap_pars_vertex: shadowmap_pars_vertex,
12941 shadowmap_vertex: shadowmap_vertex,
12942 shadowmask_pars_fragment: shadowmask_pars_fragment,
12943 skinbase_vertex: skinbase_vertex,
12944 skinning_pars_vertex: skinning_pars_vertex,
12945 skinning_vertex: skinning_vertex,
12946 skinnormal_vertex: skinnormal_vertex,
12947 specularmap_fragment: specularmap_fragment,
12948 specularmap_pars_fragment: specularmap_pars_fragment,
12949 tonemapping_fragment: tonemapping_fragment,
12950 tonemapping_pars_fragment: tonemapping_pars_fragment,
12951 transmissionmap_fragment: transmissionmap_fragment,
12952 transmissionmap_pars_fragment: transmissionmap_pars_fragment,
12953 uv_pars_fragment: uv_pars_fragment,
12954 uv_pars_vertex: uv_pars_vertex,
12955 uv_vertex: uv_vertex,
12956 uv2_pars_fragment: uv2_pars_fragment,
12957 uv2_pars_vertex: uv2_pars_vertex,
12958 uv2_vertex: uv2_vertex,
12959 worldpos_vertex: worldpos_vertex,
12961 background_frag: background_frag,
12962 background_vert: background_vert,
12963 cube_frag: cube_frag,
12964 cube_vert: cube_vert,
12965 depth_frag: depth_frag,
12966 depth_vert: depth_vert,
12967 distanceRGBA_frag: distanceRGBA_frag,
12968 distanceRGBA_vert: distanceRGBA_vert,
12969 equirect_frag: equirect_frag,
12970 equirect_vert: equirect_vert,
12971 linedashed_frag: linedashed_frag,
12972 linedashed_vert: linedashed_vert,
12973 meshbasic_frag: meshbasic_frag,
12974 meshbasic_vert: meshbasic_vert,
12975 meshlambert_frag: meshlambert_frag,
12976 meshlambert_vert: meshlambert_vert,
12977 meshmatcap_frag: meshmatcap_frag,
12978 meshmatcap_vert: meshmatcap_vert,
12979 meshtoon_frag: meshtoon_frag,
12980 meshtoon_vert: meshtoon_vert,
12981 meshphong_frag: meshphong_frag,
12982 meshphong_vert: meshphong_vert,
12983 meshphysical_frag: meshphysical_frag,
12984 meshphysical_vert: meshphysical_vert,
12985 normal_frag: normal_frag,
12986 normal_vert: normal_vert,
12987 points_frag: points_frag,
12988 points_vert: points_vert,
12989 shadow_frag: shadow_frag,
12990 shadow_vert: shadow_vert,
12991 sprite_frag: sprite_frag,
12992 sprite_vert: sprite_vert
12996 * Uniforms library for shared webgl shaders
12999 const UniformsLib = {
13003 diffuse: { value: new Color( 0xeeeeee ) },
13004 opacity: { value: 1.0 },
13006 map: { value: null },
13007 uvTransform: { value: new Matrix3() },
13008 uv2Transform: { value: new Matrix3() },
13010 alphaMap: { value: null },
13016 specularMap: { value: null },
13022 envMap: { value: null },
13023 flipEnvMap: { value: - 1 },
13024 reflectivity: { value: 1.0 },
13025 refractionRatio: { value: 0.98 },
13026 maxMipLevel: { value: 0 }
13032 aoMap: { value: null },
13033 aoMapIntensity: { value: 1 }
13039 lightMap: { value: null },
13040 lightMapIntensity: { value: 1 }
13046 emissiveMap: { value: null }
13052 bumpMap: { value: null },
13053 bumpScale: { value: 1 }
13059 normalMap: { value: null },
13060 normalScale: { value: new Vector2( 1, 1 ) }
13066 displacementMap: { value: null },
13067 displacementScale: { value: 1 },
13068 displacementBias: { value: 0 }
13074 roughnessMap: { value: null }
13080 metalnessMap: { value: null }
13086 gradientMap: { value: null }
13092 fogDensity: { value: 0.00025 },
13093 fogNear: { value: 1 },
13094 fogFar: { value: 2000 },
13095 fogColor: { value: new Color( 0xffffff ) }
13101 ambientLightColor: { value: [] },
13103 lightProbe: { value: [] },
13105 directionalLights: { value: [], properties: {
13110 directionalLightShadows: { value: [], properties: {
13112 shadowNormalBias: {},
13117 directionalShadowMap: { value: [] },
13118 directionalShadowMatrix: { value: [] },
13120 spotLights: { value: [], properties: {
13130 spotLightShadows: { value: [], properties: {
13132 shadowNormalBias: {},
13137 spotShadowMap: { value: [] },
13138 spotShadowMatrix: { value: [] },
13140 pointLights: { value: [], properties: {
13147 pointLightShadows: { value: [], properties: {
13149 shadowNormalBias: {},
13152 shadowCameraNear: {},
13153 shadowCameraFar: {}
13156 pointShadowMap: { value: [] },
13157 pointShadowMatrix: { value: [] },
13159 hemisphereLights: { value: [], properties: {
13165 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
13166 rectAreaLights: { value: [], properties: {
13173 ltc_1: { value: null },
13174 ltc_2: { value: null }
13180 diffuse: { value: new Color( 0xeeeeee ) },
13181 opacity: { value: 1.0 },
13182 size: { value: 1.0 },
13183 scale: { value: 1.0 },
13184 map: { value: null },
13185 alphaMap: { value: null },
13186 uvTransform: { value: new Matrix3() }
13192 diffuse: { value: new Color( 0xeeeeee ) },
13193 opacity: { value: 1.0 },
13194 center: { value: new Vector2( 0.5, 0.5 ) },
13195 rotation: { value: 0.0 },
13196 map: { value: null },
13197 alphaMap: { value: null },
13198 uvTransform: { value: new Matrix3() }
13204 const ShaderLib = {
13208 uniforms: mergeUniforms( [
13209 UniformsLib.common,
13210 UniformsLib.specularmap,
13211 UniformsLib.envmap,
13213 UniformsLib.lightmap,
13217 vertexShader: ShaderChunk.meshbasic_vert,
13218 fragmentShader: ShaderChunk.meshbasic_frag
13224 uniforms: mergeUniforms( [
13225 UniformsLib.common,
13226 UniformsLib.specularmap,
13227 UniformsLib.envmap,
13229 UniformsLib.lightmap,
13230 UniformsLib.emissivemap,
13232 UniformsLib.lights,
13234 emissive: { value: new Color( 0x000000 ) }
13238 vertexShader: ShaderChunk.meshlambert_vert,
13239 fragmentShader: ShaderChunk.meshlambert_frag
13245 uniforms: mergeUniforms( [
13246 UniformsLib.common,
13247 UniformsLib.specularmap,
13248 UniformsLib.envmap,
13250 UniformsLib.lightmap,
13251 UniformsLib.emissivemap,
13252 UniformsLib.bumpmap,
13253 UniformsLib.normalmap,
13254 UniformsLib.displacementmap,
13256 UniformsLib.lights,
13258 emissive: { value: new Color( 0x000000 ) },
13259 specular: { value: new Color( 0x111111 ) },
13260 shininess: { value: 30 }
13264 vertexShader: ShaderChunk.meshphong_vert,
13265 fragmentShader: ShaderChunk.meshphong_frag
13271 uniforms: mergeUniforms( [
13272 UniformsLib.common,
13273 UniformsLib.envmap,
13275 UniformsLib.lightmap,
13276 UniformsLib.emissivemap,
13277 UniformsLib.bumpmap,
13278 UniformsLib.normalmap,
13279 UniformsLib.displacementmap,
13280 UniformsLib.roughnessmap,
13281 UniformsLib.metalnessmap,
13283 UniformsLib.lights,
13285 emissive: { value: new Color( 0x000000 ) },
13286 roughness: { value: 1.0 },
13287 metalness: { value: 0.0 },
13288 envMapIntensity: { value: 1 } // temporary
13292 vertexShader: ShaderChunk.meshphysical_vert,
13293 fragmentShader: ShaderChunk.meshphysical_frag
13299 uniforms: mergeUniforms( [
13300 UniformsLib.common,
13302 UniformsLib.lightmap,
13303 UniformsLib.emissivemap,
13304 UniformsLib.bumpmap,
13305 UniformsLib.normalmap,
13306 UniformsLib.displacementmap,
13307 UniformsLib.gradientmap,
13309 UniformsLib.lights,
13311 emissive: { value: new Color( 0x000000 ) }
13315 vertexShader: ShaderChunk.meshtoon_vert,
13316 fragmentShader: ShaderChunk.meshtoon_frag
13322 uniforms: mergeUniforms( [
13323 UniformsLib.common,
13324 UniformsLib.bumpmap,
13325 UniformsLib.normalmap,
13326 UniformsLib.displacementmap,
13329 matcap: { value: null }
13333 vertexShader: ShaderChunk.meshmatcap_vert,
13334 fragmentShader: ShaderChunk.meshmatcap_frag
13340 uniforms: mergeUniforms( [
13341 UniformsLib.points,
13345 vertexShader: ShaderChunk.points_vert,
13346 fragmentShader: ShaderChunk.points_frag
13352 uniforms: mergeUniforms( [
13353 UniformsLib.common,
13356 scale: { value: 1 },
13357 dashSize: { value: 1 },
13358 totalSize: { value: 2 }
13362 vertexShader: ShaderChunk.linedashed_vert,
13363 fragmentShader: ShaderChunk.linedashed_frag
13369 uniforms: mergeUniforms( [
13370 UniformsLib.common,
13371 UniformsLib.displacementmap
13374 vertexShader: ShaderChunk.depth_vert,
13375 fragmentShader: ShaderChunk.depth_frag
13381 uniforms: mergeUniforms( [
13382 UniformsLib.common,
13383 UniformsLib.bumpmap,
13384 UniformsLib.normalmap,
13385 UniformsLib.displacementmap,
13387 opacity: { value: 1.0 }
13391 vertexShader: ShaderChunk.normal_vert,
13392 fragmentShader: ShaderChunk.normal_frag
13398 uniforms: mergeUniforms( [
13399 UniformsLib.sprite,
13403 vertexShader: ShaderChunk.sprite_vert,
13404 fragmentShader: ShaderChunk.sprite_frag
13411 uvTransform: { value: new Matrix3() },
13412 t2D: { value: null },
13415 vertexShader: ShaderChunk.background_vert,
13416 fragmentShader: ShaderChunk.background_frag
13419 /* -------------------------------------------------------------------------
13421 ------------------------------------------------------------------------- */
13425 uniforms: mergeUniforms( [
13426 UniformsLib.envmap,
13428 opacity: { value: 1.0 }
13432 vertexShader: ShaderChunk.cube_vert,
13433 fragmentShader: ShaderChunk.cube_frag
13440 tEquirect: { value: null },
13443 vertexShader: ShaderChunk.equirect_vert,
13444 fragmentShader: ShaderChunk.equirect_frag
13450 uniforms: mergeUniforms( [
13451 UniformsLib.common,
13452 UniformsLib.displacementmap,
13454 referencePosition: { value: new Vector3() },
13455 nearDistance: { value: 1 },
13456 farDistance: { value: 1000 }
13460 vertexShader: ShaderChunk.distanceRGBA_vert,
13461 fragmentShader: ShaderChunk.distanceRGBA_frag
13467 uniforms: mergeUniforms( [
13468 UniformsLib.lights,
13471 color: { value: new Color( 0x00000 ) },
13472 opacity: { value: 1.0 }
13476 vertexShader: ShaderChunk.shadow_vert,
13477 fragmentShader: ShaderChunk.shadow_frag
13483 ShaderLib.physical = {
13485 uniforms: mergeUniforms( [
13486 ShaderLib.standard.uniforms,
13488 clearcoat: { value: 0 },
13489 clearcoatMap: { value: null },
13490 clearcoatRoughness: { value: 0 },
13491 clearcoatRoughnessMap: { value: null },
13492 clearcoatNormalScale: { value: new Vector2( 1, 1 ) },
13493 clearcoatNormalMap: { value: null },
13494 sheen: { value: new Color( 0x000000 ) },
13495 transmission: { value: 0 },
13496 transmissionMap: { value: null },
13500 vertexShader: ShaderChunk.meshphysical_vert,
13501 fragmentShader: ShaderChunk.meshphysical_frag
13505 function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
13507 const clearColor = new Color( 0x000000 );
13508 let clearAlpha = 0;
13513 let currentBackground = null;
13514 let currentBackgroundVersion = 0;
13515 let currentTonemapping = null;
13517 function render( renderList, scene, camera, forceClear ) {
13519 let background = scene.isScene === true ? scene.background : null;
13521 if ( background && background.isTexture ) {
13523 background = cubemaps.get( background );
13527 // Ignore background in AR
13528 // TODO: Reconsider this.
13530 const xr = renderer.xr;
13531 const session = xr.getSession && xr.getSession();
13533 if ( session && session.environmentBlendMode === 'additive' ) {
13539 if ( background === null ) {
13541 setClear( clearColor, clearAlpha );
13543 } else if ( background && background.isColor ) {
13545 setClear( background, 1 );
13550 if ( renderer.autoClear || forceClear ) {
13552 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
13556 if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) {
13558 if ( boxMesh === undefined ) {
13560 boxMesh = new Mesh(
13561 new BoxGeometry( 1, 1, 1 ),
13562 new ShaderMaterial( {
13563 name: 'BackgroundCubeMaterial',
13564 uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
13565 vertexShader: ShaderLib.cube.vertexShader,
13566 fragmentShader: ShaderLib.cube.fragmentShader,
13574 boxMesh.geometry.deleteAttribute( 'normal' );
13575 boxMesh.geometry.deleteAttribute( 'uv' );
13577 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
13579 this.matrixWorld.copyPosition( camera.matrixWorld );
13583 // enable code injection for non-built-in material
13584 Object.defineProperty( boxMesh.material, 'envMap', {
13588 return this.uniforms.envMap.value;
13594 objects.update( boxMesh );
13598 if ( background.isWebGLCubeRenderTarget ) {
13602 background = background.texture;
13606 boxMesh.material.uniforms.envMap.value = background;
13607 boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background._needsFlipEnvMap ) ? - 1 : 1;
13609 if ( currentBackground !== background ||
13610 currentBackgroundVersion !== background.version ||
13611 currentTonemapping !== renderer.toneMapping ) {
13613 boxMesh.material.needsUpdate = true;
13615 currentBackground = background;
13616 currentBackgroundVersion = background.version;
13617 currentTonemapping = renderer.toneMapping;
13621 // push to the pre-sorted opaque render list
13622 renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
13624 } else if ( background && background.isTexture ) {
13626 if ( planeMesh === undefined ) {
13628 planeMesh = new Mesh(
13629 new PlaneGeometry( 2, 2 ),
13630 new ShaderMaterial( {
13631 name: 'BackgroundMaterial',
13632 uniforms: cloneUniforms( ShaderLib.background.uniforms ),
13633 vertexShader: ShaderLib.background.vertexShader,
13634 fragmentShader: ShaderLib.background.fragmentShader,
13642 planeMesh.geometry.deleteAttribute( 'normal' );
13644 // enable code injection for non-built-in material
13645 Object.defineProperty( planeMesh.material, 'map', {
13649 return this.uniforms.t2D.value;
13655 objects.update( planeMesh );
13659 planeMesh.material.uniforms.t2D.value = background;
13661 if ( background.matrixAutoUpdate === true ) {
13663 background.updateMatrix();
13667 planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
13669 if ( currentBackground !== background ||
13670 currentBackgroundVersion !== background.version ||
13671 currentTonemapping !== renderer.toneMapping ) {
13673 planeMesh.material.needsUpdate = true;
13675 currentBackground = background;
13676 currentBackgroundVersion = background.version;
13677 currentTonemapping = renderer.toneMapping;
13682 // push to the pre-sorted opaque render list
13683 renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
13689 function setClear( color, alpha ) {
13691 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
13697 getClearColor: function () {
13702 setClearColor: function ( color, alpha = 1 ) {
13704 clearColor.set( color );
13705 clearAlpha = alpha;
13706 setClear( clearColor, clearAlpha );
13709 getClearAlpha: function () {
13714 setClearAlpha: function ( alpha ) {
13716 clearAlpha = alpha;
13717 setClear( clearColor, clearAlpha );
13726 function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
13728 const maxVertexAttributes = gl.getParameter( 34921 );
13730 const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
13731 const vaoAvailable = capabilities.isWebGL2 || extension !== null;
13733 const bindingStates = {};
13735 const defaultState = createBindingState( null );
13736 let currentState = defaultState;
13738 function setup( object, material, program, geometry, index ) {
13740 let updateBuffers = false;
13742 if ( vaoAvailable ) {
13744 const state = getBindingState( geometry, program, material );
13746 if ( currentState !== state ) {
13748 currentState = state;
13749 bindVertexArrayObject( currentState.object );
13753 updateBuffers = needsUpdate( geometry, index );
13755 if ( updateBuffers ) saveCache( geometry, index );
13759 const wireframe = ( material.wireframe === true );
13761 if ( currentState.geometry !== geometry.id ||
13762 currentState.program !== program.id ||
13763 currentState.wireframe !== wireframe ) {
13765 currentState.geometry = geometry.id;
13766 currentState.program = program.id;
13767 currentState.wireframe = wireframe;
13769 updateBuffers = true;
13775 if ( object.isInstancedMesh === true ) {
13777 updateBuffers = true;
13781 if ( index !== null ) {
13783 attributes.update( index, 34963 );
13787 if ( updateBuffers ) {
13789 setupVertexAttributes( object, material, program, geometry );
13791 if ( index !== null ) {
13793 gl.bindBuffer( 34963, attributes.get( index ).buffer );
13801 function createVertexArrayObject() {
13803 if ( capabilities.isWebGL2 ) return gl.createVertexArray();
13805 return extension.createVertexArrayOES();
13809 function bindVertexArrayObject( vao ) {
13811 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
13813 return extension.bindVertexArrayOES( vao );
13817 function deleteVertexArrayObject( vao ) {
13819 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
13821 return extension.deleteVertexArrayOES( vao );
13825 function getBindingState( geometry, program, material ) {
13827 const wireframe = ( material.wireframe === true );
13829 let programMap = bindingStates[ geometry.id ];
13831 if ( programMap === undefined ) {
13834 bindingStates[ geometry.id ] = programMap;
13838 let stateMap = programMap[ program.id ];
13840 if ( stateMap === undefined ) {
13843 programMap[ program.id ] = stateMap;
13847 let state = stateMap[ wireframe ];
13849 if ( state === undefined ) {
13851 state = createBindingState( createVertexArrayObject() );
13852 stateMap[ wireframe ] = state;
13860 function createBindingState( vao ) {
13862 const newAttributes = [];
13863 const enabledAttributes = [];
13864 const attributeDivisors = [];
13866 for ( let i = 0; i < maxVertexAttributes; i ++ ) {
13868 newAttributes[ i ] = 0;
13869 enabledAttributes[ i ] = 0;
13870 attributeDivisors[ i ] = 0;
13876 // for backward compatibility on non-VAO support browser
13881 newAttributes: newAttributes,
13882 enabledAttributes: enabledAttributes,
13883 attributeDivisors: attributeDivisors,
13892 function needsUpdate( geometry, index ) {
13894 const cachedAttributes = currentState.attributes;
13895 const geometryAttributes = geometry.attributes;
13897 let attributesNum = 0;
13899 for ( const key in geometryAttributes ) {
13901 const cachedAttribute = cachedAttributes[ key ];
13902 const geometryAttribute = geometryAttributes[ key ];
13904 if ( cachedAttribute === undefined ) return true;
13906 if ( cachedAttribute.attribute !== geometryAttribute ) return true;
13908 if ( cachedAttribute.data !== geometryAttribute.data ) return true;
13914 if ( currentState.attributesNum !== attributesNum ) return true;
13916 if ( currentState.index !== index ) return true;
13922 function saveCache( geometry, index ) {
13925 const attributes = geometry.attributes;
13926 let attributesNum = 0;
13928 for ( const key in attributes ) {
13930 const attribute = attributes[ key ];
13933 data.attribute = attribute;
13935 if ( attribute.data ) {
13937 data.data = attribute.data;
13941 cache[ key ] = data;
13947 currentState.attributes = cache;
13948 currentState.attributesNum = attributesNum;
13950 currentState.index = index;
13954 function initAttributes() {
13956 const newAttributes = currentState.newAttributes;
13958 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
13960 newAttributes[ i ] = 0;
13966 function enableAttribute( attribute ) {
13968 enableAttributeAndDivisor( attribute, 0 );
13972 function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
13974 const newAttributes = currentState.newAttributes;
13975 const enabledAttributes = currentState.enabledAttributes;
13976 const attributeDivisors = currentState.attributeDivisors;
13978 newAttributes[ attribute ] = 1;
13980 if ( enabledAttributes[ attribute ] === 0 ) {
13982 gl.enableVertexAttribArray( attribute );
13983 enabledAttributes[ attribute ] = 1;
13987 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
13989 const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
13991 extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
13992 attributeDivisors[ attribute ] = meshPerAttribute;
13998 function disableUnusedAttributes() {
14000 const newAttributes = currentState.newAttributes;
14001 const enabledAttributes = currentState.enabledAttributes;
14003 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
14005 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
14007 gl.disableVertexAttribArray( i );
14008 enabledAttributes[ i ] = 0;
14016 function vertexAttribPointer( index, size, type, normalized, stride, offset ) {
14018 if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) {
14020 gl.vertexAttribIPointer( index, size, type, stride, offset );
14024 gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
14030 function setupVertexAttributes( object, material, program, geometry ) {
14032 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
14034 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
14040 const geometryAttributes = geometry.attributes;
14042 const programAttributes = program.getAttributes();
14044 const materialDefaultAttributeValues = material.defaultAttributeValues;
14046 for ( const name in programAttributes ) {
14048 const programAttribute = programAttributes[ name ];
14050 if ( programAttribute >= 0 ) {
14052 const geometryAttribute = geometryAttributes[ name ];
14054 if ( geometryAttribute !== undefined ) {
14056 const normalized = geometryAttribute.normalized;
14057 const size = geometryAttribute.itemSize;
14059 const attribute = attributes.get( geometryAttribute );
14061 // TODO Attribute may not be available on context restore
14063 if ( attribute === undefined ) continue;
14065 const buffer = attribute.buffer;
14066 const type = attribute.type;
14067 const bytesPerElement = attribute.bytesPerElement;
14069 if ( geometryAttribute.isInterleavedBufferAttribute ) {
14071 const data = geometryAttribute.data;
14072 const stride = data.stride;
14073 const offset = geometryAttribute.offset;
14075 if ( data && data.isInstancedInterleavedBuffer ) {
14077 enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
14079 if ( geometry._maxInstanceCount === undefined ) {
14081 geometry._maxInstanceCount = data.meshPerAttribute * data.count;
14087 enableAttribute( programAttribute );
14091 gl.bindBuffer( 34962, buffer );
14092 vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement );
14096 if ( geometryAttribute.isInstancedBufferAttribute ) {
14098 enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
14100 if ( geometry._maxInstanceCount === undefined ) {
14102 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
14108 enableAttribute( programAttribute );
14112 gl.bindBuffer( 34962, buffer );
14113 vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 );
14117 } else if ( name === 'instanceMatrix' ) {
14119 const attribute = attributes.get( object.instanceMatrix );
14121 // TODO Attribute may not be available on context restore
14123 if ( attribute === undefined ) continue;
14125 const buffer = attribute.buffer;
14126 const type = attribute.type;
14128 enableAttributeAndDivisor( programAttribute + 0, 1 );
14129 enableAttributeAndDivisor( programAttribute + 1, 1 );
14130 enableAttributeAndDivisor( programAttribute + 2, 1 );
14131 enableAttributeAndDivisor( programAttribute + 3, 1 );
14133 gl.bindBuffer( 34962, buffer );
14135 gl.vertexAttribPointer( programAttribute + 0, 4, type, false, 64, 0 );
14136 gl.vertexAttribPointer( programAttribute + 1, 4, type, false, 64, 16 );
14137 gl.vertexAttribPointer( programAttribute + 2, 4, type, false, 64, 32 );
14138 gl.vertexAttribPointer( programAttribute + 3, 4, type, false, 64, 48 );
14140 } else if ( name === 'instanceColor' ) {
14142 const attribute = attributes.get( object.instanceColor );
14144 // TODO Attribute may not be available on context restore
14146 if ( attribute === undefined ) continue;
14148 const buffer = attribute.buffer;
14149 const type = attribute.type;
14151 enableAttributeAndDivisor( programAttribute, 1 );
14153 gl.bindBuffer( 34962, buffer );
14155 gl.vertexAttribPointer( programAttribute, 3, type, false, 12, 0 );
14157 } else if ( materialDefaultAttributeValues !== undefined ) {
14159 const value = materialDefaultAttributeValues[ name ];
14161 if ( value !== undefined ) {
14163 switch ( value.length ) {
14166 gl.vertexAttrib2fv( programAttribute, value );
14170 gl.vertexAttrib3fv( programAttribute, value );
14174 gl.vertexAttrib4fv( programAttribute, value );
14178 gl.vertexAttrib1fv( programAttribute, value );
14190 disableUnusedAttributes();
14194 function dispose() {
14198 for ( const geometryId in bindingStates ) {
14200 const programMap = bindingStates[ geometryId ];
14202 for ( const programId in programMap ) {
14204 const stateMap = programMap[ programId ];
14206 for ( const wireframe in stateMap ) {
14208 deleteVertexArrayObject( stateMap[ wireframe ].object );
14210 delete stateMap[ wireframe ];
14214 delete programMap[ programId ];
14218 delete bindingStates[ geometryId ];
14224 function releaseStatesOfGeometry( geometry ) {
14226 if ( bindingStates[ geometry.id ] === undefined ) return;
14228 const programMap = bindingStates[ geometry.id ];
14230 for ( const programId in programMap ) {
14232 const stateMap = programMap[ programId ];
14234 for ( const wireframe in stateMap ) {
14236 deleteVertexArrayObject( stateMap[ wireframe ].object );
14238 delete stateMap[ wireframe ];
14242 delete programMap[ programId ];
14246 delete bindingStates[ geometry.id ];
14250 function releaseStatesOfProgram( program ) {
14252 for ( const geometryId in bindingStates ) {
14254 const programMap = bindingStates[ geometryId ];
14256 if ( programMap[ program.id ] === undefined ) continue;
14258 const stateMap = programMap[ program.id ];
14260 for ( const wireframe in stateMap ) {
14262 deleteVertexArrayObject( stateMap[ wireframe ].object );
14264 delete stateMap[ wireframe ];
14268 delete programMap[ program.id ];
14276 resetDefaultState();
14278 if ( currentState === defaultState ) return;
14280 currentState = defaultState;
14281 bindVertexArrayObject( currentState.object );
14285 // for backward-compatilibity
14287 function resetDefaultState() {
14289 defaultState.geometry = null;
14290 defaultState.program = null;
14291 defaultState.wireframe = false;
14299 resetDefaultState: resetDefaultState,
14301 releaseStatesOfGeometry: releaseStatesOfGeometry,
14302 releaseStatesOfProgram: releaseStatesOfProgram,
14304 initAttributes: initAttributes,
14305 enableAttribute: enableAttribute,
14306 disableUnusedAttributes: disableUnusedAttributes
14312 function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
14314 const isWebGL2 = capabilities.isWebGL2;
14318 function setMode( value ) {
14324 function render( start, count ) {
14326 gl.drawArrays( mode, start, count );
14328 info.update( count, mode, 1 );
14332 function renderInstances( start, count, primcount ) {
14334 if ( primcount === 0 ) return;
14336 let extension, methodName;
14341 methodName = 'drawArraysInstanced';
14345 extension = extensions.get( 'ANGLE_instanced_arrays' );
14346 methodName = 'drawArraysInstancedANGLE';
14348 if ( extension === null ) {
14350 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
14357 extension[ methodName ]( mode, start, count, primcount );
14359 info.update( count, mode, primcount );
14365 this.setMode = setMode;
14366 this.render = render;
14367 this.renderInstances = renderInstances;
14371 function WebGLCapabilities( gl, extensions, parameters ) {
14375 function getMaxAnisotropy() {
14377 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
14379 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
14381 if ( extension !== null ) {
14383 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
14391 return maxAnisotropy;
14395 function getMaxPrecision( precision ) {
14397 if ( precision === 'highp' ) {
14399 if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 &&
14400 gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) {
14406 precision = 'mediump';
14410 if ( precision === 'mediump' ) {
14412 if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 &&
14413 gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) {
14425 /* eslint-disable no-undef */
14426 const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) ||
14427 ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext );
14428 /* eslint-enable no-undef */
14430 let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
14431 const maxPrecision = getMaxPrecision( precision );
14433 if ( maxPrecision !== precision ) {
14435 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
14436 precision = maxPrecision;
14440 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
14442 const maxTextures = gl.getParameter( 34930 );
14443 const maxVertexTextures = gl.getParameter( 35660 );
14444 const maxTextureSize = gl.getParameter( 3379 );
14445 const maxCubemapSize = gl.getParameter( 34076 );
14447 const maxAttributes = gl.getParameter( 34921 );
14448 const maxVertexUniforms = gl.getParameter( 36347 );
14449 const maxVaryings = gl.getParameter( 36348 );
14450 const maxFragmentUniforms = gl.getParameter( 36349 );
14452 const vertexTextures = maxVertexTextures > 0;
14453 const floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
14454 const floatVertexTextures = vertexTextures && floatFragmentTextures;
14456 const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
14460 isWebGL2: isWebGL2,
14462 getMaxAnisotropy: getMaxAnisotropy,
14463 getMaxPrecision: getMaxPrecision,
14465 precision: precision,
14466 logarithmicDepthBuffer: logarithmicDepthBuffer,
14468 maxTextures: maxTextures,
14469 maxVertexTextures: maxVertexTextures,
14470 maxTextureSize: maxTextureSize,
14471 maxCubemapSize: maxCubemapSize,
14473 maxAttributes: maxAttributes,
14474 maxVertexUniforms: maxVertexUniforms,
14475 maxVaryings: maxVaryings,
14476 maxFragmentUniforms: maxFragmentUniforms,
14478 vertexTextures: vertexTextures,
14479 floatFragmentTextures: floatFragmentTextures,
14480 floatVertexTextures: floatVertexTextures,
14482 maxSamples: maxSamples
14488 function WebGLClipping( properties ) {
14490 const scope = this;
14492 let globalState = null,
14493 numGlobalPlanes = 0,
14494 localClippingEnabled = false,
14495 renderingShadows = false;
14497 const plane = new Plane(),
14498 viewNormalMatrix = new Matrix3(),
14500 uniform = { value: null, needsUpdate: false };
14502 this.uniform = uniform;
14503 this.numPlanes = 0;
14504 this.numIntersection = 0;
14506 this.init = function ( planes, enableLocalClipping, camera ) {
14509 planes.length !== 0 ||
14510 enableLocalClipping ||
14511 // enable state of previous frame - the clipping code has to
14512 // run another frame in order to reset the state:
14513 numGlobalPlanes !== 0 ||
14514 localClippingEnabled;
14516 localClippingEnabled = enableLocalClipping;
14518 globalState = projectPlanes( planes, camera, 0 );
14519 numGlobalPlanes = planes.length;
14525 this.beginShadows = function () {
14527 renderingShadows = true;
14528 projectPlanes( null );
14532 this.endShadows = function () {
14534 renderingShadows = false;
14535 resetGlobalState();
14539 this.setState = function ( material, camera, useCache ) {
14541 const planes = material.clippingPlanes,
14542 clipIntersection = material.clipIntersection,
14543 clipShadows = material.clipShadows;
14545 const materialProperties = properties.get( material );
14547 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
14549 // there's no local clipping
14551 if ( renderingShadows ) {
14553 // there's no global clipping
14555 projectPlanes( null );
14559 resetGlobalState();
14565 const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
14566 lGlobal = nGlobal * 4;
14568 let dstArray = materialProperties.clippingState || null;
14570 uniform.value = dstArray; // ensure unique state
14572 dstArray = projectPlanes( planes, camera, lGlobal, useCache );
14574 for ( let i = 0; i !== lGlobal; ++ i ) {
14576 dstArray[ i ] = globalState[ i ];
14580 materialProperties.clippingState = dstArray;
14581 this.numIntersection = clipIntersection ? this.numPlanes : 0;
14582 this.numPlanes += nGlobal;
14589 function resetGlobalState() {
14591 if ( uniform.value !== globalState ) {
14593 uniform.value = globalState;
14594 uniform.needsUpdate = numGlobalPlanes > 0;
14598 scope.numPlanes = numGlobalPlanes;
14599 scope.numIntersection = 0;
14603 function projectPlanes( planes, camera, dstOffset, skipTransform ) {
14605 const nPlanes = planes !== null ? planes.length : 0;
14606 let dstArray = null;
14608 if ( nPlanes !== 0 ) {
14610 dstArray = uniform.value;
14612 if ( skipTransform !== true || dstArray === null ) {
14614 const flatSize = dstOffset + nPlanes * 4,
14615 viewMatrix = camera.matrixWorldInverse;
14617 viewNormalMatrix.getNormalMatrix( viewMatrix );
14619 if ( dstArray === null || dstArray.length < flatSize ) {
14621 dstArray = new Float32Array( flatSize );
14625 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
14627 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
14629 plane.normal.toArray( dstArray, i4 );
14630 dstArray[ i4 + 3 ] = plane.constant;
14636 uniform.value = dstArray;
14637 uniform.needsUpdate = true;
14641 scope.numPlanes = nPlanes;
14642 scope.numIntersection = 0;
14650 function WebGLCubeMaps( renderer ) {
14652 let cubemaps = new WeakMap();
14654 function mapTextureMapping( texture, mapping ) {
14656 if ( mapping === EquirectangularReflectionMapping ) {
14658 texture.mapping = CubeReflectionMapping;
14660 } else if ( mapping === EquirectangularRefractionMapping ) {
14662 texture.mapping = CubeRefractionMapping;
14670 function get( texture ) {
14672 if ( texture && texture.isTexture ) {
14674 const mapping = texture.mapping;
14676 if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
14678 if ( cubemaps.has( texture ) ) {
14680 const cubemap = cubemaps.get( texture ).texture;
14681 return mapTextureMapping( cubemap, texture.mapping );
14685 const image = texture.image;
14687 if ( image && image.height > 0 ) {
14689 const currentRenderList = renderer.getRenderList();
14690 const currentRenderTarget = renderer.getRenderTarget();
14692 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
14693 renderTarget.fromEquirectangularTexture( renderer, texture );
14694 cubemaps.set( texture, renderTarget );
14696 renderer.setRenderTarget( currentRenderTarget );
14697 renderer.setRenderList( currentRenderList );
14699 texture.addEventListener( 'dispose', onTextureDispose );
14701 return mapTextureMapping( renderTarget.texture, texture.mapping );
14705 // image not yet ready. try the conversion next frame
14721 function onTextureDispose( event ) {
14723 const texture = event.target;
14725 texture.removeEventListener( 'dispose', onTextureDispose );
14727 const cubemap = cubemaps.get( texture );
14729 if ( cubemap !== undefined ) {
14731 cubemaps.delete( texture );
14738 function dispose() {
14740 cubemaps = new WeakMap();
14751 function WebGLExtensions( gl ) {
14753 const extensions = {};
14755 function getExtension( name ) {
14757 if ( extensions[ name ] !== undefined ) {
14759 return extensions[ name ];
14767 case 'WEBGL_depth_texture':
14768 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
14771 case 'EXT_texture_filter_anisotropic':
14772 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
14775 case 'WEBGL_compressed_texture_s3tc':
14776 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
14779 case 'WEBGL_compressed_texture_pvrtc':
14780 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
14784 extension = gl.getExtension( name );
14788 extensions[ name ] = extension;
14796 has: function ( name ) {
14798 return getExtension( name ) !== null;
14802 init: function ( capabilities ) {
14804 if ( capabilities.isWebGL2 ) {
14806 getExtension( 'EXT_color_buffer_float' );
14810 getExtension( 'WEBGL_depth_texture' );
14811 getExtension( 'OES_texture_float' );
14812 getExtension( 'OES_texture_half_float' );
14813 getExtension( 'OES_texture_half_float_linear' );
14814 getExtension( 'OES_standard_derivatives' );
14815 getExtension( 'OES_element_index_uint' );
14816 getExtension( 'OES_vertex_array_object' );
14817 getExtension( 'ANGLE_instanced_arrays' );
14821 getExtension( 'OES_texture_float_linear' );
14822 getExtension( 'EXT_color_buffer_half_float' );
14826 get: function ( name ) {
14828 const extension = getExtension( name );
14830 if ( extension === null ) {
14832 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
14844 function WebGLGeometries( gl, attributes, info, bindingStates ) {
14846 const geometries = {};
14847 const wireframeAttributes = new WeakMap();
14849 function onGeometryDispose( event ) {
14851 const geometry = event.target;
14853 if ( geometry.index !== null ) {
14855 attributes.remove( geometry.index );
14859 for ( const name in geometry.attributes ) {
14861 attributes.remove( geometry.attributes[ name ] );
14865 geometry.removeEventListener( 'dispose', onGeometryDispose );
14867 delete geometries[ geometry.id ];
14869 const attribute = wireframeAttributes.get( geometry );
14873 attributes.remove( attribute );
14874 wireframeAttributes.delete( geometry );
14878 bindingStates.releaseStatesOfGeometry( geometry );
14880 if ( geometry.isInstancedBufferGeometry === true ) {
14882 delete geometry._maxInstanceCount;
14888 info.memory.geometries --;
14892 function get( object, geometry ) {
14894 if ( geometries[ geometry.id ] === true ) return geometry;
14896 geometry.addEventListener( 'dispose', onGeometryDispose );
14898 geometries[ geometry.id ] = true;
14900 info.memory.geometries ++;
14906 function update( geometry ) {
14908 const geometryAttributes = geometry.attributes;
14910 // Updating index buffer in VAO now. See WebGLBindingStates.
14912 for ( const name in geometryAttributes ) {
14914 attributes.update( geometryAttributes[ name ], 34962 );
14920 const morphAttributes = geometry.morphAttributes;
14922 for ( const name in morphAttributes ) {
14924 const array = morphAttributes[ name ];
14926 for ( let i = 0, l = array.length; i < l; i ++ ) {
14928 attributes.update( array[ i ], 34962 );
14936 function updateWireframeAttribute( geometry ) {
14938 const indices = [];
14940 const geometryIndex = geometry.index;
14941 const geometryPosition = geometry.attributes.position;
14944 if ( geometryIndex !== null ) {
14946 const array = geometryIndex.array;
14947 version = geometryIndex.version;
14949 for ( let i = 0, l = array.length; i < l; i += 3 ) {
14951 const a = array[ i + 0 ];
14952 const b = array[ i + 1 ];
14953 const c = array[ i + 2 ];
14955 indices.push( a, b, b, c, c, a );
14961 const array = geometryPosition.array;
14962 version = geometryPosition.version;
14964 for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
14970 indices.push( a, b, b, c, c, a );
14976 const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
14977 attribute.version = version;
14979 // Updating index buffer in VAO now. See WebGLBindingStates
14983 const previousAttribute = wireframeAttributes.get( geometry );
14985 if ( previousAttribute ) attributes.remove( previousAttribute );
14989 wireframeAttributes.set( geometry, attribute );
14993 function getWireframeAttribute( geometry ) {
14995 const currentAttribute = wireframeAttributes.get( geometry );
14997 if ( currentAttribute ) {
14999 const geometryIndex = geometry.index;
15001 if ( geometryIndex !== null ) {
15003 // if the attribute is obsolete, create a new one
15005 if ( currentAttribute.version < geometryIndex.version ) {
15007 updateWireframeAttribute( geometry );
15015 updateWireframeAttribute( geometry );
15019 return wireframeAttributes.get( geometry );
15028 getWireframeAttribute: getWireframeAttribute
15034 function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
15036 const isWebGL2 = capabilities.isWebGL2;
15040 function setMode( value ) {
15046 let type, bytesPerElement;
15048 function setIndex( value ) {
15051 bytesPerElement = value.bytesPerElement;
15055 function render( start, count ) {
15057 gl.drawElements( mode, count, type, start * bytesPerElement );
15059 info.update( count, mode, 1 );
15063 function renderInstances( start, count, primcount ) {
15065 if ( primcount === 0 ) return;
15067 let extension, methodName;
15072 methodName = 'drawElementsInstanced';
15076 extension = extensions.get( 'ANGLE_instanced_arrays' );
15077 methodName = 'drawElementsInstancedANGLE';
15079 if ( extension === null ) {
15081 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
15088 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
15090 info.update( count, mode, primcount );
15096 this.setMode = setMode;
15097 this.setIndex = setIndex;
15098 this.render = render;
15099 this.renderInstances = renderInstances;
15103 function WebGLInfo( gl ) {
15118 function update( count, mode, instanceCount ) {
15125 render.triangles += instanceCount * ( count / 3 );
15129 render.lines += instanceCount * ( count / 2 );
15133 render.lines += instanceCount * ( count - 1 );
15137 render.lines += instanceCount * count;
15141 render.points += instanceCount * count;
15145 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
15156 render.triangles = 0;
15173 function numericalSort( a, b ) {
15175 return a[ 0 ] - b[ 0 ];
15179 function absNumericalSort( a, b ) {
15181 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
15185 function WebGLMorphtargets( gl ) {
15187 const influencesList = {};
15188 const morphInfluences = new Float32Array( 8 );
15190 const workInfluences = [];
15192 for ( let i = 0; i < 8; i ++ ) {
15194 workInfluences[ i ] = [ i, 0 ];
15198 function update( object, geometry, material, program ) {
15200 const objectInfluences = object.morphTargetInfluences;
15202 // When object doesn't have morph target influences defined, we treat it as a 0-length array
15203 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
15205 const length = objectInfluences === undefined ? 0 : objectInfluences.length;
15207 let influences = influencesList[ geometry.id ];
15209 if ( influences === undefined ) {
15215 for ( let i = 0; i < length; i ++ ) {
15217 influences[ i ] = [ i, 0 ];
15221 influencesList[ geometry.id ] = influences;
15225 // Collect influences
15227 for ( let i = 0; i < length; i ++ ) {
15229 const influence = influences[ i ];
15231 influence[ 0 ] = i;
15232 influence[ 1 ] = objectInfluences[ i ];
15236 influences.sort( absNumericalSort );
15238 for ( let i = 0; i < 8; i ++ ) {
15240 if ( i < length && influences[ i ][ 1 ] ) {
15242 workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
15243 workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
15247 workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
15248 workInfluences[ i ][ 1 ] = 0;
15254 workInfluences.sort( numericalSort );
15256 const morphTargets = material.morphTargets && geometry.morphAttributes.position;
15257 const morphNormals = material.morphNormals && geometry.morphAttributes.normal;
15259 let morphInfluencesSum = 0;
15261 for ( let i = 0; i < 8; i ++ ) {
15263 const influence = workInfluences[ i ];
15264 const index = influence[ 0 ];
15265 const value = influence[ 1 ];
15267 if ( index !== Number.MAX_SAFE_INTEGER && value ) {
15269 if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
15271 geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
15275 if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
15277 geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
15281 morphInfluences[ i ] = value;
15282 morphInfluencesSum += value;
15286 if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
15288 geometry.deleteAttribute( 'morphTarget' + i );
15292 if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
15294 geometry.deleteAttribute( 'morphNormal' + i );
15298 morphInfluences[ i ] = 0;
15304 // GLSL shader uses formula baseinfluence * base + sum(target * influence)
15305 // This allows us to switch between absolute morphs and relative morphs without changing shader code
15306 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
15307 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
15309 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
15310 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
15322 function WebGLObjects( gl, geometries, attributes, info ) {
15324 let updateMap = new WeakMap();
15326 function update( object ) {
15328 const frame = info.render.frame;
15330 const geometry = object.geometry;
15331 const buffergeometry = geometries.get( object, geometry );
15333 // Update once per frame
15335 if ( updateMap.get( buffergeometry ) !== frame ) {
15337 geometries.update( buffergeometry );
15339 updateMap.set( buffergeometry, frame );
15343 if ( object.isInstancedMesh ) {
15345 if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
15347 object.addEventListener( 'dispose', onInstancedMeshDispose );
15351 attributes.update( object.instanceMatrix, 34962 );
15353 if ( object.instanceColor !== null ) {
15355 attributes.update( object.instanceColor, 34962 );
15361 return buffergeometry;
15365 function dispose() {
15367 updateMap = new WeakMap();
15371 function onInstancedMeshDispose( event ) {
15373 const instancedMesh = event.target;
15375 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
15377 attributes.remove( instancedMesh.instanceMatrix );
15379 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
15392 function DataTexture2DArray( data = null, width = 1, height = 1, depth = 1 ) {
15394 Texture.call( this, null );
15396 this.image = { data, width, height, depth };
15398 this.magFilter = NearestFilter;
15399 this.minFilter = NearestFilter;
15401 this.wrapR = ClampToEdgeWrapping;
15403 this.generateMipmaps = false;
15404 this.flipY = false;
15406 this.needsUpdate = true;
15410 DataTexture2DArray.prototype = Object.create( Texture.prototype );
15411 DataTexture2DArray.prototype.constructor = DataTexture2DArray;
15412 DataTexture2DArray.prototype.isDataTexture2DArray = true;
15414 function DataTexture3D( data = null, width = 1, height = 1, depth = 1 ) {
15416 // We're going to add .setXXX() methods for setting properties later.
15417 // Users can still set in DataTexture3D directly.
15419 // const texture = new THREE.DataTexture3D( data, width, height, depth );
15420 // texture.anisotropy = 16;
15424 Texture.call( this, null );
15426 this.image = { data, width, height, depth };
15428 this.magFilter = NearestFilter;
15429 this.minFilter = NearestFilter;
15431 this.wrapR = ClampToEdgeWrapping;
15433 this.generateMipmaps = false;
15434 this.flipY = false;
15436 this.needsUpdate = true;
15441 DataTexture3D.prototype = Object.create( Texture.prototype );
15442 DataTexture3D.prototype.constructor = DataTexture3D;
15443 DataTexture3D.prototype.isDataTexture3D = true;
15446 * Uniforms of a program.
15447 * Those form a tree structure with a special top-level container for the root,
15448 * which you get by calling 'new WebGLUniforms( gl, program )'.
15451 * Properties of inner nodes including the top-level container:
15453 * .seq - array of nested uniforms
15454 * .map - nested uniforms by name
15457 * Methods of all nodes except the top-level container:
15459 * .setValue( gl, value, [textures] )
15461 * uploads a uniform value(s)
15462 * the 'textures' parameter is needed for sampler uniforms
15465 * Static methods of the top-level container (textures factorizations):
15467 * .upload( gl, seq, values, textures )
15469 * sets uniforms in 'seq' to 'values[id].value'
15471 * .seqWithValue( seq, values ) : filteredSeq
15473 * filters 'seq' entries with corresponding entry in values
15476 * Methods of the top-level container (textures factorizations):
15478 * .setValue( gl, name, value, textures )
15480 * sets uniform with name 'name' to 'value'
15482 * .setOptional( gl, obj, prop )
15484 * like .set for an optional property of the object
15488 const emptyTexture = new Texture();
15489 const emptyTexture2dArray = new DataTexture2DArray();
15490 const emptyTexture3d = new DataTexture3D();
15491 const emptyCubeTexture = new CubeTexture();
15493 // --- Utilities ---
15495 // Array Caches (provide typed arrays for temporary by size)
15497 const arrayCacheF32 = [];
15498 const arrayCacheI32 = [];
15500 // Float32Array caches used for uploading Matrix uniforms
15502 const mat4array = new Float32Array( 16 );
15503 const mat3array = new Float32Array( 9 );
15504 const mat2array = new Float32Array( 4 );
15506 // Flattening for arrays of vectors and matrices
15508 function flatten( array, nBlocks, blockSize ) {
15510 const firstElem = array[ 0 ];
15512 if ( firstElem <= 0 || firstElem > 0 ) return array;
15513 // unoptimized: ! isNaN( firstElem )
15514 // see http://jacksondunstan.com/articles/983
15516 const n = nBlocks * blockSize;
15517 let r = arrayCacheF32[ n ];
15519 if ( r === undefined ) {
15521 r = new Float32Array( n );
15522 arrayCacheF32[ n ] = r;
15526 if ( nBlocks !== 0 ) {
15528 firstElem.toArray( r, 0 );
15530 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
15532 offset += blockSize;
15533 array[ i ].toArray( r, offset );
15543 function arraysEqual( a, b ) {
15545 if ( a.length !== b.length ) return false;
15547 for ( let i = 0, l = a.length; i < l; i ++ ) {
15549 if ( a[ i ] !== b[ i ] ) return false;
15557 function copyArray( a, b ) {
15559 for ( let i = 0, l = b.length; i < l; i ++ ) {
15567 // Texture unit allocation
15569 function allocTexUnits( textures, n ) {
15571 let r = arrayCacheI32[ n ];
15573 if ( r === undefined ) {
15575 r = new Int32Array( n );
15576 arrayCacheI32[ n ] = r;
15580 for ( let i = 0; i !== n; ++ i ) {
15582 r[ i ] = textures.allocateTextureUnit();
15592 // Note: Defining these methods externally, because they come in a bunch
15593 // and this way their names minify.
15597 function setValueV1f( gl, v ) {
15599 const cache = this.cache;
15601 if ( cache[ 0 ] === v ) return;
15603 gl.uniform1f( this.addr, v );
15609 // Single float vector (from flat array or THREE.VectorN)
15611 function setValueV2f( gl, v ) {
15613 const cache = this.cache;
15615 if ( v.x !== undefined ) {
15617 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
15619 gl.uniform2f( this.addr, v.x, v.y );
15628 if ( arraysEqual( cache, v ) ) return;
15630 gl.uniform2fv( this.addr, v );
15632 copyArray( cache, v );
15638 function setValueV3f( gl, v ) {
15640 const cache = this.cache;
15642 if ( v.x !== undefined ) {
15644 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
15646 gl.uniform3f( this.addr, v.x, v.y, v.z );
15654 } else if ( v.r !== undefined ) {
15656 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
15658 gl.uniform3f( this.addr, v.r, v.g, v.b );
15668 if ( arraysEqual( cache, v ) ) return;
15670 gl.uniform3fv( this.addr, v );
15672 copyArray( cache, v );
15678 function setValueV4f( gl, v ) {
15680 const cache = this.cache;
15682 if ( v.x !== undefined ) {
15684 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
15686 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
15697 if ( arraysEqual( cache, v ) ) return;
15699 gl.uniform4fv( this.addr, v );
15701 copyArray( cache, v );
15707 // Single matrix (from flat array or MatrixN)
15709 function setValueM2( gl, v ) {
15711 const cache = this.cache;
15712 const elements = v.elements;
15714 if ( elements === undefined ) {
15716 if ( arraysEqual( cache, v ) ) return;
15718 gl.uniformMatrix2fv( this.addr, false, v );
15720 copyArray( cache, v );
15724 if ( arraysEqual( cache, elements ) ) return;
15726 mat2array.set( elements );
15728 gl.uniformMatrix2fv( this.addr, false, mat2array );
15730 copyArray( cache, elements );
15736 function setValueM3( gl, v ) {
15738 const cache = this.cache;
15739 const elements = v.elements;
15741 if ( elements === undefined ) {
15743 if ( arraysEqual( cache, v ) ) return;
15745 gl.uniformMatrix3fv( this.addr, false, v );
15747 copyArray( cache, v );
15751 if ( arraysEqual( cache, elements ) ) return;
15753 mat3array.set( elements );
15755 gl.uniformMatrix3fv( this.addr, false, mat3array );
15757 copyArray( cache, elements );
15763 function setValueM4( gl, v ) {
15765 const cache = this.cache;
15766 const elements = v.elements;
15768 if ( elements === undefined ) {
15770 if ( arraysEqual( cache, v ) ) return;
15772 gl.uniformMatrix4fv( this.addr, false, v );
15774 copyArray( cache, v );
15778 if ( arraysEqual( cache, elements ) ) return;
15780 mat4array.set( elements );
15782 gl.uniformMatrix4fv( this.addr, false, mat4array );
15784 copyArray( cache, elements );
15790 // Single texture (2D / Cube)
15792 function setValueT1( gl, v, textures ) {
15794 const cache = this.cache;
15795 const unit = textures.allocateTextureUnit();
15797 if ( cache[ 0 ] !== unit ) {
15799 gl.uniform1i( this.addr, unit );
15804 textures.safeSetTexture2D( v || emptyTexture, unit );
15808 function setValueT2DArray1( gl, v, textures ) {
15810 const cache = this.cache;
15811 const unit = textures.allocateTextureUnit();
15813 if ( cache[ 0 ] !== unit ) {
15815 gl.uniform1i( this.addr, unit );
15820 textures.setTexture2DArray( v || emptyTexture2dArray, unit );
15824 function setValueT3D1( gl, v, textures ) {
15826 const cache = this.cache;
15827 const unit = textures.allocateTextureUnit();
15829 if ( cache[ 0 ] !== unit ) {
15831 gl.uniform1i( this.addr, unit );
15836 textures.setTexture3D( v || emptyTexture3d, unit );
15840 function setValueT6( gl, v, textures ) {
15842 const cache = this.cache;
15843 const unit = textures.allocateTextureUnit();
15845 if ( cache[ 0 ] !== unit ) {
15847 gl.uniform1i( this.addr, unit );
15852 textures.safeSetTextureCube( v || emptyCubeTexture, unit );
15856 // Integer / Boolean vectors or arrays thereof (always flat arrays)
15858 function setValueV1i( gl, v ) {
15860 const cache = this.cache;
15862 if ( cache[ 0 ] === v ) return;
15864 gl.uniform1i( this.addr, v );
15870 function setValueV2i( gl, v ) {
15872 const cache = this.cache;
15874 if ( arraysEqual( cache, v ) ) return;
15876 gl.uniform2iv( this.addr, v );
15878 copyArray( cache, v );
15882 function setValueV3i( gl, v ) {
15884 const cache = this.cache;
15886 if ( arraysEqual( cache, v ) ) return;
15888 gl.uniform3iv( this.addr, v );
15890 copyArray( cache, v );
15894 function setValueV4i( gl, v ) {
15896 const cache = this.cache;
15898 if ( arraysEqual( cache, v ) ) return;
15900 gl.uniform4iv( this.addr, v );
15902 copyArray( cache, v );
15908 function setValueV1ui( gl, v ) {
15910 const cache = this.cache;
15912 if ( cache[ 0 ] === v ) return;
15914 gl.uniform1ui( this.addr, v );
15920 // Helper to pick the right setter for the singular case
15922 function getSingularSetter( type ) {
15926 case 0x1406: return setValueV1f; // FLOAT
15927 case 0x8b50: return setValueV2f; // _VEC2
15928 case 0x8b51: return setValueV3f; // _VEC3
15929 case 0x8b52: return setValueV4f; // _VEC4
15931 case 0x8b5a: return setValueM2; // _MAT2
15932 case 0x8b5b: return setValueM3; // _MAT3
15933 case 0x8b5c: return setValueM4; // _MAT4
15935 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
15936 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
15937 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
15938 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
15940 case 0x1405: return setValueV1ui; // UINT
15942 case 0x8b5e: // SAMPLER_2D
15943 case 0x8d66: // SAMPLER_EXTERNAL_OES
15944 case 0x8dca: // INT_SAMPLER_2D
15945 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
15946 case 0x8b62: // SAMPLER_2D_SHADOW
15949 case 0x8b5f: // SAMPLER_3D
15950 case 0x8dcb: // INT_SAMPLER_3D
15951 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
15952 return setValueT3D1;
15954 case 0x8b60: // SAMPLER_CUBE
15955 case 0x8dcc: // INT_SAMPLER_CUBE
15956 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
15957 case 0x8dc5: // SAMPLER_CUBE_SHADOW
15960 case 0x8dc1: // SAMPLER_2D_ARRAY
15961 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
15962 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
15963 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
15964 return setValueT2DArray1;
15970 // Array of scalars
15971 function setValueV1fArray( gl, v ) {
15973 gl.uniform1fv( this.addr, v );
15977 // Integer / Boolean vectors or arrays thereof (always flat arrays)
15978 function setValueV1iArray( gl, v ) {
15980 gl.uniform1iv( this.addr, v );
15984 function setValueV2iArray( gl, v ) {
15986 gl.uniform2iv( this.addr, v );
15990 function setValueV3iArray( gl, v ) {
15992 gl.uniform3iv( this.addr, v );
15996 function setValueV4iArray( gl, v ) {
15998 gl.uniform4iv( this.addr, v );
16003 // Array of vectors (flat or from THREE classes)
16005 function setValueV2fArray( gl, v ) {
16007 const data = flatten( v, this.size, 2 );
16009 gl.uniform2fv( this.addr, data );
16013 function setValueV3fArray( gl, v ) {
16015 const data = flatten( v, this.size, 3 );
16017 gl.uniform3fv( this.addr, data );
16021 function setValueV4fArray( gl, v ) {
16023 const data = flatten( v, this.size, 4 );
16025 gl.uniform4fv( this.addr, data );
16029 // Array of matrices (flat or from THREE clases)
16031 function setValueM2Array( gl, v ) {
16033 const data = flatten( v, this.size, 4 );
16035 gl.uniformMatrix2fv( this.addr, false, data );
16039 function setValueM3Array( gl, v ) {
16041 const data = flatten( v, this.size, 9 );
16043 gl.uniformMatrix3fv( this.addr, false, data );
16047 function setValueM4Array( gl, v ) {
16049 const data = flatten( v, this.size, 16 );
16051 gl.uniformMatrix4fv( this.addr, false, data );
16055 // Array of textures (2D / Cube)
16057 function setValueT1Array( gl, v, textures ) {
16059 const n = v.length;
16061 const units = allocTexUnits( textures, n );
16063 gl.uniform1iv( this.addr, units );
16065 for ( let i = 0; i !== n; ++ i ) {
16067 textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] );
16073 function setValueT6Array( gl, v, textures ) {
16075 const n = v.length;
16077 const units = allocTexUnits( textures, n );
16079 gl.uniform1iv( this.addr, units );
16081 for ( let i = 0; i !== n; ++ i ) {
16083 textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
16089 // Helper to pick the right setter for a pure (bottom-level) array
16091 function getPureArraySetter( type ) {
16095 case 0x1406: return setValueV1fArray; // FLOAT
16096 case 0x8b50: return setValueV2fArray; // _VEC2
16097 case 0x8b51: return setValueV3fArray; // _VEC3
16098 case 0x8b52: return setValueV4fArray; // _VEC4
16100 case 0x8b5a: return setValueM2Array; // _MAT2
16101 case 0x8b5b: return setValueM3Array; // _MAT3
16102 case 0x8b5c: return setValueM4Array; // _MAT4
16104 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
16105 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
16106 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
16107 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
16109 case 0x8b5e: // SAMPLER_2D
16110 case 0x8d66: // SAMPLER_EXTERNAL_OES
16111 case 0x8dca: // INT_SAMPLER_2D
16112 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
16113 case 0x8b62: // SAMPLER_2D_SHADOW
16114 return setValueT1Array;
16116 case 0x8b60: // SAMPLER_CUBE
16117 case 0x8dcc: // INT_SAMPLER_CUBE
16118 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
16119 case 0x8dc5: // SAMPLER_CUBE_SHADOW
16120 return setValueT6Array;
16126 // --- Uniform Classes ---
16128 function SingleUniform( id, activeInfo, addr ) {
16133 this.setValue = getSingularSetter( activeInfo.type );
16135 // this.path = activeInfo.name; // DEBUG
16139 function PureArrayUniform( id, activeInfo, addr ) {
16144 this.size = activeInfo.size;
16145 this.setValue = getPureArraySetter( activeInfo.type );
16147 // this.path = activeInfo.name; // DEBUG
16151 PureArrayUniform.prototype.updateCache = function ( data ) {
16153 const cache = this.cache;
16155 if ( data instanceof Float32Array && cache.length !== data.length ) {
16157 this.cache = new Float32Array( data.length );
16161 copyArray( cache, data );
16165 function StructuredUniform( id ) {
16174 StructuredUniform.prototype.setValue = function ( gl, value, textures ) {
16176 const seq = this.seq;
16178 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16180 const u = seq[ i ];
16181 u.setValue( gl, value[ u.id ], textures );
16187 // --- Top-level ---
16189 // Parser - builds up the property tree from the path strings
16191 const RePathPart = /(\w+)(\])?(\[|\.)?/g;
16194 // - the identifier (member name or array index)
16195 // - followed by an optional right bracket (found when array index)
16196 // - followed by an optional left bracket or dot (type of subscript)
16198 // Note: These portions can be read in a non-overlapping fashion and
16199 // allow straightforward parsing of the hierarchy that WebGL encodes
16200 // in the uniform names.
16202 function addUniform( container, uniformObject ) {
16204 container.seq.push( uniformObject );
16205 container.map[ uniformObject.id ] = uniformObject;
16209 function parseUniform( activeInfo, addr, container ) {
16211 const path = activeInfo.name,
16212 pathLength = path.length;
16214 // reset RegExp object, because of the early exit of a previous run
16215 RePathPart.lastIndex = 0;
16219 const match = RePathPart.exec( path ),
16220 matchEnd = RePathPart.lastIndex;
16222 let id = match[ 1 ];
16223 const idIsIndex = match[ 2 ] === ']',
16224 subscript = match[ 3 ];
16226 if ( idIsIndex ) id = id | 0; // convert to integer
16228 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
16230 // bare name or "pure" bottom-level array "[0]" suffix
16232 addUniform( container, subscript === undefined ?
16233 new SingleUniform( id, activeInfo, addr ) :
16234 new PureArrayUniform( id, activeInfo, addr ) );
16240 // step into inner node / create it in case it doesn't exist
16242 const map = container.map;
16243 let next = map[ id ];
16245 if ( next === undefined ) {
16247 next = new StructuredUniform( id );
16248 addUniform( container, next );
16262 function WebGLUniforms( gl, program ) {
16267 const n = gl.getProgramParameter( program, 35718 );
16269 for ( let i = 0; i < n; ++ i ) {
16271 const info = gl.getActiveUniform( program, i ),
16272 addr = gl.getUniformLocation( program, info.name );
16274 parseUniform( info, addr, this );
16280 WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
16282 const u = this.map[ name ];
16284 if ( u !== undefined ) u.setValue( gl, value, textures );
16288 WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
16290 const v = object[ name ];
16292 if ( v !== undefined ) this.setValue( gl, name, v );
16297 // Static interface
16299 WebGLUniforms.upload = function ( gl, seq, values, textures ) {
16301 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16303 const u = seq[ i ],
16304 v = values[ u.id ];
16306 if ( v.needsUpdate !== false ) {
16308 // note: always updating when .needsUpdate is undefined
16309 u.setValue( gl, v.value, textures );
16317 WebGLUniforms.seqWithValue = function ( seq, values ) {
16321 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16323 const u = seq[ i ];
16324 if ( u.id in values ) r.push( u );
16332 function WebGLShader( gl, type, string ) {
16334 const shader = gl.createShader( type );
16336 gl.shaderSource( shader, string );
16337 gl.compileShader( shader );
16343 let programIdCount = 0;
16345 function addLineNumbers( string ) {
16347 const lines = string.split( '\n' );
16349 for ( let i = 0; i < lines.length; i ++ ) {
16351 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
16355 return lines.join( '\n' );
16359 function getEncodingComponents( encoding ) {
16361 switch ( encoding ) {
16363 case LinearEncoding:
16364 return [ 'Linear', '( value )' ];
16366 return [ 'sRGB', '( value )' ];
16368 return [ 'RGBE', '( value )' ];
16369 case RGBM7Encoding:
16370 return [ 'RGBM', '( value, 7.0 )' ];
16371 case RGBM16Encoding:
16372 return [ 'RGBM', '( value, 16.0 )' ];
16374 return [ 'RGBD', '( value, 256.0 )' ];
16375 case GammaEncoding:
16376 return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
16377 case LogLuvEncoding:
16378 return [ 'LogLuv', '( value )' ];
16380 console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding );
16381 return [ 'Linear', '( value )' ];
16387 function getShaderErrors( gl, shader, type ) {
16389 const status = gl.getShaderParameter( shader, 35713 );
16390 const log = gl.getShaderInfoLog( shader ).trim();
16392 if ( status && log === '' ) return '';
16394 // --enable-privileged-webgl-extension
16395 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
16397 const source = gl.getShaderSource( shader );
16399 return 'THREE.WebGLShader: gl.getShaderInfoLog() ' + type + '\n' + log + addLineNumbers( source );
16403 function getTexelDecodingFunction( functionName, encoding ) {
16405 const components = getEncodingComponents( encoding );
16406 return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
16410 function getTexelEncodingFunction( functionName, encoding ) {
16412 const components = getEncodingComponents( encoding );
16413 return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
16417 function getToneMappingFunction( functionName, toneMapping ) {
16419 let toneMappingName;
16421 switch ( toneMapping ) {
16423 case LinearToneMapping:
16424 toneMappingName = 'Linear';
16427 case ReinhardToneMapping:
16428 toneMappingName = 'Reinhard';
16431 case CineonToneMapping:
16432 toneMappingName = 'OptimizedCineon';
16435 case ACESFilmicToneMapping:
16436 toneMappingName = 'ACESFilmic';
16439 case CustomToneMapping:
16440 toneMappingName = 'Custom';
16444 console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
16445 toneMappingName = 'Linear';
16449 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
16453 function generateExtensions( parameters ) {
16456 ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
16457 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
16458 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
16459 ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
16462 return chunks.filter( filterEmptyLine ).join( '\n' );
16466 function generateDefines( defines ) {
16470 for ( const name in defines ) {
16472 const value = defines[ name ];
16474 if ( value === false ) continue;
16476 chunks.push( '#define ' + name + ' ' + value );
16480 return chunks.join( '\n' );
16484 function fetchAttributeLocations( gl, program ) {
16486 const attributes = {};
16488 const n = gl.getProgramParameter( program, 35721 );
16490 for ( let i = 0; i < n; i ++ ) {
16492 const info = gl.getActiveAttrib( program, i );
16493 const name = info.name;
16495 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
16497 attributes[ name ] = gl.getAttribLocation( program, name );
16505 function filterEmptyLine( string ) {
16507 return string !== '';
16511 function replaceLightNums( string, parameters ) {
16514 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
16515 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
16516 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
16517 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
16518 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
16519 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
16520 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
16521 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
16525 function replaceClippingPlaneNums( string, parameters ) {
16528 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
16529 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
16533 // Resolve Includes
16535 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
16537 function resolveIncludes( string ) {
16539 return string.replace( includePattern, includeReplacer );
16543 function includeReplacer( match, include ) {
16545 const string = ShaderChunk[ include ];
16547 if ( string === undefined ) {
16549 throw new Error( 'Can not resolve #include <' + include + '>' );
16553 return resolveIncludes( string );
16559 const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
16560 const 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;
16562 function unrollLoops( string ) {
16565 .replace( unrollLoopPattern, loopReplacer )
16566 .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer );
16570 function deprecatedLoopReplacer( match, start, end, snippet ) {
16572 console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' );
16573 return loopReplacer( match, start, end, snippet );
16577 function loopReplacer( match, start, end, snippet ) {
16581 for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
16584 .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
16585 .replace( /UNROLLED_LOOP_INDEX/g, i );
16595 function generatePrecision( parameters ) {
16597 let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
16599 if ( parameters.precision === 'highp' ) {
16601 precisionstring += '\n#define HIGH_PRECISION';
16603 } else if ( parameters.precision === 'mediump' ) {
16605 precisionstring += '\n#define MEDIUM_PRECISION';
16607 } else if ( parameters.precision === 'lowp' ) {
16609 precisionstring += '\n#define LOW_PRECISION';
16613 return precisionstring;
16617 function generateShadowMapTypeDefine( parameters ) {
16619 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
16621 if ( parameters.shadowMapType === PCFShadowMap ) {
16623 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
16625 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
16627 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
16629 } else if ( parameters.shadowMapType === VSMShadowMap ) {
16631 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
16635 return shadowMapTypeDefine;
16639 function generateEnvMapTypeDefine( parameters ) {
16641 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
16643 if ( parameters.envMap ) {
16645 switch ( parameters.envMapMode ) {
16647 case CubeReflectionMapping:
16648 case CubeRefractionMapping:
16649 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
16652 case CubeUVReflectionMapping:
16653 case CubeUVRefractionMapping:
16654 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
16661 return envMapTypeDefine;
16665 function generateEnvMapModeDefine( parameters ) {
16667 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
16669 if ( parameters.envMap ) {
16671 switch ( parameters.envMapMode ) {
16673 case CubeRefractionMapping:
16674 case CubeUVRefractionMapping:
16676 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
16683 return envMapModeDefine;
16687 function generateEnvMapBlendingDefine( parameters ) {
16689 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
16691 if ( parameters.envMap ) {
16693 switch ( parameters.combine ) {
16695 case MultiplyOperation:
16696 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
16700 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
16704 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
16711 return envMapBlendingDefine;
16715 function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
16717 const gl = renderer.getContext();
16719 const defines = parameters.defines;
16721 let vertexShader = parameters.vertexShader;
16722 let fragmentShader = parameters.fragmentShader;
16724 const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
16725 const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
16726 const envMapModeDefine = generateEnvMapModeDefine( parameters );
16727 const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
16730 const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
16732 const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
16734 const customDefines = generateDefines( defines );
16736 const program = gl.createProgram();
16738 let prefixVertex, prefixFragment;
16739 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
16741 if ( parameters.isRawShaderMaterial ) {
16747 ].filter( filterEmptyLine ).join( '\n' );
16749 if ( prefixVertex.length > 0 ) {
16751 prefixVertex += '\n';
16760 ].filter( filterEmptyLine ).join( '\n' );
16762 if ( prefixFragment.length > 0 ) {
16764 prefixFragment += '\n';
16772 generatePrecision( parameters ),
16774 '#define SHADER_NAME ' + parameters.shaderName,
16778 parameters.instancing ? '#define USE_INSTANCING' : '',
16779 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
16781 parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
16783 '#define GAMMA_FACTOR ' + gammaFactorDefine,
16785 '#define MAX_BONES ' + parameters.maxBones,
16786 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
16787 ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
16789 parameters.map ? '#define USE_MAP' : '',
16790 parameters.envMap ? '#define USE_ENVMAP' : '',
16791 parameters.envMap ? '#define ' + envMapModeDefine : '',
16792 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
16793 parameters.aoMap ? '#define USE_AOMAP' : '',
16794 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
16795 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
16796 parameters.normalMap ? '#define USE_NORMALMAP' : '',
16797 ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
16798 ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
16800 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
16801 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
16802 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
16803 parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
16804 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
16805 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
16806 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
16807 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
16808 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
16810 parameters.vertexTangents ? '#define USE_TANGENT' : '',
16811 parameters.vertexColors ? '#define USE_COLOR' : '',
16812 parameters.vertexUvs ? '#define USE_UV' : '',
16813 parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
16815 parameters.flatShading ? '#define FLAT_SHADED' : '',
16817 parameters.skinning ? '#define USE_SKINNING' : '',
16818 parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
16820 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
16821 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
16822 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
16823 parameters.flipSided ? '#define FLIP_SIDED' : '',
16825 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
16826 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
16828 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
16830 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
16831 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
16833 'uniform mat4 modelMatrix;',
16834 'uniform mat4 modelViewMatrix;',
16835 'uniform mat4 projectionMatrix;',
16836 'uniform mat4 viewMatrix;',
16837 'uniform mat3 normalMatrix;',
16838 'uniform vec3 cameraPosition;',
16839 'uniform bool isOrthographic;',
16841 '#ifdef USE_INSTANCING',
16843 ' attribute mat4 instanceMatrix;',
16847 '#ifdef USE_INSTANCING_COLOR',
16849 ' attribute vec3 instanceColor;',
16853 'attribute vec3 position;',
16854 'attribute vec3 normal;',
16855 'attribute vec2 uv;',
16857 '#ifdef USE_TANGENT',
16859 ' attribute vec4 tangent;',
16863 '#ifdef USE_COLOR',
16865 ' attribute vec3 color;',
16869 '#ifdef USE_MORPHTARGETS',
16871 ' attribute vec3 morphTarget0;',
16872 ' attribute vec3 morphTarget1;',
16873 ' attribute vec3 morphTarget2;',
16874 ' attribute vec3 morphTarget3;',
16876 ' #ifdef USE_MORPHNORMALS',
16878 ' attribute vec3 morphNormal0;',
16879 ' attribute vec3 morphNormal1;',
16880 ' attribute vec3 morphNormal2;',
16881 ' attribute vec3 morphNormal3;',
16885 ' attribute vec3 morphTarget4;',
16886 ' attribute vec3 morphTarget5;',
16887 ' attribute vec3 morphTarget6;',
16888 ' attribute vec3 morphTarget7;',
16894 '#ifdef USE_SKINNING',
16896 ' attribute vec4 skinIndex;',
16897 ' attribute vec4 skinWeight;',
16903 ].filter( filterEmptyLine ).join( '\n' );
16909 generatePrecision( parameters ),
16911 '#define SHADER_NAME ' + parameters.shaderName,
16915 parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
16917 '#define GAMMA_FACTOR ' + gammaFactorDefine,
16919 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
16920 ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
16922 parameters.map ? '#define USE_MAP' : '',
16923 parameters.matcap ? '#define USE_MATCAP' : '',
16924 parameters.envMap ? '#define USE_ENVMAP' : '',
16925 parameters.envMap ? '#define ' + envMapTypeDefine : '',
16926 parameters.envMap ? '#define ' + envMapModeDefine : '',
16927 parameters.envMap ? '#define ' + envMapBlendingDefine : '',
16928 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
16929 parameters.aoMap ? '#define USE_AOMAP' : '',
16930 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
16931 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
16932 parameters.normalMap ? '#define USE_NORMALMAP' : '',
16933 ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
16934 ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
16935 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
16936 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
16937 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
16938 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
16939 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
16940 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
16941 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
16943 parameters.sheen ? '#define USE_SHEEN' : '',
16944 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
16946 parameters.vertexTangents ? '#define USE_TANGENT' : '',
16947 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
16948 parameters.vertexUvs ? '#define USE_UV' : '',
16949 parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
16951 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
16953 parameters.flatShading ? '#define FLAT_SHADED' : '',
16955 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
16956 parameters.flipSided ? '#define FLIP_SIDED' : '',
16958 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
16959 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
16961 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
16963 parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
16965 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
16966 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
16968 ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '',
16970 'uniform mat4 viewMatrix;',
16971 'uniform vec3 cameraPosition;',
16972 'uniform bool isOrthographic;',
16974 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
16975 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
16976 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
16978 parameters.dithering ? '#define DITHERING' : '',
16980 ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
16981 parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
16982 parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
16983 parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
16984 parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
16985 parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
16986 getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
16988 parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
16992 ].filter( filterEmptyLine ).join( '\n' );
16996 vertexShader = resolveIncludes( vertexShader );
16997 vertexShader = replaceLightNums( vertexShader, parameters );
16998 vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
17000 fragmentShader = resolveIncludes( fragmentShader );
17001 fragmentShader = replaceLightNums( fragmentShader, parameters );
17002 fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
17004 vertexShader = unrollLoops( vertexShader );
17005 fragmentShader = unrollLoops( fragmentShader );
17007 if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
17009 // GLSL 3.0 conversion for built-in materials and ShaderMaterial
17011 versionString = '#version 300 es\n';
17014 '#define attribute in',
17015 '#define varying out',
17016 '#define texture2D texture'
17017 ].join( '\n' ) + '\n' + prefixVertex;
17020 '#define varying in',
17021 ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;',
17022 ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
17023 '#define gl_FragDepthEXT gl_FragDepth',
17024 '#define texture2D texture',
17025 '#define textureCube texture',
17026 '#define texture2DProj textureProj',
17027 '#define texture2DLodEXT textureLod',
17028 '#define texture2DProjLodEXT textureProjLod',
17029 '#define textureCubeLodEXT textureLod',
17030 '#define texture2DGradEXT textureGrad',
17031 '#define texture2DProjGradEXT textureProjGrad',
17032 '#define textureCubeGradEXT textureGrad'
17033 ].join( '\n' ) + '\n' + prefixFragment;
17037 const vertexGlsl = versionString + prefixVertex + vertexShader;
17038 const fragmentGlsl = versionString + prefixFragment + fragmentShader;
17040 // console.log( '*VERTEX*', vertexGlsl );
17041 // console.log( '*FRAGMENT*', fragmentGlsl );
17043 const glVertexShader = WebGLShader( gl, 35633, vertexGlsl );
17044 const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl );
17046 gl.attachShader( program, glVertexShader );
17047 gl.attachShader( program, glFragmentShader );
17049 // Force a particular attribute to index 0.
17051 if ( parameters.index0AttributeName !== undefined ) {
17053 gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
17055 } else if ( parameters.morphTargets === true ) {
17057 // programs with morphTargets displace position out of attribute 0
17058 gl.bindAttribLocation( program, 0, 'position' );
17062 gl.linkProgram( program );
17064 // check for link errors
17065 if ( renderer.debug.checkShaderErrors ) {
17067 const programLog = gl.getProgramInfoLog( program ).trim();
17068 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
17069 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
17071 let runnable = true;
17072 let haveDiagnostics = true;
17074 if ( gl.getProgramParameter( program, 35714 ) === false ) {
17078 const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
17079 const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
17081 console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors );
17083 } else if ( programLog !== '' ) {
17085 console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
17087 } else if ( vertexLog === '' || fragmentLog === '' ) {
17089 haveDiagnostics = false;
17093 if ( haveDiagnostics ) {
17095 this.diagnostics = {
17097 runnable: runnable,
17099 programLog: programLog,
17104 prefix: prefixVertex
17111 prefix: prefixFragment
17123 // Crashes in iOS9 and iOS10. #18402
17124 // gl.detachShader( program, glVertexShader );
17125 // gl.detachShader( program, glFragmentShader );
17127 gl.deleteShader( glVertexShader );
17128 gl.deleteShader( glFragmentShader );
17130 // set up caching for uniform locations
17132 let cachedUniforms;
17134 this.getUniforms = function () {
17136 if ( cachedUniforms === undefined ) {
17138 cachedUniforms = new WebGLUniforms( gl, program );
17142 return cachedUniforms;
17146 // set up caching for attribute locations
17148 let cachedAttributes;
17150 this.getAttributes = function () {
17152 if ( cachedAttributes === undefined ) {
17154 cachedAttributes = fetchAttributeLocations( gl, program );
17158 return cachedAttributes;
17164 this.destroy = function () {
17166 bindingStates.releaseStatesOfProgram( this );
17168 gl.deleteProgram( program );
17169 this.program = undefined;
17175 this.name = parameters.shaderName;
17176 this.id = programIdCount ++;
17177 this.cacheKey = cacheKey;
17178 this.usedTimes = 1;
17179 this.program = program;
17180 this.vertexShader = glVertexShader;
17181 this.fragmentShader = glFragmentShader;
17187 function WebGLPrograms( renderer, cubemaps, extensions, capabilities, bindingStates, clipping ) {
17189 const programs = [];
17191 const isWebGL2 = capabilities.isWebGL2;
17192 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
17193 const floatVertexTextures = capabilities.floatVertexTextures;
17194 const maxVertexUniforms = capabilities.maxVertexUniforms;
17195 const vertexTextures = capabilities.vertexTextures;
17197 let precision = capabilities.precision;
17199 const shaderIDs = {
17200 MeshDepthMaterial: 'depth',
17201 MeshDistanceMaterial: 'distanceRGBA',
17202 MeshNormalMaterial: 'normal',
17203 MeshBasicMaterial: 'basic',
17204 MeshLambertMaterial: 'lambert',
17205 MeshPhongMaterial: 'phong',
17206 MeshToonMaterial: 'toon',
17207 MeshStandardMaterial: 'physical',
17208 MeshPhysicalMaterial: 'physical',
17209 MeshMatcapMaterial: 'matcap',
17210 LineBasicMaterial: 'basic',
17211 LineDashedMaterial: 'dashed',
17212 PointsMaterial: 'points',
17213 ShadowMaterial: 'shadow',
17214 SpriteMaterial: 'sprite'
17217 const parameterNames = [
17218 'precision', 'isWebGL2', 'supportsVertexTextures', 'outputEncoding', 'instancing', 'instancingColor',
17219 'map', 'mapEncoding', 'matcap', 'matcapEncoding', 'envMap', 'envMapMode', 'envMapEncoding', 'envMapCubeUV',
17220 'lightMap', 'lightMapEncoding', 'aoMap', 'emissiveMap', 'emissiveMapEncoding', 'bumpMap', 'normalMap', 'objectSpaceNormalMap', 'tangentSpaceNormalMap', 'clearcoatMap', 'clearcoatRoughnessMap', 'clearcoatNormalMap', 'displacementMap', 'specularMap',
17221 'roughnessMap', 'metalnessMap', 'gradientMap',
17222 'alphaMap', 'combine', 'vertexColors', 'vertexTangents', 'vertexUvs', 'uvsVertexOnly', 'fog', 'useFog', 'fogExp2',
17223 'flatShading', 'sizeAttenuation', 'logarithmicDepthBuffer', 'skinning',
17224 'maxBones', 'useVertexTexture', 'morphTargets', 'morphNormals',
17225 'maxMorphTargets', 'maxMorphNormals', 'premultipliedAlpha',
17226 'numDirLights', 'numPointLights', 'numSpotLights', 'numHemiLights', 'numRectAreaLights',
17227 'numDirLightShadows', 'numPointLightShadows', 'numSpotLightShadows',
17228 'shadowMapEnabled', 'shadowMapType', 'toneMapping', 'physicallyCorrectLights',
17229 'alphaTest', 'doubleSided', 'flipSided', 'numClippingPlanes', 'numClipIntersection', 'depthPacking', 'dithering',
17230 'sheen', 'transmissionMap'
17233 function getMaxBones( object ) {
17235 const skeleton = object.skeleton;
17236 const bones = skeleton.bones;
17238 if ( floatVertexTextures ) {
17244 // default for when object is not specified
17245 // ( for example when prebuilding shader to be used with multiple objects )
17247 // - leave some extra space for other uniforms
17248 // - limit here is ANGLE's 254 max uniform vectors
17249 // (up to 54 should be safe)
17251 const nVertexUniforms = maxVertexUniforms;
17252 const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
17254 const maxBones = Math.min( nVertexMatrices, bones.length );
17256 if ( maxBones < bones.length ) {
17258 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
17269 function getTextureEncodingFromMap( map ) {
17273 if ( map && map.isTexture ) {
17275 encoding = map.encoding;
17277 } else if ( map && map.isWebGLRenderTarget ) {
17279 console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' );
17280 encoding = map.texture.encoding;
17284 encoding = LinearEncoding;
17292 function getParameters( material, lights, shadows, scene, object ) {
17294 const fog = scene.fog;
17295 const environment = material.isMeshStandardMaterial ? scene.environment : null;
17297 const envMap = cubemaps.get( material.envMap || environment );
17299 const shaderID = shaderIDs[ material.type ];
17301 // heuristics to create shader parameters according to lights in the scene
17302 // (not to blow over maxLights budget)
17304 const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0;
17306 if ( material.precision !== null ) {
17308 precision = capabilities.getMaxPrecision( material.precision );
17310 if ( precision !== material.precision ) {
17312 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
17318 let vertexShader, fragmentShader;
17322 const shader = ShaderLib[ shaderID ];
17324 vertexShader = shader.vertexShader;
17325 fragmentShader = shader.fragmentShader;
17329 vertexShader = material.vertexShader;
17330 fragmentShader = material.fragmentShader;
17334 const currentRenderTarget = renderer.getRenderTarget();
17336 const parameters = {
17338 isWebGL2: isWebGL2,
17340 shaderID: shaderID,
17341 shaderName: material.type,
17343 vertexShader: vertexShader,
17344 fragmentShader: fragmentShader,
17345 defines: material.defines,
17347 isRawShaderMaterial: material.isRawShaderMaterial === true,
17348 glslVersion: material.glslVersion,
17350 precision: precision,
17352 instancing: object.isInstancedMesh === true,
17353 instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
17355 supportsVertexTextures: vertexTextures,
17356 outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
17357 map: !! material.map,
17358 mapEncoding: getTextureEncodingFromMap( material.map ),
17359 matcap: !! material.matcap,
17360 matcapEncoding: getTextureEncodingFromMap( material.matcap ),
17362 envMapMode: envMap && envMap.mapping,
17363 envMapEncoding: getTextureEncodingFromMap( envMap ),
17364 envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
17365 lightMap: !! material.lightMap,
17366 lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
17367 aoMap: !! material.aoMap,
17368 emissiveMap: !! material.emissiveMap,
17369 emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
17370 bumpMap: !! material.bumpMap,
17371 normalMap: !! material.normalMap,
17372 objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
17373 tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
17374 clearcoatMap: !! material.clearcoatMap,
17375 clearcoatRoughnessMap: !! material.clearcoatRoughnessMap,
17376 clearcoatNormalMap: !! material.clearcoatNormalMap,
17377 displacementMap: !! material.displacementMap,
17378 roughnessMap: !! material.roughnessMap,
17379 metalnessMap: !! material.metalnessMap,
17380 specularMap: !! material.specularMap,
17381 alphaMap: !! material.alphaMap,
17383 gradientMap: !! material.gradientMap,
17385 sheen: !! material.sheen,
17387 transmissionMap: !! material.transmissionMap,
17389 combine: material.combine,
17391 vertexTangents: ( material.normalMap && material.vertexTangents ),
17392 vertexColors: material.vertexColors,
17393 vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap,
17394 uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.transmissionMap ) && !! material.displacementMap,
17397 useFog: material.fog,
17398 fogExp2: ( fog && fog.isFogExp2 ),
17400 flatShading: material.flatShading,
17402 sizeAttenuation: material.sizeAttenuation,
17403 logarithmicDepthBuffer: logarithmicDepthBuffer,
17405 skinning: material.skinning && maxBones > 0,
17406 maxBones: maxBones,
17407 useVertexTexture: floatVertexTextures,
17409 morphTargets: material.morphTargets,
17410 morphNormals: material.morphNormals,
17411 maxMorphTargets: renderer.maxMorphTargets,
17412 maxMorphNormals: renderer.maxMorphNormals,
17414 numDirLights: lights.directional.length,
17415 numPointLights: lights.point.length,
17416 numSpotLights: lights.spot.length,
17417 numRectAreaLights: lights.rectArea.length,
17418 numHemiLights: lights.hemi.length,
17420 numDirLightShadows: lights.directionalShadowMap.length,
17421 numPointLightShadows: lights.pointShadowMap.length,
17422 numSpotLightShadows: lights.spotShadowMap.length,
17424 numClippingPlanes: clipping.numPlanes,
17425 numClipIntersection: clipping.numIntersection,
17427 dithering: material.dithering,
17429 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
17430 shadowMapType: renderer.shadowMap.type,
17432 toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
17433 physicallyCorrectLights: renderer.physicallyCorrectLights,
17435 premultipliedAlpha: material.premultipliedAlpha,
17437 alphaTest: material.alphaTest,
17438 doubleSided: material.side === DoubleSide,
17439 flipSided: material.side === BackSide,
17441 depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false,
17443 index0AttributeName: material.index0AttributeName,
17445 extensionDerivatives: material.extensions && material.extensions.derivatives,
17446 extensionFragDepth: material.extensions && material.extensions.fragDepth,
17447 extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
17448 extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
17450 rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
17451 rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
17452 rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
17454 customProgramCacheKey: material.customProgramCacheKey()
17462 function getProgramCacheKey( parameters ) {
17466 if ( parameters.shaderID ) {
17468 array.push( parameters.shaderID );
17472 array.push( parameters.fragmentShader );
17473 array.push( parameters.vertexShader );
17477 if ( parameters.defines !== undefined ) {
17479 for ( const name in parameters.defines ) {
17481 array.push( name );
17482 array.push( parameters.defines[ name ] );
17488 if ( parameters.isRawShaderMaterial === false ) {
17490 for ( let i = 0; i < parameterNames.length; i ++ ) {
17492 array.push( parameters[ parameterNames[ i ] ] );
17496 array.push( renderer.outputEncoding );
17497 array.push( renderer.gammaFactor );
17501 array.push( parameters.customProgramCacheKey );
17503 return array.join();
17507 function getUniforms( material ) {
17509 const shaderID = shaderIDs[ material.type ];
17514 const shader = ShaderLib[ shaderID ];
17515 uniforms = UniformsUtils.clone( shader.uniforms );
17519 uniforms = material.uniforms;
17527 function acquireProgram( parameters, cacheKey ) {
17531 // Check if code has been already compiled
17532 for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
17534 const preexistingProgram = programs[ p ];
17536 if ( preexistingProgram.cacheKey === cacheKey ) {
17538 program = preexistingProgram;
17539 ++ program.usedTimes;
17547 if ( program === undefined ) {
17549 program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
17550 programs.push( program );
17558 function releaseProgram( program ) {
17560 if ( -- program.usedTimes === 0 ) {
17562 // Remove from unordered set
17563 const i = programs.indexOf( program );
17564 programs[ i ] = programs[ programs.length - 1 ];
17567 // Free WebGL resources
17575 getParameters: getParameters,
17576 getProgramCacheKey: getProgramCacheKey,
17577 getUniforms: getUniforms,
17578 acquireProgram: acquireProgram,
17579 releaseProgram: releaseProgram,
17580 // Exposed for resource monitoring & error feedback via renderer.info:
17586 function WebGLProperties() {
17588 let properties = new WeakMap();
17590 function get( object ) {
17592 let map = properties.get( object );
17594 if ( map === undefined ) {
17597 properties.set( object, map );
17605 function remove( object ) {
17607 properties.delete( object );
17611 function update( object, key, value ) {
17613 properties.get( object )[ key ] = value;
17617 function dispose() {
17619 properties = new WeakMap();
17632 function painterSortStable( a, b ) {
17634 if ( a.groupOrder !== b.groupOrder ) {
17636 return a.groupOrder - b.groupOrder;
17638 } else if ( a.renderOrder !== b.renderOrder ) {
17640 return a.renderOrder - b.renderOrder;
17642 } else if ( a.program !== b.program ) {
17644 return a.program.id - b.program.id;
17646 } else if ( a.material.id !== b.material.id ) {
17648 return a.material.id - b.material.id;
17650 } else if ( a.z !== b.z ) {
17656 return a.id - b.id;
17662 function reversePainterSortStable( a, b ) {
17664 if ( a.groupOrder !== b.groupOrder ) {
17666 return a.groupOrder - b.groupOrder;
17668 } else if ( a.renderOrder !== b.renderOrder ) {
17670 return a.renderOrder - b.renderOrder;
17672 } else if ( a.z !== b.z ) {
17678 return a.id - b.id;
17685 function WebGLRenderList( properties ) {
17687 const renderItems = [];
17688 let renderItemsIndex = 0;
17691 const transparent = [];
17693 const defaultProgram = { id: - 1 };
17697 renderItemsIndex = 0;
17700 transparent.length = 0;
17704 function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
17706 let renderItem = renderItems[ renderItemsIndex ];
17707 const materialProperties = properties.get( material );
17709 if ( renderItem === undefined ) {
17714 geometry: geometry,
17715 material: material,
17716 program: materialProperties.program || defaultProgram,
17717 groupOrder: groupOrder,
17718 renderOrder: object.renderOrder,
17723 renderItems[ renderItemsIndex ] = renderItem;
17727 renderItem.id = object.id;
17728 renderItem.object = object;
17729 renderItem.geometry = geometry;
17730 renderItem.material = material;
17731 renderItem.program = materialProperties.program || defaultProgram;
17732 renderItem.groupOrder = groupOrder;
17733 renderItem.renderOrder = object.renderOrder;
17735 renderItem.group = group;
17739 renderItemsIndex ++;
17745 function push( object, geometry, material, groupOrder, z, group ) {
17747 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
17749 ( material.transparent === true ? transparent : opaque ).push( renderItem );
17753 function unshift( object, geometry, material, groupOrder, z, group ) {
17755 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
17757 ( material.transparent === true ? transparent : opaque ).unshift( renderItem );
17761 function sort( customOpaqueSort, customTransparentSort ) {
17763 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
17764 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
17768 function finish() {
17770 // Clear references from inactive renderItems in the list
17772 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
17774 const renderItem = renderItems[ i ];
17776 if ( renderItem.id === null ) break;
17778 renderItem.id = null;
17779 renderItem.object = null;
17780 renderItem.geometry = null;
17781 renderItem.material = null;
17782 renderItem.program = null;
17783 renderItem.group = null;
17792 transparent: transparent,
17804 function WebGLRenderLists( properties ) {
17806 let lists = new WeakMap();
17808 function get( scene, camera ) {
17810 const cameras = lists.get( scene );
17813 if ( cameras === undefined ) {
17815 list = new WebGLRenderList( properties );
17816 lists.set( scene, new WeakMap() );
17817 lists.get( scene ).set( camera, list );
17821 list = cameras.get( camera );
17822 if ( list === undefined ) {
17824 list = new WebGLRenderList( properties );
17825 cameras.set( camera, list );
17835 function dispose() {
17837 lists = new WeakMap();
17848 function UniformsCache() {
17854 get: function ( light ) {
17856 if ( lights[ light.id ] !== undefined ) {
17858 return lights[ light.id ];
17864 switch ( light.type ) {
17866 case 'DirectionalLight':
17868 direction: new Vector3(),
17875 position: new Vector3(),
17876 direction: new Vector3(),
17877 color: new Color(),
17887 position: new Vector3(),
17888 color: new Color(),
17894 case 'HemisphereLight':
17896 direction: new Vector3(),
17897 skyColor: new Color(),
17898 groundColor: new Color()
17902 case 'RectAreaLight':
17904 color: new Color(),
17905 position: new Vector3(),
17906 halfWidth: new Vector3(),
17907 halfHeight: new Vector3()
17913 lights[ light.id ] = uniforms;
17923 function ShadowUniformsCache() {
17929 get: function ( light ) {
17931 if ( lights[ light.id ] !== undefined ) {
17933 return lights[ light.id ];
17939 switch ( light.type ) {
17941 case 'DirectionalLight':
17944 shadowNormalBias: 0,
17946 shadowMapSize: new Vector2()
17953 shadowNormalBias: 0,
17955 shadowMapSize: new Vector2()
17962 shadowNormalBias: 0,
17964 shadowMapSize: new Vector2(),
17965 shadowCameraNear: 1,
17966 shadowCameraFar: 1000
17970 // TODO (abelnation): set RectAreaLight shadow uniforms
17974 lights[ light.id ] = uniforms;
17986 let nextVersion = 0;
17988 function shadowCastingLightsFirst( lightA, lightB ) {
17990 return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
17994 function WebGLLights( extensions, capabilities ) {
17996 const cache = new UniformsCache();
17998 const shadowCache = ShadowUniformsCache();
18005 directionalLength: - 1,
18008 rectAreaLength: - 1,
18011 numDirectionalShadows: - 1,
18012 numPointShadows: - 1,
18013 numSpotShadows: - 1
18016 ambient: [ 0, 0, 0 ],
18019 directionalShadow: [],
18020 directionalShadowMap: [],
18021 directionalShadowMatrix: [],
18025 spotShadowMatrix: [],
18027 rectAreaLTC1: null,
18028 rectAreaLTC2: null,
18031 pointShadowMap: [],
18032 pointShadowMatrix: [],
18037 for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
18039 const vector3 = new Vector3();
18040 const matrix4 = new Matrix4();
18041 const matrix42 = new Matrix4();
18043 function setup( lights ) {
18045 let r = 0, g = 0, b = 0;
18047 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
18049 let directionalLength = 0;
18050 let pointLength = 0;
18051 let spotLength = 0;
18052 let rectAreaLength = 0;
18053 let hemiLength = 0;
18055 let numDirectionalShadows = 0;
18056 let numPointShadows = 0;
18057 let numSpotShadows = 0;
18059 lights.sort( shadowCastingLightsFirst );
18061 for ( let i = 0, l = lights.length; i < l; i ++ ) {
18063 const light = lights[ i ];
18065 const color = light.color;
18066 const intensity = light.intensity;
18067 const distance = light.distance;
18069 const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
18071 if ( light.isAmbientLight ) {
18073 r += color.r * intensity;
18074 g += color.g * intensity;
18075 b += color.b * intensity;
18077 } else if ( light.isLightProbe ) {
18079 for ( let j = 0; j < 9; j ++ ) {
18081 state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
18085 } else if ( light.isDirectionalLight ) {
18087 const uniforms = cache.get( light );
18089 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18091 if ( light.castShadow ) {
18093 const shadow = light.shadow;
18095 const shadowUniforms = shadowCache.get( light );
18097 shadowUniforms.shadowBias = shadow.bias;
18098 shadowUniforms.shadowNormalBias = shadow.normalBias;
18099 shadowUniforms.shadowRadius = shadow.radius;
18100 shadowUniforms.shadowMapSize = shadow.mapSize;
18102 state.directionalShadow[ directionalLength ] = shadowUniforms;
18103 state.directionalShadowMap[ directionalLength ] = shadowMap;
18104 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
18106 numDirectionalShadows ++;
18110 state.directional[ directionalLength ] = uniforms;
18112 directionalLength ++;
18114 } else if ( light.isSpotLight ) {
18116 const uniforms = cache.get( light );
18118 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18120 uniforms.color.copy( color ).multiplyScalar( intensity );
18121 uniforms.distance = distance;
18123 uniforms.coneCos = Math.cos( light.angle );
18124 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
18125 uniforms.decay = light.decay;
18127 if ( light.castShadow ) {
18129 const shadow = light.shadow;
18131 const shadowUniforms = shadowCache.get( light );
18133 shadowUniforms.shadowBias = shadow.bias;
18134 shadowUniforms.shadowNormalBias = shadow.normalBias;
18135 shadowUniforms.shadowRadius = shadow.radius;
18136 shadowUniforms.shadowMapSize = shadow.mapSize;
18138 state.spotShadow[ spotLength ] = shadowUniforms;
18139 state.spotShadowMap[ spotLength ] = shadowMap;
18140 state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
18146 state.spot[ spotLength ] = uniforms;
18150 } else if ( light.isRectAreaLight ) {
18152 const uniforms = cache.get( light );
18154 // (a) intensity is the total visible light emitted
18155 //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
18157 // (b) intensity is the brightness of the light
18158 uniforms.color.copy( color ).multiplyScalar( intensity );
18160 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
18161 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
18163 state.rectArea[ rectAreaLength ] = uniforms;
18167 } else if ( light.isPointLight ) {
18169 const uniforms = cache.get( light );
18171 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18172 uniforms.distance = light.distance;
18173 uniforms.decay = light.decay;
18175 if ( light.castShadow ) {
18177 const shadow = light.shadow;
18179 const shadowUniforms = shadowCache.get( light );
18181 shadowUniforms.shadowBias = shadow.bias;
18182 shadowUniforms.shadowNormalBias = shadow.normalBias;
18183 shadowUniforms.shadowRadius = shadow.radius;
18184 shadowUniforms.shadowMapSize = shadow.mapSize;
18185 shadowUniforms.shadowCameraNear = shadow.camera.near;
18186 shadowUniforms.shadowCameraFar = shadow.camera.far;
18188 state.pointShadow[ pointLength ] = shadowUniforms;
18189 state.pointShadowMap[ pointLength ] = shadowMap;
18190 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
18192 numPointShadows ++;
18196 state.point[ pointLength ] = uniforms;
18200 } else if ( light.isHemisphereLight ) {
18202 const uniforms = cache.get( light );
18204 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
18205 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
18207 state.hemi[ hemiLength ] = uniforms;
18215 if ( rectAreaLength > 0 ) {
18217 if ( capabilities.isWebGL2 ) {
18221 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
18222 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
18228 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
18230 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
18231 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
18233 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
18235 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
18236 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
18240 console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
18248 state.ambient[ 0 ] = r;
18249 state.ambient[ 1 ] = g;
18250 state.ambient[ 2 ] = b;
18252 const hash = state.hash;
18254 if ( hash.directionalLength !== directionalLength ||
18255 hash.pointLength !== pointLength ||
18256 hash.spotLength !== spotLength ||
18257 hash.rectAreaLength !== rectAreaLength ||
18258 hash.hemiLength !== hemiLength ||
18259 hash.numDirectionalShadows !== numDirectionalShadows ||
18260 hash.numPointShadows !== numPointShadows ||
18261 hash.numSpotShadows !== numSpotShadows ) {
18263 state.directional.length = directionalLength;
18264 state.spot.length = spotLength;
18265 state.rectArea.length = rectAreaLength;
18266 state.point.length = pointLength;
18267 state.hemi.length = hemiLength;
18269 state.directionalShadow.length = numDirectionalShadows;
18270 state.directionalShadowMap.length = numDirectionalShadows;
18271 state.pointShadow.length = numPointShadows;
18272 state.pointShadowMap.length = numPointShadows;
18273 state.spotShadow.length = numSpotShadows;
18274 state.spotShadowMap.length = numSpotShadows;
18275 state.directionalShadowMatrix.length = numDirectionalShadows;
18276 state.pointShadowMatrix.length = numPointShadows;
18277 state.spotShadowMatrix.length = numSpotShadows;
18279 hash.directionalLength = directionalLength;
18280 hash.pointLength = pointLength;
18281 hash.spotLength = spotLength;
18282 hash.rectAreaLength = rectAreaLength;
18283 hash.hemiLength = hemiLength;
18285 hash.numDirectionalShadows = numDirectionalShadows;
18286 hash.numPointShadows = numPointShadows;
18287 hash.numSpotShadows = numSpotShadows;
18289 state.version = nextVersion ++;
18295 function setupView( lights, camera ) {
18297 let directionalLength = 0;
18298 let pointLength = 0;
18299 let spotLength = 0;
18300 let rectAreaLength = 0;
18301 let hemiLength = 0;
18303 const viewMatrix = camera.matrixWorldInverse;
18305 for ( let i = 0, l = lights.length; i < l; i ++ ) {
18307 const light = lights[ i ];
18309 if ( light.isDirectionalLight ) {
18311 const uniforms = state.directional[ directionalLength ];
18313 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18314 vector3.setFromMatrixPosition( light.target.matrixWorld );
18315 uniforms.direction.sub( vector3 );
18316 uniforms.direction.transformDirection( viewMatrix );
18318 directionalLength ++;
18320 } else if ( light.isSpotLight ) {
18322 const uniforms = state.spot[ spotLength ];
18324 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18325 uniforms.position.applyMatrix4( viewMatrix );
18327 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18328 vector3.setFromMatrixPosition( light.target.matrixWorld );
18329 uniforms.direction.sub( vector3 );
18330 uniforms.direction.transformDirection( viewMatrix );
18334 } else if ( light.isRectAreaLight ) {
18336 const uniforms = state.rectArea[ rectAreaLength ];
18338 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18339 uniforms.position.applyMatrix4( viewMatrix );
18341 // extract local rotation of light to derive width/height half vectors
18342 matrix42.identity();
18343 matrix4.copy( light.matrixWorld );
18344 matrix4.premultiply( viewMatrix );
18345 matrix42.extractRotation( matrix4 );
18347 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
18348 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
18350 uniforms.halfWidth.applyMatrix4( matrix42 );
18351 uniforms.halfHeight.applyMatrix4( matrix42 );
18355 } else if ( light.isPointLight ) {
18357 const uniforms = state.point[ pointLength ];
18359 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18360 uniforms.position.applyMatrix4( viewMatrix );
18364 } else if ( light.isHemisphereLight ) {
18366 const uniforms = state.hemi[ hemiLength ];
18368 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18369 uniforms.direction.transformDirection( viewMatrix );
18370 uniforms.direction.normalize();
18382 setupView: setupView,
18388 function WebGLRenderState( extensions, capabilities ) {
18390 const lights = new WebGLLights( extensions, capabilities );
18392 const lightsArray = [];
18393 const shadowsArray = [];
18397 lightsArray.length = 0;
18398 shadowsArray.length = 0;
18402 function pushLight( light ) {
18404 lightsArray.push( light );
18408 function pushShadow( shadowLight ) {
18410 shadowsArray.push( shadowLight );
18414 function setupLights() {
18416 lights.setup( lightsArray );
18420 function setupLightsView( camera ) {
18422 lights.setupView( lightsArray, camera );
18427 lightsArray: lightsArray,
18428 shadowsArray: shadowsArray,
18436 setupLights: setupLights,
18437 setupLightsView: setupLightsView,
18439 pushLight: pushLight,
18440 pushShadow: pushShadow
18445 function WebGLRenderStates( extensions, capabilities ) {
18447 let renderStates = new WeakMap();
18449 function get( scene, renderCallDepth = 0 ) {
18453 if ( renderStates.has( scene ) === false ) {
18455 renderState = new WebGLRenderState( extensions, capabilities );
18456 renderStates.set( scene, [] );
18457 renderStates.get( scene ).push( renderState );
18461 if ( renderCallDepth >= renderStates.get( scene ).length ) {
18463 renderState = new WebGLRenderState( extensions, capabilities );
18464 renderStates.get( scene ).push( renderState );
18468 renderState = renderStates.get( scene )[ renderCallDepth ];
18474 return renderState;
18478 function dispose() {
18480 renderStates = new WeakMap();
18494 * opacity: <float>,
18496 * map: new THREE.Texture( <Image> ),
18498 * alphaMap: new THREE.Texture( <Image> ),
18500 * displacementMap: new THREE.Texture( <Image> ),
18501 * displacementScale: <float>,
18502 * displacementBias: <float>,
18504 * wireframe: <boolean>,
18505 * wireframeLinewidth: <float>
18509 function MeshDepthMaterial( parameters ) {
18511 Material.call( this );
18513 this.type = 'MeshDepthMaterial';
18515 this.depthPacking = BasicDepthPacking;
18517 this.skinning = false;
18518 this.morphTargets = false;
18522 this.alphaMap = null;
18524 this.displacementMap = null;
18525 this.displacementScale = 1;
18526 this.displacementBias = 0;
18528 this.wireframe = false;
18529 this.wireframeLinewidth = 1;
18533 this.setValues( parameters );
18537 MeshDepthMaterial.prototype = Object.create( Material.prototype );
18538 MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
18540 MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
18542 MeshDepthMaterial.prototype.copy = function ( source ) {
18544 Material.prototype.copy.call( this, source );
18546 this.depthPacking = source.depthPacking;
18548 this.skinning = source.skinning;
18549 this.morphTargets = source.morphTargets;
18551 this.map = source.map;
18553 this.alphaMap = source.alphaMap;
18555 this.displacementMap = source.displacementMap;
18556 this.displacementScale = source.displacementScale;
18557 this.displacementBias = source.displacementBias;
18559 this.wireframe = source.wireframe;
18560 this.wireframeLinewidth = source.wireframeLinewidth;
18569 * referencePosition: <float>,
18570 * nearDistance: <float>,
18571 * farDistance: <float>,
18573 * skinning: <bool>,
18574 * morphTargets: <bool>,
18576 * map: new THREE.Texture( <Image> ),
18578 * alphaMap: new THREE.Texture( <Image> ),
18580 * displacementMap: new THREE.Texture( <Image> ),
18581 * displacementScale: <float>,
18582 * displacementBias: <float>
18587 function MeshDistanceMaterial( parameters ) {
18589 Material.call( this );
18591 this.type = 'MeshDistanceMaterial';
18593 this.referencePosition = new Vector3();
18594 this.nearDistance = 1;
18595 this.farDistance = 1000;
18597 this.skinning = false;
18598 this.morphTargets = false;
18602 this.alphaMap = null;
18604 this.displacementMap = null;
18605 this.displacementScale = 1;
18606 this.displacementBias = 0;
18610 this.setValues( parameters );
18614 MeshDistanceMaterial.prototype = Object.create( Material.prototype );
18615 MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
18617 MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
18619 MeshDistanceMaterial.prototype.copy = function ( source ) {
18621 Material.prototype.copy.call( this, source );
18623 this.referencePosition.copy( source.referencePosition );
18624 this.nearDistance = source.nearDistance;
18625 this.farDistance = source.farDistance;
18627 this.skinning = source.skinning;
18628 this.morphTargets = source.morphTargets;
18630 this.map = source.map;
18632 this.alphaMap = source.alphaMap;
18634 this.displacementMap = source.displacementMap;
18635 this.displacementScale = source.displacementScale;
18636 this.displacementBias = source.displacementBias;
18642 var vsm_frag = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n\tfor ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 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, i ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean * HALF_SAMPLE_RATE;\n\tsquared_mean = squared_mean * HALF_SAMPLE_RATE;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
18644 var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
18646 function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
18648 let _frustum = new Frustum();
18650 const _shadowMapSize = new Vector2(),
18651 _viewportSize = new Vector2(),
18653 _viewport = new Vector4(),
18655 _depthMaterials = [],
18656 _distanceMaterials = [],
18658 _materialCache = {};
18660 const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
18662 const shadowMaterialVertical = new ShaderMaterial( {
18665 SAMPLE_RATE: 2.0 / 8.0,
18666 HALF_SAMPLE_RATE: 1.0 / 8.0
18670 shadow_pass: { value: null },
18671 resolution: { value: new Vector2() },
18672 radius: { value: 4.0 }
18675 vertexShader: vsm_vert,
18677 fragmentShader: vsm_frag
18681 const shadowMaterialHorizontal = shadowMaterialVertical.clone();
18682 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
18684 const fullScreenTri = new BufferGeometry();
18685 fullScreenTri.setAttribute(
18687 new BufferAttribute(
18688 new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
18693 const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
18695 const scope = this;
18697 this.enabled = false;
18699 this.autoUpdate = true;
18700 this.needsUpdate = false;
18702 this.type = PCFShadowMap;
18704 this.render = function ( lights, scene, camera ) {
18706 if ( scope.enabled === false ) return;
18707 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
18709 if ( lights.length === 0 ) return;
18711 const currentRenderTarget = _renderer.getRenderTarget();
18712 const activeCubeFace = _renderer.getActiveCubeFace();
18713 const activeMipmapLevel = _renderer.getActiveMipmapLevel();
18715 const _state = _renderer.state;
18717 // Set GL state for depth map.
18718 _state.setBlending( NoBlending );
18719 _state.buffers.color.setClear( 1, 1, 1, 1 );
18720 _state.buffers.depth.setTest( true );
18721 _state.setScissorTest( false );
18723 // render depth map
18725 for ( let i = 0, il = lights.length; i < il; i ++ ) {
18727 const light = lights[ i ];
18728 const shadow = light.shadow;
18730 if ( shadow === undefined ) {
18732 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
18737 if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
18739 _shadowMapSize.copy( shadow.mapSize );
18741 const shadowFrameExtents = shadow.getFrameExtents();
18743 _shadowMapSize.multiply( shadowFrameExtents );
18745 _viewportSize.copy( shadow.mapSize );
18747 if ( _shadowMapSize.x > maxTextureSize || _shadowMapSize.y > maxTextureSize ) {
18749 if ( _shadowMapSize.x > maxTextureSize ) {
18751 _viewportSize.x = Math.floor( maxTextureSize / shadowFrameExtents.x );
18752 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
18753 shadow.mapSize.x = _viewportSize.x;
18757 if ( _shadowMapSize.y > maxTextureSize ) {
18759 _viewportSize.y = Math.floor( maxTextureSize / shadowFrameExtents.y );
18760 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
18761 shadow.mapSize.y = _viewportSize.y;
18767 if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
18769 const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
18771 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
18772 shadow.map.texture.name = light.name + '.shadowMap';
18774 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
18776 shadow.camera.updateProjectionMatrix();
18780 if ( shadow.map === null ) {
18782 const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
18784 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
18785 shadow.map.texture.name = light.name + '.shadowMap';
18787 shadow.camera.updateProjectionMatrix();
18791 _renderer.setRenderTarget( shadow.map );
18794 const viewportCount = shadow.getViewportCount();
18796 for ( let vp = 0; vp < viewportCount; vp ++ ) {
18798 const viewport = shadow.getViewport( vp );
18801 _viewportSize.x * viewport.x,
18802 _viewportSize.y * viewport.y,
18803 _viewportSize.x * viewport.z,
18804 _viewportSize.y * viewport.w
18807 _state.viewport( _viewport );
18809 shadow.updateMatrices( light, vp );
18811 _frustum = shadow.getFrustum();
18813 renderObject( scene, camera, shadow.camera, light, this.type );
18817 // do blur pass for VSM
18819 if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
18821 VSMPass( shadow, camera );
18825 shadow.needsUpdate = false;
18829 scope.needsUpdate = false;
18831 _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
18835 function VSMPass( shadow, camera ) {
18837 const geometry = _objects.update( fullScreenMesh );
18841 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
18842 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
18843 shadowMaterialVertical.uniforms.radius.value = shadow.radius;
18844 _renderer.setRenderTarget( shadow.mapPass );
18846 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
18850 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
18851 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
18852 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
18853 _renderer.setRenderTarget( shadow.map );
18855 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
18859 function getDepthMaterialVariant( useMorphing, useSkinning, useInstancing ) {
18861 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
18863 let material = _depthMaterials[ index ];
18865 if ( material === undefined ) {
18867 material = new MeshDepthMaterial( {
18869 depthPacking: RGBADepthPacking,
18871 morphTargets: useMorphing,
18872 skinning: useSkinning
18876 _depthMaterials[ index ] = material;
18884 function getDistanceMaterialVariant( useMorphing, useSkinning, useInstancing ) {
18886 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
18888 let material = _distanceMaterials[ index ];
18890 if ( material === undefined ) {
18892 material = new MeshDistanceMaterial( {
18894 morphTargets: useMorphing,
18895 skinning: useSkinning
18899 _distanceMaterials[ index ] = material;
18907 function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) {
18911 let getMaterialVariant = getDepthMaterialVariant;
18912 let customMaterial = object.customDepthMaterial;
18914 if ( light.isPointLight === true ) {
18916 getMaterialVariant = getDistanceMaterialVariant;
18917 customMaterial = object.customDistanceMaterial;
18921 if ( customMaterial === undefined ) {
18923 let useMorphing = false;
18925 if ( material.morphTargets === true ) {
18927 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
18931 let useSkinning = false;
18933 if ( object.isSkinnedMesh === true ) {
18935 if ( material.skinning === true ) {
18937 useSkinning = true;
18941 console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
18947 const useInstancing = object.isInstancedMesh === true;
18949 result = getMaterialVariant( useMorphing, useSkinning, useInstancing );
18953 result = customMaterial;
18957 if ( _renderer.localClippingEnabled &&
18958 material.clipShadows === true &&
18959 material.clippingPlanes.length !== 0 ) {
18961 // in this case we need a unique material instance reflecting the
18962 // appropriate state
18964 const keyA = result.uuid, keyB = material.uuid;
18966 let materialsForVariant = _materialCache[ keyA ];
18968 if ( materialsForVariant === undefined ) {
18970 materialsForVariant = {};
18971 _materialCache[ keyA ] = materialsForVariant;
18975 let cachedMaterial = materialsForVariant[ keyB ];
18977 if ( cachedMaterial === undefined ) {
18979 cachedMaterial = result.clone();
18980 materialsForVariant[ keyB ] = cachedMaterial;
18984 result = cachedMaterial;
18988 result.visible = material.visible;
18989 result.wireframe = material.wireframe;
18991 if ( type === VSMShadowMap ) {
18993 result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
18997 result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
19001 result.clipShadows = material.clipShadows;
19002 result.clippingPlanes = material.clippingPlanes;
19003 result.clipIntersection = material.clipIntersection;
19005 result.wireframeLinewidth = material.wireframeLinewidth;
19006 result.linewidth = material.linewidth;
19008 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
19010 result.referencePosition.setFromMatrixPosition( light.matrixWorld );
19011 result.nearDistance = shadowCameraNear;
19012 result.farDistance = shadowCameraFar;
19020 function renderObject( object, camera, shadowCamera, light, type ) {
19022 if ( object.visible === false ) return;
19024 const visible = object.layers.test( camera.layers );
19026 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
19028 if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
19030 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
19032 const geometry = _objects.update( object );
19033 const material = object.material;
19035 if ( Array.isArray( material ) ) {
19037 const groups = geometry.groups;
19039 for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
19041 const group = groups[ k ];
19042 const groupMaterial = material[ group.materialIndex ];
19044 if ( groupMaterial && groupMaterial.visible ) {
19046 const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type );
19048 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
19054 } else if ( material.visible ) {
19056 const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type );
19058 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
19066 const children = object.children;
19068 for ( let i = 0, l = children.length; i < l; i ++ ) {
19070 renderObject( children[ i ], camera, shadowCamera, light, type );
19078 function WebGLState( gl, extensions, capabilities ) {
19080 const isWebGL2 = capabilities.isWebGL2;
19082 function ColorBuffer() {
19084 let locked = false;
19086 const color = new Vector4();
19087 let currentColorMask = null;
19088 const currentColorClear = new Vector4( 0, 0, 0, 0 );
19092 setMask: function ( colorMask ) {
19094 if ( currentColorMask !== colorMask && ! locked ) {
19096 gl.colorMask( colorMask, colorMask, colorMask, colorMask );
19097 currentColorMask = colorMask;
19103 setLocked: function ( lock ) {
19109 setClear: function ( r, g, b, a, premultipliedAlpha ) {
19111 if ( premultipliedAlpha === true ) {
19113 r *= a; g *= a; b *= a;
19117 color.set( r, g, b, a );
19119 if ( currentColorClear.equals( color ) === false ) {
19121 gl.clearColor( r, g, b, a );
19122 currentColorClear.copy( color );
19128 reset: function () {
19132 currentColorMask = null;
19133 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
19141 function DepthBuffer() {
19143 let locked = false;
19145 let currentDepthMask = null;
19146 let currentDepthFunc = null;
19147 let currentDepthClear = null;
19151 setTest: function ( depthTest ) {
19165 setMask: function ( depthMask ) {
19167 if ( currentDepthMask !== depthMask && ! locked ) {
19169 gl.depthMask( depthMask );
19170 currentDepthMask = depthMask;
19176 setFunc: function ( depthFunc ) {
19178 if ( currentDepthFunc !== depthFunc ) {
19182 switch ( depthFunc ) {
19186 gl.depthFunc( 512 );
19191 gl.depthFunc( 519 );
19196 gl.depthFunc( 513 );
19199 case LessEqualDepth:
19201 gl.depthFunc( 515 );
19206 gl.depthFunc( 514 );
19209 case GreaterEqualDepth:
19211 gl.depthFunc( 518 );
19216 gl.depthFunc( 516 );
19219 case NotEqualDepth:
19221 gl.depthFunc( 517 );
19226 gl.depthFunc( 515 );
19232 gl.depthFunc( 515 );
19236 currentDepthFunc = depthFunc;
19242 setLocked: function ( lock ) {
19248 setClear: function ( depth ) {
19250 if ( currentDepthClear !== depth ) {
19252 gl.clearDepth( depth );
19253 currentDepthClear = depth;
19259 reset: function () {
19263 currentDepthMask = null;
19264 currentDepthFunc = null;
19265 currentDepthClear = null;
19273 function StencilBuffer() {
19275 let locked = false;
19277 let currentStencilMask = null;
19278 let currentStencilFunc = null;
19279 let currentStencilRef = null;
19280 let currentStencilFuncMask = null;
19281 let currentStencilFail = null;
19282 let currentStencilZFail = null;
19283 let currentStencilZPass = null;
19284 let currentStencilClear = null;
19288 setTest: function ( stencilTest ) {
19292 if ( stencilTest ) {
19306 setMask: function ( stencilMask ) {
19308 if ( currentStencilMask !== stencilMask && ! locked ) {
19310 gl.stencilMask( stencilMask );
19311 currentStencilMask = stencilMask;
19317 setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
19319 if ( currentStencilFunc !== stencilFunc ||
19320 currentStencilRef !== stencilRef ||
19321 currentStencilFuncMask !== stencilMask ) {
19323 gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
19325 currentStencilFunc = stencilFunc;
19326 currentStencilRef = stencilRef;
19327 currentStencilFuncMask = stencilMask;
19333 setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
19335 if ( currentStencilFail !== stencilFail ||
19336 currentStencilZFail !== stencilZFail ||
19337 currentStencilZPass !== stencilZPass ) {
19339 gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
19341 currentStencilFail = stencilFail;
19342 currentStencilZFail = stencilZFail;
19343 currentStencilZPass = stencilZPass;
19349 setLocked: function ( lock ) {
19355 setClear: function ( stencil ) {
19357 if ( currentStencilClear !== stencil ) {
19359 gl.clearStencil( stencil );
19360 currentStencilClear = stencil;
19366 reset: function () {
19370 currentStencilMask = null;
19371 currentStencilFunc = null;
19372 currentStencilRef = null;
19373 currentStencilFuncMask = null;
19374 currentStencilFail = null;
19375 currentStencilZFail = null;
19376 currentStencilZPass = null;
19377 currentStencilClear = null;
19387 const colorBuffer = new ColorBuffer();
19388 const depthBuffer = new DepthBuffer();
19389 const stencilBuffer = new StencilBuffer();
19391 let enabledCapabilities = {};
19393 let currentProgram = null;
19395 let currentBlendingEnabled = null;
19396 let currentBlending = null;
19397 let currentBlendEquation = null;
19398 let currentBlendSrc = null;
19399 let currentBlendDst = null;
19400 let currentBlendEquationAlpha = null;
19401 let currentBlendSrcAlpha = null;
19402 let currentBlendDstAlpha = null;
19403 let currentPremultipledAlpha = false;
19405 let currentFlipSided = null;
19406 let currentCullFace = null;
19408 let currentLineWidth = null;
19410 let currentPolygonOffsetFactor = null;
19411 let currentPolygonOffsetUnits = null;
19413 const maxTextures = gl.getParameter( 35661 );
19415 let lineWidthAvailable = false;
19417 const glVersion = gl.getParameter( 7938 );
19419 if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
19421 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
19422 lineWidthAvailable = ( version >= 1.0 );
19424 } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
19426 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
19427 lineWidthAvailable = ( version >= 2.0 );
19431 let currentTextureSlot = null;
19432 let currentBoundTextures = {};
19434 const currentScissor = new Vector4();
19435 const currentViewport = new Vector4();
19437 function createTexture( type, target, count ) {
19439 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
19440 const texture = gl.createTexture();
19442 gl.bindTexture( type, texture );
19443 gl.texParameteri( type, 10241, 9728 );
19444 gl.texParameteri( type, 10240, 9728 );
19446 for ( let i = 0; i < count; i ++ ) {
19448 gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data );
19456 const emptyTextures = {};
19457 emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 );
19458 emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 );
19462 colorBuffer.setClear( 0, 0, 0, 1 );
19463 depthBuffer.setClear( 1 );
19464 stencilBuffer.setClear( 0 );
19467 depthBuffer.setFunc( LessEqualDepth );
19469 setFlipSided( false );
19470 setCullFace( CullFaceBack );
19473 setBlending( NoBlending );
19477 function enable( id ) {
19479 if ( enabledCapabilities[ id ] !== true ) {
19482 enabledCapabilities[ id ] = true;
19488 function disable( id ) {
19490 if ( enabledCapabilities[ id ] !== false ) {
19493 enabledCapabilities[ id ] = false;
19499 function useProgram( program ) {
19501 if ( currentProgram !== program ) {
19503 gl.useProgram( program );
19505 currentProgram = program;
19515 const equationToGL = {
19516 [ AddEquation ]: 32774,
19517 [ SubtractEquation ]: 32778,
19518 [ ReverseSubtractEquation ]: 32779
19523 equationToGL[ MinEquation ] = 32775;
19524 equationToGL[ MaxEquation ] = 32776;
19528 const extension = extensions.get( 'EXT_blend_minmax' );
19530 if ( extension !== null ) {
19532 equationToGL[ MinEquation ] = extension.MIN_EXT;
19533 equationToGL[ MaxEquation ] = extension.MAX_EXT;
19539 const factorToGL = {
19542 [ SrcColorFactor ]: 768,
19543 [ SrcAlphaFactor ]: 770,
19544 [ SrcAlphaSaturateFactor ]: 776,
19545 [ DstColorFactor ]: 774,
19546 [ DstAlphaFactor ]: 772,
19547 [ OneMinusSrcColorFactor ]: 769,
19548 [ OneMinusSrcAlphaFactor ]: 771,
19549 [ OneMinusDstColorFactor ]: 775,
19550 [ OneMinusDstAlphaFactor ]: 773
19553 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
19555 if ( blending === NoBlending ) {
19557 if ( currentBlendingEnabled ) {
19560 currentBlendingEnabled = false;
19568 if ( ! currentBlendingEnabled ) {
19571 currentBlendingEnabled = true;
19575 if ( blending !== CustomBlending ) {
19577 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
19579 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
19581 gl.blendEquation( 32774 );
19583 currentBlendEquation = AddEquation;
19584 currentBlendEquationAlpha = AddEquation;
19588 if ( premultipliedAlpha ) {
19590 switch ( blending ) {
19592 case NormalBlending:
19593 gl.blendFuncSeparate( 1, 771, 1, 771 );
19596 case AdditiveBlending:
19597 gl.blendFunc( 1, 1 );
19600 case SubtractiveBlending:
19601 gl.blendFuncSeparate( 0, 0, 769, 771 );
19604 case MultiplyBlending:
19605 gl.blendFuncSeparate( 0, 768, 0, 770 );
19609 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
19616 switch ( blending ) {
19618 case NormalBlending:
19619 gl.blendFuncSeparate( 770, 771, 1, 771 );
19622 case AdditiveBlending:
19623 gl.blendFunc( 770, 1 );
19626 case SubtractiveBlending:
19627 gl.blendFunc( 0, 769 );
19630 case MultiplyBlending:
19631 gl.blendFunc( 0, 768 );
19635 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
19642 currentBlendSrc = null;
19643 currentBlendDst = null;
19644 currentBlendSrcAlpha = null;
19645 currentBlendDstAlpha = null;
19647 currentBlending = blending;
19648 currentPremultipledAlpha = premultipliedAlpha;
19658 blendEquationAlpha = blendEquationAlpha || blendEquation;
19659 blendSrcAlpha = blendSrcAlpha || blendSrc;
19660 blendDstAlpha = blendDstAlpha || blendDst;
19662 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
19664 gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
19666 currentBlendEquation = blendEquation;
19667 currentBlendEquationAlpha = blendEquationAlpha;
19671 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
19673 gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
19675 currentBlendSrc = blendSrc;
19676 currentBlendDst = blendDst;
19677 currentBlendSrcAlpha = blendSrcAlpha;
19678 currentBlendDstAlpha = blendDstAlpha;
19682 currentBlending = blending;
19683 currentPremultipledAlpha = null;
19687 function setMaterial( material, frontFaceCW ) {
19689 material.side === DoubleSide
19693 let flipSided = ( material.side === BackSide );
19694 if ( frontFaceCW ) flipSided = ! flipSided;
19696 setFlipSided( flipSided );
19698 ( material.blending === NormalBlending && material.transparent === false )
19699 ? setBlending( NoBlending )
19700 : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
19702 depthBuffer.setFunc( material.depthFunc );
19703 depthBuffer.setTest( material.depthTest );
19704 depthBuffer.setMask( material.depthWrite );
19705 colorBuffer.setMask( material.colorWrite );
19707 const stencilWrite = material.stencilWrite;
19708 stencilBuffer.setTest( stencilWrite );
19709 if ( stencilWrite ) {
19711 stencilBuffer.setMask( material.stencilWriteMask );
19712 stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
19713 stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
19717 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
19723 function setFlipSided( flipSided ) {
19725 if ( currentFlipSided !== flipSided ) {
19729 gl.frontFace( 2304 );
19733 gl.frontFace( 2305 );
19737 currentFlipSided = flipSided;
19743 function setCullFace( cullFace ) {
19745 if ( cullFace !== CullFaceNone ) {
19749 if ( cullFace !== currentCullFace ) {
19751 if ( cullFace === CullFaceBack ) {
19753 gl.cullFace( 1029 );
19755 } else if ( cullFace === CullFaceFront ) {
19757 gl.cullFace( 1028 );
19761 gl.cullFace( 1032 );
19773 currentCullFace = cullFace;
19777 function setLineWidth( width ) {
19779 if ( width !== currentLineWidth ) {
19781 if ( lineWidthAvailable ) gl.lineWidth( width );
19783 currentLineWidth = width;
19789 function setPolygonOffset( polygonOffset, factor, units ) {
19791 if ( polygonOffset ) {
19795 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
19797 gl.polygonOffset( factor, units );
19799 currentPolygonOffsetFactor = factor;
19800 currentPolygonOffsetUnits = units;
19812 function setScissorTest( scissorTest ) {
19814 if ( scissorTest ) {
19828 function activeTexture( webglSlot ) {
19830 if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1;
19832 if ( currentTextureSlot !== webglSlot ) {
19834 gl.activeTexture( webglSlot );
19835 currentTextureSlot = webglSlot;
19841 function bindTexture( webglType, webglTexture ) {
19843 if ( currentTextureSlot === null ) {
19849 let boundTexture = currentBoundTextures[ currentTextureSlot ];
19851 if ( boundTexture === undefined ) {
19853 boundTexture = { type: undefined, texture: undefined };
19854 currentBoundTextures[ currentTextureSlot ] = boundTexture;
19858 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
19860 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
19862 boundTexture.type = webglType;
19863 boundTexture.texture = webglTexture;
19869 function unbindTexture() {
19871 const boundTexture = currentBoundTextures[ currentTextureSlot ];
19873 if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
19875 gl.bindTexture( boundTexture.type, null );
19877 boundTexture.type = undefined;
19878 boundTexture.texture = undefined;
19884 function compressedTexImage2D() {
19888 gl.compressedTexImage2D.apply( gl, arguments );
19890 } catch ( error ) {
19892 console.error( 'THREE.WebGLState:', error );
19898 function texImage2D() {
19902 gl.texImage2D.apply( gl, arguments );
19904 } catch ( error ) {
19906 console.error( 'THREE.WebGLState:', error );
19912 function texImage3D() {
19916 gl.texImage3D.apply( gl, arguments );
19918 } catch ( error ) {
19920 console.error( 'THREE.WebGLState:', error );
19928 function scissor( scissor ) {
19930 if ( currentScissor.equals( scissor ) === false ) {
19932 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
19933 currentScissor.copy( scissor );
19939 function viewport( viewport ) {
19941 if ( currentViewport.equals( viewport ) === false ) {
19943 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
19944 currentViewport.copy( viewport );
19954 enabledCapabilities = {};
19956 currentTextureSlot = null;
19957 currentBoundTextures = {};
19959 currentProgram = null;
19961 currentBlendingEnabled = null;
19962 currentBlending = null;
19963 currentBlendEquation = null;
19964 currentBlendSrc = null;
19965 currentBlendDst = null;
19966 currentBlendEquationAlpha = null;
19967 currentBlendSrcAlpha = null;
19968 currentBlendDstAlpha = null;
19969 currentPremultipledAlpha = false;
19971 currentFlipSided = null;
19972 currentCullFace = null;
19974 currentLineWidth = null;
19976 currentPolygonOffsetFactor = null;
19977 currentPolygonOffsetUnits = null;
19979 colorBuffer.reset();
19980 depthBuffer.reset();
19981 stencilBuffer.reset();
19988 color: colorBuffer,
19989 depth: depthBuffer,
19990 stencil: stencilBuffer
19996 useProgram: useProgram,
19998 setBlending: setBlending,
19999 setMaterial: setMaterial,
20001 setFlipSided: setFlipSided,
20002 setCullFace: setCullFace,
20004 setLineWidth: setLineWidth,
20005 setPolygonOffset: setPolygonOffset,
20007 setScissorTest: setScissorTest,
20009 activeTexture: activeTexture,
20010 bindTexture: bindTexture,
20011 unbindTexture: unbindTexture,
20012 compressedTexImage2D: compressedTexImage2D,
20013 texImage2D: texImage2D,
20014 texImage3D: texImage3D,
20017 viewport: viewport,
20025 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
20027 const isWebGL2 = capabilities.isWebGL2;
20028 const maxTextures = capabilities.maxTextures;
20029 const maxCubemapSize = capabilities.maxCubemapSize;
20030 const maxTextureSize = capabilities.maxTextureSize;
20031 const maxSamples = capabilities.maxSamples;
20033 const _videoTextures = new WeakMap();
20036 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
20037 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
20038 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
20040 let useOffscreenCanvas = false;
20044 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
20045 && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
20049 // Ignore any errors
20053 function createCanvas( width, height ) {
20055 // Use OffscreenCanvas when available. Specially needed in web workers
20057 return useOffscreenCanvas ?
20058 new OffscreenCanvas( width, height ) :
20059 document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
20063 function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
20067 // handle case if texture exceeds max size
20069 if ( image.width > maxSize || image.height > maxSize ) {
20071 scale = maxSize / Math.max( image.width, image.height );
20075 // only perform resize if necessary
20077 if ( scale < 1 || needsPowerOfTwo === true ) {
20079 // only perform resize for certain image types
20081 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
20082 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
20083 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
20085 const floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor;
20087 const width = floor( scale * image.width );
20088 const height = floor( scale * image.height );
20090 if ( _canvas === undefined ) _canvas = createCanvas( width, height );
20092 // cube textures can't reuse the same canvas
20094 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
20096 canvas.width = width;
20097 canvas.height = height;
20099 const context = canvas.getContext( '2d' );
20100 context.drawImage( image, 0, 0, width, height );
20102 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
20108 if ( 'data' in image ) {
20110 console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
20124 function isPowerOfTwo( image ) {
20126 return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height );
20130 function textureNeedsPowerOfTwo( texture ) {
20132 if ( isWebGL2 ) return false;
20134 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
20135 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
20139 function textureNeedsGenerateMipmaps( texture, supportsMips ) {
20141 return texture.generateMipmaps && supportsMips &&
20142 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
20146 function generateMipmap( target, texture, width, height ) {
20148 _gl.generateMipmap( target );
20150 const textureProperties = properties.get( texture );
20152 // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
20153 textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
20157 function getInternalFormat( internalFormatName, glFormat, glType ) {
20159 if ( isWebGL2 === false ) return glFormat;
20161 if ( internalFormatName !== null ) {
20163 if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
20165 console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
20169 let internalFormat = glFormat;
20171 if ( glFormat === 6403 ) {
20173 if ( glType === 5126 ) internalFormat = 33326;
20174 if ( glType === 5131 ) internalFormat = 33325;
20175 if ( glType === 5121 ) internalFormat = 33321;
20179 if ( glFormat === 6407 ) {
20181 if ( glType === 5126 ) internalFormat = 34837;
20182 if ( glType === 5131 ) internalFormat = 34843;
20183 if ( glType === 5121 ) internalFormat = 32849;
20187 if ( glFormat === 6408 ) {
20189 if ( glType === 5126 ) internalFormat = 34836;
20190 if ( glType === 5131 ) internalFormat = 34842;
20191 if ( glType === 5121 ) internalFormat = 32856;
20195 if ( internalFormat === 33325 || internalFormat === 33326 ||
20196 internalFormat === 34842 || internalFormat === 34836 ) {
20198 extensions.get( 'EXT_color_buffer_float' );
20202 return internalFormat;
20206 // Fallback filters for non-power-of-2 textures
20208 function filterFallback( f ) {
20210 if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
20222 function onTextureDispose( event ) {
20224 const texture = event.target;
20226 texture.removeEventListener( 'dispose', onTextureDispose );
20228 deallocateTexture( texture );
20230 if ( texture.isVideoTexture ) {
20232 _videoTextures.delete( texture );
20236 info.memory.textures --;
20240 function onRenderTargetDispose( event ) {
20242 const renderTarget = event.target;
20244 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
20246 deallocateRenderTarget( renderTarget );
20248 info.memory.textures --;
20254 function deallocateTexture( texture ) {
20256 const textureProperties = properties.get( texture );
20258 if ( textureProperties.__webglInit === undefined ) return;
20260 _gl.deleteTexture( textureProperties.__webglTexture );
20262 properties.remove( texture );
20266 function deallocateRenderTarget( renderTarget ) {
20268 const renderTargetProperties = properties.get( renderTarget );
20269 const textureProperties = properties.get( renderTarget.texture );
20271 if ( ! renderTarget ) return;
20273 if ( textureProperties.__webglTexture !== undefined ) {
20275 _gl.deleteTexture( textureProperties.__webglTexture );
20279 if ( renderTarget.depthTexture ) {
20281 renderTarget.depthTexture.dispose();
20285 if ( renderTarget.isWebGLCubeRenderTarget ) {
20287 for ( let i = 0; i < 6; i ++ ) {
20289 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
20290 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
20296 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
20297 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
20298 if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
20299 if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
20300 if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
20304 properties.remove( renderTarget.texture );
20305 properties.remove( renderTarget );
20311 let textureUnits = 0;
20313 function resetTextureUnits() {
20319 function allocateTextureUnit() {
20321 const textureUnit = textureUnits;
20323 if ( textureUnit >= maxTextures ) {
20325 console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
20331 return textureUnit;
20337 function setTexture2D( texture, slot ) {
20339 const textureProperties = properties.get( texture );
20341 if ( texture.isVideoTexture ) updateVideoTexture( texture );
20343 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20345 const image = texture.image;
20347 if ( image === undefined ) {
20349 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
20351 } else if ( image.complete === false ) {
20353 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
20357 uploadTexture( textureProperties, texture, slot );
20364 state.activeTexture( 33984 + slot );
20365 state.bindTexture( 3553, textureProperties.__webglTexture );
20369 function setTexture2DArray( texture, slot ) {
20371 const textureProperties = properties.get( texture );
20373 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20375 uploadTexture( textureProperties, texture, slot );
20380 state.activeTexture( 33984 + slot );
20381 state.bindTexture( 35866, textureProperties.__webglTexture );
20385 function setTexture3D( texture, slot ) {
20387 const textureProperties = properties.get( texture );
20389 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20391 uploadTexture( textureProperties, texture, slot );
20396 state.activeTexture( 33984 + slot );
20397 state.bindTexture( 32879, textureProperties.__webglTexture );
20401 function setTextureCube( texture, slot ) {
20403 const textureProperties = properties.get( texture );
20405 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20407 uploadCubeTexture( textureProperties, texture, slot );
20412 state.activeTexture( 33984 + slot );
20413 state.bindTexture( 34067, textureProperties.__webglTexture );
20417 const wrappingToGL = {
20418 [ RepeatWrapping ]: 10497,
20419 [ ClampToEdgeWrapping ]: 33071,
20420 [ MirroredRepeatWrapping ]: 33648
20423 const filterToGL = {
20424 [ NearestFilter ]: 9728,
20425 [ NearestMipmapNearestFilter ]: 9984,
20426 [ NearestMipmapLinearFilter ]: 9986,
20428 [ LinearFilter ]: 9729,
20429 [ LinearMipmapNearestFilter ]: 9985,
20430 [ LinearMipmapLinearFilter ]: 9987
20433 function setTextureParameters( textureType, texture, supportsMips ) {
20435 if ( supportsMips ) {
20437 _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
20438 _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
20440 if ( textureType === 32879 || textureType === 35866 ) {
20442 _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
20446 _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
20447 _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
20451 _gl.texParameteri( textureType, 10242, 33071 );
20452 _gl.texParameteri( textureType, 10243, 33071 );
20454 if ( textureType === 32879 || textureType === 35866 ) {
20456 _gl.texParameteri( textureType, 32882, 33071 );
20460 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
20462 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
20466 _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) );
20467 _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) );
20469 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
20471 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
20477 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
20481 if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
20482 if ( texture.type === HalfFloatType && ( isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
20484 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
20486 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
20487 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
20495 function initTexture( textureProperties, texture ) {
20497 if ( textureProperties.__webglInit === undefined ) {
20499 textureProperties.__webglInit = true;
20501 texture.addEventListener( 'dispose', onTextureDispose );
20503 textureProperties.__webglTexture = _gl.createTexture();
20505 info.memory.textures ++;
20511 function uploadTexture( textureProperties, texture, slot ) {
20513 let textureType = 3553;
20515 if ( texture.isDataTexture2DArray ) textureType = 35866;
20516 if ( texture.isDataTexture3D ) textureType = 32879;
20518 initTexture( textureProperties, texture );
20520 state.activeTexture( 33984 + slot );
20521 state.bindTexture( textureType, textureProperties.__webglTexture );
20523 _gl.pixelStorei( 37440, texture.flipY );
20524 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
20525 _gl.pixelStorei( 3317, texture.unpackAlignment );
20527 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
20528 const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
20530 const supportsMips = isPowerOfTwo( image ) || isWebGL2,
20531 glFormat = utils.convert( texture.format );
20533 let glType = utils.convert( texture.type ),
20534 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
20536 setTextureParameters( textureType, texture, supportsMips );
20539 const mipmaps = texture.mipmaps;
20541 if ( texture.isDepthTexture ) {
20543 // populate depth texture with dummy data
20545 glInternalFormat = 6402;
20549 if ( texture.type === FloatType ) {
20551 glInternalFormat = 36012;
20553 } else if ( texture.type === UnsignedIntType ) {
20555 glInternalFormat = 33190;
20557 } else if ( texture.type === UnsignedInt248Type ) {
20559 glInternalFormat = 35056;
20563 glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D
20569 if ( texture.type === FloatType ) {
20571 console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
20577 // validation checks for WebGL 1
20579 if ( texture.format === DepthFormat && glInternalFormat === 6402 ) {
20581 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20582 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
20583 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20584 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
20586 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
20588 texture.type = UnsignedShortType;
20589 glType = utils.convert( texture.type );
20595 if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) {
20597 // Depth stencil textures need the DEPTH_STENCIL internal format
20598 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20599 glInternalFormat = 34041;
20601 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20602 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
20603 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20604 if ( texture.type !== UnsignedInt248Type ) {
20606 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
20608 texture.type = UnsignedInt248Type;
20609 glType = utils.convert( texture.type );
20617 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
20619 } else if ( texture.isDataTexture ) {
20621 // use manually created mipmaps if available
20622 // if there are no manual mipmaps
20623 // set 0 level mipmap and then use GL to generate other mipmap levels
20625 if ( mipmaps.length > 0 && supportsMips ) {
20627 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20629 mipmap = mipmaps[ i ];
20630 state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20634 texture.generateMipmaps = false;
20635 textureProperties.__maxMipLevel = mipmaps.length - 1;
20639 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
20640 textureProperties.__maxMipLevel = 0;
20644 } else if ( texture.isCompressedTexture ) {
20646 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20648 mipmap = mipmaps[ i ];
20650 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
20652 if ( glFormat !== null ) {
20654 state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
20658 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
20664 state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20670 textureProperties.__maxMipLevel = mipmaps.length - 1;
20672 } else if ( texture.isDataTexture2DArray ) {
20674 state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
20675 textureProperties.__maxMipLevel = 0;
20677 } else if ( texture.isDataTexture3D ) {
20679 state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
20680 textureProperties.__maxMipLevel = 0;
20684 // regular Texture (image, video, canvas)
20686 // use manually created mipmaps if available
20687 // if there are no manual mipmaps
20688 // set 0 level mipmap and then use GL to generate other mipmap levels
20690 if ( mipmaps.length > 0 && supportsMips ) {
20692 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20694 mipmap = mipmaps[ i ];
20695 state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap );
20699 texture.generateMipmaps = false;
20700 textureProperties.__maxMipLevel = mipmaps.length - 1;
20704 state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image );
20705 textureProperties.__maxMipLevel = 0;
20711 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
20713 generateMipmap( textureType, texture, image.width, image.height );
20717 textureProperties.__version = texture.version;
20719 if ( texture.onUpdate ) texture.onUpdate( texture );
20723 function uploadCubeTexture( textureProperties, texture, slot ) {
20725 if ( texture.image.length !== 6 ) return;
20727 initTexture( textureProperties, texture );
20729 state.activeTexture( 33984 + slot );
20730 state.bindTexture( 34067, textureProperties.__webglTexture );
20732 _gl.pixelStorei( 37440, texture.flipY );
20733 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
20734 _gl.pixelStorei( 3317, texture.unpackAlignment );
20736 const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) );
20737 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
20739 const cubeImage = [];
20741 for ( let i = 0; i < 6; i ++ ) {
20743 if ( ! isCompressed && ! isDataTexture ) {
20745 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
20749 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
20755 const image = cubeImage[ 0 ],
20756 supportsMips = isPowerOfTwo( image ) || isWebGL2,
20757 glFormat = utils.convert( texture.format ),
20758 glType = utils.convert( texture.type ),
20759 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
20761 setTextureParameters( 34067, texture, supportsMips );
20765 if ( isCompressed ) {
20767 for ( let i = 0; i < 6; i ++ ) {
20769 mipmaps = cubeImage[ i ].mipmaps;
20771 for ( let j = 0; j < mipmaps.length; j ++ ) {
20773 const mipmap = mipmaps[ j ];
20775 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
20777 if ( glFormat !== null ) {
20779 state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
20783 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
20789 state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20797 textureProperties.__maxMipLevel = mipmaps.length - 1;
20801 mipmaps = texture.mipmaps;
20803 for ( let i = 0; i < 6; i ++ ) {
20805 if ( isDataTexture ) {
20807 state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
20809 for ( let j = 0; j < mipmaps.length; j ++ ) {
20811 const mipmap = mipmaps[ j ];
20812 const mipmapImage = mipmap.image[ i ].image;
20814 state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
20820 state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
20822 for ( let j = 0; j < mipmaps.length; j ++ ) {
20824 const mipmap = mipmaps[ j ];
20826 state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
20834 textureProperties.__maxMipLevel = mipmaps.length;
20838 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
20840 // We assume images for cube map have the same size.
20841 generateMipmap( 34067, texture, image.width, image.height );
20845 textureProperties.__version = texture.version;
20847 if ( texture.onUpdate ) texture.onUpdate( texture );
20853 // Setup storage for target texture and bind it to correct framebuffer
20854 function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
20856 const glFormat = utils.convert( renderTarget.texture.format );
20857 const glType = utils.convert( renderTarget.texture.type );
20858 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
20859 state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
20860 _gl.bindFramebuffer( 36160, framebuffer );
20861 _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
20862 _gl.bindFramebuffer( 36160, null );
20866 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
20867 function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
20869 _gl.bindRenderbuffer( 36161, renderbuffer );
20871 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
20873 let glInternalFormat = 33189;
20875 if ( isMultisample ) {
20877 const depthTexture = renderTarget.depthTexture;
20879 if ( depthTexture && depthTexture.isDepthTexture ) {
20881 if ( depthTexture.type === FloatType ) {
20883 glInternalFormat = 36012;
20885 } else if ( depthTexture.type === UnsignedIntType ) {
20887 glInternalFormat = 33190;
20893 const samples = getRenderTargetSamples( renderTarget );
20895 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
20899 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
20903 _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
20905 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
20907 if ( isMultisample ) {
20909 const samples = getRenderTargetSamples( renderTarget );
20911 _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height );
20915 _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
20920 _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
20924 const glFormat = utils.convert( renderTarget.texture.format );
20925 const glType = utils.convert( renderTarget.texture.type );
20926 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
20928 if ( isMultisample ) {
20930 const samples = getRenderTargetSamples( renderTarget );
20932 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
20936 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
20942 _gl.bindRenderbuffer( 36161, null );
20946 // Setup resources for a Depth Texture for a FBO (needs an extension)
20947 function setupDepthTexture( framebuffer, renderTarget ) {
20949 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
20950 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
20952 _gl.bindFramebuffer( 36160, framebuffer );
20954 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
20956 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
20960 // upload an empty depth texture with framebuffer size
20961 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
20962 renderTarget.depthTexture.image.width !== renderTarget.width ||
20963 renderTarget.depthTexture.image.height !== renderTarget.height ) {
20965 renderTarget.depthTexture.image.width = renderTarget.width;
20966 renderTarget.depthTexture.image.height = renderTarget.height;
20967 renderTarget.depthTexture.needsUpdate = true;
20971 setTexture2D( renderTarget.depthTexture, 0 );
20973 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
20975 if ( renderTarget.depthTexture.format === DepthFormat ) {
20977 _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 );
20979 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
20981 _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 );
20985 throw new Error( 'Unknown depthTexture format' );
20991 // Setup GL resources for a non-texture depth buffer
20992 function setupDepthRenderbuffer( renderTarget ) {
20994 const renderTargetProperties = properties.get( renderTarget );
20996 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
20998 if ( renderTarget.depthTexture ) {
21000 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
21002 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
21008 renderTargetProperties.__webglDepthbuffer = [];
21010 for ( let i = 0; i < 6; i ++ ) {
21012 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] );
21013 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
21014 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
21020 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer );
21021 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
21022 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
21028 _gl.bindFramebuffer( 36160, null );
21032 // Set up GL resources for the render target
21033 function setupRenderTarget( renderTarget ) {
21035 const renderTargetProperties = properties.get( renderTarget );
21036 const textureProperties = properties.get( renderTarget.texture );
21038 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
21040 textureProperties.__webglTexture = _gl.createTexture();
21042 info.memory.textures ++;
21044 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
21045 const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
21046 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
21048 // Handles WebGL2 RGBFormat fallback - #18858
21050 if ( isWebGL2 && renderTarget.texture.format === RGBFormat && ( renderTarget.texture.type === FloatType || renderTarget.texture.type === HalfFloatType ) ) {
21052 renderTarget.texture.format = RGBAFormat;
21054 console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' );
21058 // Setup framebuffer
21062 renderTargetProperties.__webglFramebuffer = [];
21064 for ( let i = 0; i < 6; i ++ ) {
21066 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
21072 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
21074 if ( isMultisample ) {
21078 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
21079 renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
21081 _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
21083 const glFormat = utils.convert( renderTarget.texture.format );
21084 const glType = utils.convert( renderTarget.texture.type );
21085 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
21086 const samples = getRenderTargetSamples( renderTarget );
21087 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
21089 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
21090 _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
21091 _gl.bindRenderbuffer( 36161, null );
21093 if ( renderTarget.depthBuffer ) {
21095 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
21096 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
21100 _gl.bindFramebuffer( 36160, null );
21105 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
21113 // Setup color buffer
21117 state.bindTexture( 34067, textureProperties.__webglTexture );
21118 setTextureParameters( 34067, renderTarget.texture, supportsMips );
21120 for ( let i = 0; i < 6; i ++ ) {
21122 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i );
21126 if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
21128 generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height );
21132 state.bindTexture( 34067, null );
21136 state.bindTexture( 3553, textureProperties.__webglTexture );
21137 setTextureParameters( 3553, renderTarget.texture, supportsMips );
21138 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 );
21140 if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
21142 generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height );
21146 state.bindTexture( 3553, null );
21150 // Setup depth and stencil buffers
21152 if ( renderTarget.depthBuffer ) {
21154 setupDepthRenderbuffer( renderTarget );
21160 function updateRenderTargetMipmap( renderTarget ) {
21162 const texture = renderTarget.texture;
21163 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
21165 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
21167 const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553;
21168 const webglTexture = properties.get( texture ).__webglTexture;
21170 state.bindTexture( target, webglTexture );
21171 generateMipmap( target, texture, renderTarget.width, renderTarget.height );
21172 state.bindTexture( target, null );
21178 function updateMultisampleRenderTarget( renderTarget ) {
21180 if ( renderTarget.isWebGLMultisampleRenderTarget ) {
21184 const renderTargetProperties = properties.get( renderTarget );
21186 _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
21187 _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
21189 const width = renderTarget.width;
21190 const height = renderTarget.height;
21193 if ( renderTarget.depthBuffer ) mask |= 256;
21194 if ( renderTarget.stencilBuffer ) mask |= 1024;
21196 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
21198 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); // see #18905
21202 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
21210 function getRenderTargetSamples( renderTarget ) {
21212 return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
21213 Math.min( maxSamples, renderTarget.samples ) : 0;
21217 function updateVideoTexture( texture ) {
21219 const frame = info.render.frame;
21221 // Check the last frame we updated the VideoTexture
21223 if ( _videoTextures.get( texture ) !== frame ) {
21225 _videoTextures.set( texture, frame );
21232 // backwards compatibility
21234 let warnedTexture2D = false;
21235 let warnedTextureCube = false;
21237 function safeSetTexture2D( texture, slot ) {
21239 if ( texture && texture.isWebGLRenderTarget ) {
21241 if ( warnedTexture2D === false ) {
21243 console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' );
21244 warnedTexture2D = true;
21248 texture = texture.texture;
21252 setTexture2D( texture, slot );
21256 function safeSetTextureCube( texture, slot ) {
21258 if ( texture && texture.isWebGLCubeRenderTarget ) {
21260 if ( warnedTextureCube === false ) {
21262 console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' );
21263 warnedTextureCube = true;
21267 texture = texture.texture;
21272 setTextureCube( texture, slot );
21278 this.allocateTextureUnit = allocateTextureUnit;
21279 this.resetTextureUnits = resetTextureUnits;
21281 this.setTexture2D = setTexture2D;
21282 this.setTexture2DArray = setTexture2DArray;
21283 this.setTexture3D = setTexture3D;
21284 this.setTextureCube = setTextureCube;
21285 this.setupRenderTarget = setupRenderTarget;
21286 this.updateRenderTargetMipmap = updateRenderTargetMipmap;
21287 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
21289 this.safeSetTexture2D = safeSetTexture2D;
21290 this.safeSetTextureCube = safeSetTextureCube;
21294 function WebGLUtils( gl, extensions, capabilities ) {
21296 const isWebGL2 = capabilities.isWebGL2;
21298 function convert( p ) {
21302 if ( p === UnsignedByteType ) return 5121;
21303 if ( p === UnsignedShort4444Type ) return 32819;
21304 if ( p === UnsignedShort5551Type ) return 32820;
21305 if ( p === UnsignedShort565Type ) return 33635;
21307 if ( p === ByteType ) return 5120;
21308 if ( p === ShortType ) return 5122;
21309 if ( p === UnsignedShortType ) return 5123;
21310 if ( p === IntType ) return 5124;
21311 if ( p === UnsignedIntType ) return 5125;
21312 if ( p === FloatType ) return 5126;
21314 if ( p === HalfFloatType ) {
21316 if ( isWebGL2 ) return 5131;
21318 extension = extensions.get( 'OES_texture_half_float' );
21320 if ( extension !== null ) {
21322 return extension.HALF_FLOAT_OES;
21332 if ( p === AlphaFormat ) return 6406;
21333 if ( p === RGBFormat ) return 6407;
21334 if ( p === RGBAFormat ) return 6408;
21335 if ( p === LuminanceFormat ) return 6409;
21336 if ( p === LuminanceAlphaFormat ) return 6410;
21337 if ( p === DepthFormat ) return 6402;
21338 if ( p === DepthStencilFormat ) return 34041;
21339 if ( p === RedFormat ) return 6403;
21343 if ( p === RedIntegerFormat ) return 36244;
21344 if ( p === RGFormat ) return 33319;
21345 if ( p === RGIntegerFormat ) return 33320;
21346 if ( p === RGBIntegerFormat ) return 36248;
21347 if ( p === RGBAIntegerFormat ) return 36249;
21349 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
21350 p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
21352 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
21354 if ( extension !== null ) {
21356 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
21357 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
21358 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
21359 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
21369 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
21370 p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
21372 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
21374 if ( extension !== null ) {
21376 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
21377 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
21378 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
21379 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
21389 if ( p === RGB_ETC1_Format ) {
21391 extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
21393 if ( extension !== null ) {
21395 return extension.COMPRESSED_RGB_ETC1_WEBGL;
21405 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
21407 extension = extensions.get( 'WEBGL_compressed_texture_etc' );
21409 if ( extension !== null ) {
21411 if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2;
21412 if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC;
21418 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
21419 p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
21420 p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
21421 p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
21422 p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ||
21423 p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format ||
21424 p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format ||
21425 p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format ||
21426 p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format ||
21427 p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) {
21429 extension = extensions.get( 'WEBGL_compressed_texture_astc' );
21431 if ( extension !== null ) {
21445 if ( p === RGBA_BPTC_Format ) {
21447 extension = extensions.get( 'EXT_texture_compression_bptc' );
21449 if ( extension !== null ) {
21463 if ( p === UnsignedInt248Type ) {
21465 if ( isWebGL2 ) return 34042;
21467 extension = extensions.get( 'WEBGL_depth_texture' );
21469 if ( extension !== null ) {
21471 return extension.UNSIGNED_INT_24_8_WEBGL;
21483 return { convert: convert };
21487 function ArrayCamera( array = [] ) {
21489 PerspectiveCamera.call( this );
21491 this.cameras = array;
21495 ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
21497 constructor: ArrayCamera,
21499 isArrayCamera: true
21505 Object3D.call( this );
21507 this.type = 'Group';
21511 Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
21513 constructor: Group,
21519 function WebXRController() {
21521 this._targetRay = null;
21527 Object.assign( WebXRController.prototype, {
21529 constructor: WebXRController,
21531 getHandSpace: function () {
21533 if ( this._hand === null ) {
21535 this._hand = new Group();
21536 this._hand.matrixAutoUpdate = false;
21537 this._hand.visible = false;
21539 this._hand.joints = {};
21540 this._hand.inputState = { pinching: false };
21548 getTargetRaySpace: function () {
21550 if ( this._targetRay === null ) {
21552 this._targetRay = new Group();
21553 this._targetRay.matrixAutoUpdate = false;
21554 this._targetRay.visible = false;
21558 return this._targetRay;
21562 getGripSpace: function () {
21564 if ( this._grip === null ) {
21566 this._grip = new Group();
21567 this._grip.matrixAutoUpdate = false;
21568 this._grip.visible = false;
21576 dispatchEvent: function ( event ) {
21578 if ( this._targetRay !== null ) {
21580 this._targetRay.dispatchEvent( event );
21584 if ( this._grip !== null ) {
21586 this._grip.dispatchEvent( event );
21590 if ( this._hand !== null ) {
21592 this._hand.dispatchEvent( event );
21600 disconnect: function ( inputSource ) {
21602 this.dispatchEvent( { type: 'disconnected', data: inputSource } );
21604 if ( this._targetRay !== null ) {
21606 this._targetRay.visible = false;
21610 if ( this._grip !== null ) {
21612 this._grip.visible = false;
21616 if ( this._hand !== null ) {
21618 this._hand.visible = false;
21626 update: function ( inputSource, frame, referenceSpace ) {
21628 let inputPose = null;
21629 let gripPose = null;
21630 let handPose = null;
21632 const targetRay = this._targetRay;
21633 const grip = this._grip;
21634 const hand = this._hand;
21636 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
21638 if ( hand && inputSource.hand ) {
21642 for ( const inputjoint of inputSource.hand.values() ) {
21644 // Update the joints groups with the XRJoint poses
21645 const jointPose = frame.getJointPose( inputjoint, referenceSpace );
21647 if ( hand.joints[ inputjoint.jointName ] === undefined ) {
21649 // The transform of this joint will be updated with the joint pose on each frame
21650 const joint = new Group();
21651 joint.matrixAutoUpdate = false;
21652 joint.visible = false;
21653 hand.joints[ inputjoint.jointName ] = joint;
21659 const joint = hand.joints[ inputjoint.jointName ];
21661 if ( jointPose !== null ) {
21663 joint.matrix.fromArray( jointPose.transform.matrix );
21664 joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
21665 joint.jointRadius = jointPose.radius;
21669 joint.visible = jointPose !== null;
21676 const indexTip = hand.joints[ 'index-finger-tip' ];
21677 const thumbTip = hand.joints[ 'thumb-tip' ];
21678 const distance = indexTip.position.distanceTo( thumbTip.position );
21680 const distanceToPinch = 0.02;
21681 const threshold = 0.005;
21683 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
21685 hand.inputState.pinching = false;
21686 this.dispatchEvent( {
21688 handedness: inputSource.handedness,
21692 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
21694 hand.inputState.pinching = true;
21695 this.dispatchEvent( {
21696 type: 'pinchstart',
21697 handedness: inputSource.handedness,
21705 if ( targetRay !== null ) {
21707 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
21709 if ( inputPose !== null ) {
21711 targetRay.matrix.fromArray( inputPose.transform.matrix );
21712 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
21718 if ( grip !== null && inputSource.gripSpace ) {
21720 gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
21722 if ( gripPose !== null ) {
21724 grip.matrix.fromArray( gripPose.transform.matrix );
21725 grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
21735 if ( targetRay !== null ) {
21737 targetRay.visible = ( inputPose !== null );
21741 if ( grip !== null ) {
21743 grip.visible = ( gripPose !== null );
21747 if ( hand !== null ) {
21749 hand.visible = ( handPose !== null );
21759 function WebXRManager( renderer, gl ) {
21761 const scope = this;
21763 let session = null;
21765 let framebufferScaleFactor = 1.0;
21767 let referenceSpace = null;
21768 let referenceSpaceType = 'local-floor';
21772 const controllers = [];
21773 const inputSourcesMap = new Map();
21777 const cameraL = new PerspectiveCamera();
21778 cameraL.layers.enable( 1 );
21779 cameraL.viewport = new Vector4();
21781 const cameraR = new PerspectiveCamera();
21782 cameraR.layers.enable( 2 );
21783 cameraR.viewport = new Vector4();
21785 const cameras = [ cameraL, cameraR ];
21787 const cameraVR = new ArrayCamera();
21788 cameraVR.layers.enable( 1 );
21789 cameraVR.layers.enable( 2 );
21791 let _currentDepthNear = null;
21792 let _currentDepthFar = null;
21796 this.enabled = false;
21798 this.isPresenting = false;
21800 this.getController = function ( index ) {
21802 let controller = controllers[ index ];
21804 if ( controller === undefined ) {
21806 controller = new WebXRController();
21807 controllers[ index ] = controller;
21811 return controller.getTargetRaySpace();
21815 this.getControllerGrip = function ( index ) {
21817 let controller = controllers[ index ];
21819 if ( controller === undefined ) {
21821 controller = new WebXRController();
21822 controllers[ index ] = controller;
21826 return controller.getGripSpace();
21830 this.getHand = function ( index ) {
21832 let controller = controllers[ index ];
21834 if ( controller === undefined ) {
21836 controller = new WebXRController();
21837 controllers[ index ] = controller;
21841 return controller.getHandSpace();
21847 function onSessionEvent( event ) {
21849 const controller = inputSourcesMap.get( event.inputSource );
21851 if ( controller ) {
21853 controller.dispatchEvent( { type: event.type, data: event.inputSource } );
21859 function onSessionEnd() {
21861 inputSourcesMap.forEach( function ( controller, inputSource ) {
21863 controller.disconnect( inputSource );
21867 inputSourcesMap.clear();
21869 _currentDepthNear = null;
21870 _currentDepthFar = null;
21874 renderer.setFramebuffer( null );
21875 renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830
21878 scope.isPresenting = false;
21880 scope.dispatchEvent( { type: 'sessionend' } );
21884 this.setFramebufferScaleFactor = function ( value ) {
21886 framebufferScaleFactor = value;
21888 if ( scope.isPresenting === true ) {
21890 console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
21896 this.setReferenceSpaceType = function ( value ) {
21898 referenceSpaceType = value;
21900 if ( scope.isPresenting === true ) {
21902 console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
21908 this.getReferenceSpace = function () {
21910 return referenceSpace;
21914 this.getSession = function () {
21920 this.setSession = async function ( value ) {
21924 if ( session !== null ) {
21926 session.addEventListener( 'select', onSessionEvent );
21927 session.addEventListener( 'selectstart', onSessionEvent );
21928 session.addEventListener( 'selectend', onSessionEvent );
21929 session.addEventListener( 'squeeze', onSessionEvent );
21930 session.addEventListener( 'squeezestart', onSessionEvent );
21931 session.addEventListener( 'squeezeend', onSessionEvent );
21932 session.addEventListener( 'end', onSessionEnd );
21933 session.addEventListener( 'inputsourceschange', onInputSourcesChange );
21935 const attributes = gl.getContextAttributes();
21937 if ( attributes.xrCompatible !== true ) {
21939 await gl.makeXRCompatible();
21943 const layerInit = {
21944 antialias: attributes.antialias,
21945 alpha: attributes.alpha,
21946 depth: attributes.depth,
21947 stencil: attributes.stencil,
21948 framebufferScaleFactor: framebufferScaleFactor
21951 // eslint-disable-next-line no-undef
21952 const baseLayer = new XRWebGLLayer( session, gl, layerInit );
21954 session.updateRenderState( { baseLayer: baseLayer } );
21956 referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
21958 animation.setContext( session );
21961 scope.isPresenting = true;
21963 scope.dispatchEvent( { type: 'sessionstart' } );
21969 function onInputSourcesChange( event ) {
21971 const inputSources = session.inputSources;
21973 // Assign inputSources to available controllers
21975 for ( let i = 0; i < controllers.length; i ++ ) {
21977 inputSourcesMap.set( inputSources[ i ], controllers[ i ] );
21981 // Notify disconnected
21983 for ( let i = 0; i < event.removed.length; i ++ ) {
21985 const inputSource = event.removed[ i ];
21986 const controller = inputSourcesMap.get( inputSource );
21988 if ( controller ) {
21990 controller.dispatchEvent( { type: 'disconnected', data: inputSource } );
21991 inputSourcesMap.delete( inputSource );
21997 // Notify connected
21999 for ( let i = 0; i < event.added.length; i ++ ) {
22001 const inputSource = event.added[ i ];
22002 const controller = inputSourcesMap.get( inputSource );
22004 if ( controller ) {
22006 controller.dispatchEvent( { type: 'connected', data: inputSource } );
22016 const cameraLPos = new Vector3();
22017 const cameraRPos = new Vector3();
22020 * Assumes 2 cameras that are parallel and share an X-axis, and that
22021 * the cameras' projection and world matrices have already been set.
22022 * And that near and far planes are identical for both cameras.
22023 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
22025 function setProjectionFromUnion( camera, cameraL, cameraR ) {
22027 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
22028 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
22030 const ipd = cameraLPos.distanceTo( cameraRPos );
22032 const projL = cameraL.projectionMatrix.elements;
22033 const projR = cameraR.projectionMatrix.elements;
22035 // VR systems will have identical far and near planes, and
22036 // most likely identical top and bottom frustum extents.
22037 // Use the left camera for these values.
22038 const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
22039 const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
22040 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
22041 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
22043 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
22044 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
22045 const left = near * leftFov;
22046 const right = near * rightFov;
22048 // Calculate the new camera's position offset from the
22049 // left camera. xOffset should be roughly half `ipd`.
22050 const zOffset = ipd / ( - leftFov + rightFov );
22051 const xOffset = zOffset * - leftFov;
22053 // TODO: Better way to apply this offset?
22054 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
22055 camera.translateX( xOffset );
22056 camera.translateZ( zOffset );
22057 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
22058 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
22060 // Find the union of the frustum values of the cameras and scale
22061 // the values so that the near plane's position does not change in world space,
22062 // although must now be relative to the new union camera.
22063 const near2 = near + zOffset;
22064 const far2 = far + zOffset;
22065 const left2 = left - xOffset;
22066 const right2 = right + ( ipd - xOffset );
22067 const top2 = topFov * far / far2 * near2;
22068 const bottom2 = bottomFov * far / far2 * near2;
22070 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
22074 function updateCamera( camera, parent ) {
22076 if ( parent === null ) {
22078 camera.matrixWorld.copy( camera.matrix );
22082 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
22086 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
22090 this.getCamera = function ( camera ) {
22092 cameraVR.near = cameraR.near = cameraL.near = camera.near;
22093 cameraVR.far = cameraR.far = cameraL.far = camera.far;
22095 if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) {
22097 // Note that the new renderState won't apply until the next frame. See #18320
22099 session.updateRenderState( {
22100 depthNear: cameraVR.near,
22101 depthFar: cameraVR.far
22104 _currentDepthNear = cameraVR.near;
22105 _currentDepthFar = cameraVR.far;
22109 const parent = camera.parent;
22110 const cameras = cameraVR.cameras;
22112 updateCamera( cameraVR, parent );
22114 for ( let i = 0; i < cameras.length; i ++ ) {
22116 updateCamera( cameras[ i ], parent );
22120 // update camera and its children
22122 camera.matrixWorld.copy( cameraVR.matrixWorld );
22123 camera.matrix.copy( cameraVR.matrix );
22124 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
22126 const children = camera.children;
22128 for ( let i = 0, l = children.length; i < l; i ++ ) {
22130 children[ i ].updateMatrixWorld( true );
22134 // update projection matrix for proper view frustum culling
22136 if ( cameras.length === 2 ) {
22138 setProjectionFromUnion( cameraVR, cameraL, cameraR );
22142 // assume single camera setup (AR)
22144 cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
22154 let onAnimationFrameCallback = null;
22156 function onAnimationFrame( time, frame ) {
22158 pose = frame.getViewerPose( referenceSpace );
22160 if ( pose !== null ) {
22162 const views = pose.views;
22163 const baseLayer = session.renderState.baseLayer;
22165 renderer.setFramebuffer( baseLayer.framebuffer );
22167 let cameraVRNeedsUpdate = false;
22169 // check if it's necessary to rebuild cameraVR's camera list
22171 if ( views.length !== cameraVR.cameras.length ) {
22173 cameraVR.cameras.length = 0;
22174 cameraVRNeedsUpdate = true;
22178 for ( let i = 0; i < views.length; i ++ ) {
22180 const view = views[ i ];
22181 const viewport = baseLayer.getViewport( view );
22183 const camera = cameras[ i ];
22184 camera.matrix.fromArray( view.transform.matrix );
22185 camera.projectionMatrix.fromArray( view.projectionMatrix );
22186 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
22190 cameraVR.matrix.copy( camera.matrix );
22194 if ( cameraVRNeedsUpdate === true ) {
22196 cameraVR.cameras.push( camera );
22206 const inputSources = session.inputSources;
22208 for ( let i = 0; i < controllers.length; i ++ ) {
22210 const controller = controllers[ i ];
22211 const inputSource = inputSources[ i ];
22213 controller.update( inputSource, frame, referenceSpace );
22217 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
22221 const animation = new WebGLAnimation();
22222 animation.setAnimationLoop( onAnimationFrame );
22224 this.setAnimationLoop = function ( callback ) {
22226 onAnimationFrameCallback = callback;
22230 this.dispose = function () {};
22234 Object.assign( WebXRManager.prototype, EventDispatcher.prototype );
22236 function WebGLMaterials( properties ) {
22238 function refreshFogUniforms( uniforms, fog ) {
22240 uniforms.fogColor.value.copy( fog.color );
22244 uniforms.fogNear.value = fog.near;
22245 uniforms.fogFar.value = fog.far;
22247 } else if ( fog.isFogExp2 ) {
22249 uniforms.fogDensity.value = fog.density;
22255 function refreshMaterialUniforms( uniforms, material, pixelRatio, height ) {
22257 if ( material.isMeshBasicMaterial ) {
22259 refreshUniformsCommon( uniforms, material );
22261 } else if ( material.isMeshLambertMaterial ) {
22263 refreshUniformsCommon( uniforms, material );
22264 refreshUniformsLambert( uniforms, material );
22266 } else if ( material.isMeshToonMaterial ) {
22268 refreshUniformsCommon( uniforms, material );
22269 refreshUniformsToon( uniforms, material );
22271 } else if ( material.isMeshPhongMaterial ) {
22273 refreshUniformsCommon( uniforms, material );
22274 refreshUniformsPhong( uniforms, material );
22276 } else if ( material.isMeshStandardMaterial ) {
22278 refreshUniformsCommon( uniforms, material );
22280 if ( material.isMeshPhysicalMaterial ) {
22282 refreshUniformsPhysical( uniforms, material );
22286 refreshUniformsStandard( uniforms, material );
22290 } else if ( material.isMeshMatcapMaterial ) {
22292 refreshUniformsCommon( uniforms, material );
22293 refreshUniformsMatcap( uniforms, material );
22295 } else if ( material.isMeshDepthMaterial ) {
22297 refreshUniformsCommon( uniforms, material );
22298 refreshUniformsDepth( uniforms, material );
22300 } else if ( material.isMeshDistanceMaterial ) {
22302 refreshUniformsCommon( uniforms, material );
22303 refreshUniformsDistance( uniforms, material );
22305 } else if ( material.isMeshNormalMaterial ) {
22307 refreshUniformsCommon( uniforms, material );
22308 refreshUniformsNormal( uniforms, material );
22310 } else if ( material.isLineBasicMaterial ) {
22312 refreshUniformsLine( uniforms, material );
22314 if ( material.isLineDashedMaterial ) {
22316 refreshUniformsDash( uniforms, material );
22320 } else if ( material.isPointsMaterial ) {
22322 refreshUniformsPoints( uniforms, material, pixelRatio, height );
22324 } else if ( material.isSpriteMaterial ) {
22326 refreshUniformsSprites( uniforms, material );
22328 } else if ( material.isShadowMaterial ) {
22330 uniforms.color.value.copy( material.color );
22331 uniforms.opacity.value = material.opacity;
22333 } else if ( material.isShaderMaterial ) {
22335 material.uniformsNeedUpdate = false; // #15581
22341 function refreshUniformsCommon( uniforms, material ) {
22343 uniforms.opacity.value = material.opacity;
22345 if ( material.color ) {
22347 uniforms.diffuse.value.copy( material.color );
22351 if ( material.emissive ) {
22353 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
22357 if ( material.map ) {
22359 uniforms.map.value = material.map;
22363 if ( material.alphaMap ) {
22365 uniforms.alphaMap.value = material.alphaMap;
22369 if ( material.specularMap ) {
22371 uniforms.specularMap.value = material.specularMap;
22375 const envMap = properties.get( material ).envMap;
22379 uniforms.envMap.value = envMap;
22381 uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap._needsFlipEnvMap ) ? - 1 : 1;
22383 uniforms.reflectivity.value = material.reflectivity;
22384 uniforms.refractionRatio.value = material.refractionRatio;
22386 const maxMipLevel = properties.get( envMap ).__maxMipLevel;
22388 if ( maxMipLevel !== undefined ) {
22390 uniforms.maxMipLevel.value = maxMipLevel;
22396 if ( material.lightMap ) {
22398 uniforms.lightMap.value = material.lightMap;
22399 uniforms.lightMapIntensity.value = material.lightMapIntensity;
22403 if ( material.aoMap ) {
22405 uniforms.aoMap.value = material.aoMap;
22406 uniforms.aoMapIntensity.value = material.aoMapIntensity;
22410 // uv repeat and offset setting priorities
22413 // 3. displacementMap map
22416 // 6. roughnessMap map
22417 // 7. metalnessMap map
22419 // 9. emissiveMap map
22420 // 10. clearcoat map
22421 // 11. clearcoat normal map
22422 // 12. clearcoat roughnessMap map
22426 if ( material.map ) {
22428 uvScaleMap = material.map;
22430 } else if ( material.specularMap ) {
22432 uvScaleMap = material.specularMap;
22434 } else if ( material.displacementMap ) {
22436 uvScaleMap = material.displacementMap;
22438 } else if ( material.normalMap ) {
22440 uvScaleMap = material.normalMap;
22442 } else if ( material.bumpMap ) {
22444 uvScaleMap = material.bumpMap;
22446 } else if ( material.roughnessMap ) {
22448 uvScaleMap = material.roughnessMap;
22450 } else if ( material.metalnessMap ) {
22452 uvScaleMap = material.metalnessMap;
22454 } else if ( material.alphaMap ) {
22456 uvScaleMap = material.alphaMap;
22458 } else if ( material.emissiveMap ) {
22460 uvScaleMap = material.emissiveMap;
22462 } else if ( material.clearcoatMap ) {
22464 uvScaleMap = material.clearcoatMap;
22466 } else if ( material.clearcoatNormalMap ) {
22468 uvScaleMap = material.clearcoatNormalMap;
22470 } else if ( material.clearcoatRoughnessMap ) {
22472 uvScaleMap = material.clearcoatRoughnessMap;
22476 if ( uvScaleMap !== undefined ) {
22478 // backwards compatibility
22479 if ( uvScaleMap.isWebGLRenderTarget ) {
22481 uvScaleMap = uvScaleMap.texture;
22485 if ( uvScaleMap.matrixAutoUpdate === true ) {
22487 uvScaleMap.updateMatrix();
22491 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22495 // uv repeat and offset setting priorities for uv2
22501 if ( material.aoMap ) {
22503 uv2ScaleMap = material.aoMap;
22505 } else if ( material.lightMap ) {
22507 uv2ScaleMap = material.lightMap;
22511 if ( uv2ScaleMap !== undefined ) {
22513 // backwards compatibility
22514 if ( uv2ScaleMap.isWebGLRenderTarget ) {
22516 uv2ScaleMap = uv2ScaleMap.texture;
22520 if ( uv2ScaleMap.matrixAutoUpdate === true ) {
22522 uv2ScaleMap.updateMatrix();
22526 uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix );
22532 function refreshUniformsLine( uniforms, material ) {
22534 uniforms.diffuse.value.copy( material.color );
22535 uniforms.opacity.value = material.opacity;
22539 function refreshUniformsDash( uniforms, material ) {
22541 uniforms.dashSize.value = material.dashSize;
22542 uniforms.totalSize.value = material.dashSize + material.gapSize;
22543 uniforms.scale.value = material.scale;
22547 function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
22549 uniforms.diffuse.value.copy( material.color );
22550 uniforms.opacity.value = material.opacity;
22551 uniforms.size.value = material.size * pixelRatio;
22552 uniforms.scale.value = height * 0.5;
22554 if ( material.map ) {
22556 uniforms.map.value = material.map;
22560 if ( material.alphaMap ) {
22562 uniforms.alphaMap.value = material.alphaMap;
22566 // uv repeat and offset setting priorities
22572 if ( material.map ) {
22574 uvScaleMap = material.map;
22576 } else if ( material.alphaMap ) {
22578 uvScaleMap = material.alphaMap;
22582 if ( uvScaleMap !== undefined ) {
22584 if ( uvScaleMap.matrixAutoUpdate === true ) {
22586 uvScaleMap.updateMatrix();
22590 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22596 function refreshUniformsSprites( uniforms, material ) {
22598 uniforms.diffuse.value.copy( material.color );
22599 uniforms.opacity.value = material.opacity;
22600 uniforms.rotation.value = material.rotation;
22602 if ( material.map ) {
22604 uniforms.map.value = material.map;
22608 if ( material.alphaMap ) {
22610 uniforms.alphaMap.value = material.alphaMap;
22614 // uv repeat and offset setting priorities
22620 if ( material.map ) {
22622 uvScaleMap = material.map;
22624 } else if ( material.alphaMap ) {
22626 uvScaleMap = material.alphaMap;
22630 if ( uvScaleMap !== undefined ) {
22632 if ( uvScaleMap.matrixAutoUpdate === true ) {
22634 uvScaleMap.updateMatrix();
22638 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22644 function refreshUniformsLambert( uniforms, material ) {
22646 if ( material.emissiveMap ) {
22648 uniforms.emissiveMap.value = material.emissiveMap;
22654 function refreshUniformsPhong( uniforms, material ) {
22656 uniforms.specular.value.copy( material.specular );
22657 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
22659 if ( material.emissiveMap ) {
22661 uniforms.emissiveMap.value = material.emissiveMap;
22665 if ( material.bumpMap ) {
22667 uniforms.bumpMap.value = material.bumpMap;
22668 uniforms.bumpScale.value = material.bumpScale;
22669 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22673 if ( material.normalMap ) {
22675 uniforms.normalMap.value = material.normalMap;
22676 uniforms.normalScale.value.copy( material.normalScale );
22677 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22681 if ( material.displacementMap ) {
22683 uniforms.displacementMap.value = material.displacementMap;
22684 uniforms.displacementScale.value = material.displacementScale;
22685 uniforms.displacementBias.value = material.displacementBias;
22691 function refreshUniformsToon( uniforms, material ) {
22693 if ( material.gradientMap ) {
22695 uniforms.gradientMap.value = material.gradientMap;
22699 if ( material.emissiveMap ) {
22701 uniforms.emissiveMap.value = material.emissiveMap;
22705 if ( material.bumpMap ) {
22707 uniforms.bumpMap.value = material.bumpMap;
22708 uniforms.bumpScale.value = material.bumpScale;
22709 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22713 if ( material.normalMap ) {
22715 uniforms.normalMap.value = material.normalMap;
22716 uniforms.normalScale.value.copy( material.normalScale );
22717 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22721 if ( material.displacementMap ) {
22723 uniforms.displacementMap.value = material.displacementMap;
22724 uniforms.displacementScale.value = material.displacementScale;
22725 uniforms.displacementBias.value = material.displacementBias;
22731 function refreshUniformsStandard( uniforms, material ) {
22733 uniforms.roughness.value = material.roughness;
22734 uniforms.metalness.value = material.metalness;
22736 if ( material.roughnessMap ) {
22738 uniforms.roughnessMap.value = material.roughnessMap;
22742 if ( material.metalnessMap ) {
22744 uniforms.metalnessMap.value = material.metalnessMap;
22748 if ( material.emissiveMap ) {
22750 uniforms.emissiveMap.value = material.emissiveMap;
22754 if ( material.bumpMap ) {
22756 uniforms.bumpMap.value = material.bumpMap;
22757 uniforms.bumpScale.value = material.bumpScale;
22758 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22762 if ( material.normalMap ) {
22764 uniforms.normalMap.value = material.normalMap;
22765 uniforms.normalScale.value.copy( material.normalScale );
22766 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22770 if ( material.displacementMap ) {
22772 uniforms.displacementMap.value = material.displacementMap;
22773 uniforms.displacementScale.value = material.displacementScale;
22774 uniforms.displacementBias.value = material.displacementBias;
22778 const envMap = properties.get( material ).envMap;
22782 //uniforms.envMap.value = material.envMap; // part of uniforms common
22783 uniforms.envMapIntensity.value = material.envMapIntensity;
22789 function refreshUniformsPhysical( uniforms, material ) {
22791 refreshUniformsStandard( uniforms, material );
22793 uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common
22795 uniforms.clearcoat.value = material.clearcoat;
22796 uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
22797 if ( material.sheen ) uniforms.sheen.value.copy( material.sheen );
22799 if ( material.clearcoatMap ) {
22801 uniforms.clearcoatMap.value = material.clearcoatMap;
22805 if ( material.clearcoatRoughnessMap ) {
22807 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
22811 if ( material.clearcoatNormalMap ) {
22813 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
22814 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
22816 if ( material.side === BackSide ) {
22818 uniforms.clearcoatNormalScale.value.negate();
22824 uniforms.transmission.value = material.transmission;
22826 if ( material.transmissionMap ) {
22828 uniforms.transmissionMap.value = material.transmissionMap;
22834 function refreshUniformsMatcap( uniforms, material ) {
22836 if ( material.matcap ) {
22838 uniforms.matcap.value = material.matcap;
22842 if ( material.bumpMap ) {
22844 uniforms.bumpMap.value = material.bumpMap;
22845 uniforms.bumpScale.value = material.bumpScale;
22846 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22850 if ( material.normalMap ) {
22852 uniforms.normalMap.value = material.normalMap;
22853 uniforms.normalScale.value.copy( material.normalScale );
22854 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22858 if ( material.displacementMap ) {
22860 uniforms.displacementMap.value = material.displacementMap;
22861 uniforms.displacementScale.value = material.displacementScale;
22862 uniforms.displacementBias.value = material.displacementBias;
22868 function refreshUniformsDepth( uniforms, material ) {
22870 if ( material.displacementMap ) {
22872 uniforms.displacementMap.value = material.displacementMap;
22873 uniforms.displacementScale.value = material.displacementScale;
22874 uniforms.displacementBias.value = material.displacementBias;
22880 function refreshUniformsDistance( uniforms, material ) {
22882 if ( material.displacementMap ) {
22884 uniforms.displacementMap.value = material.displacementMap;
22885 uniforms.displacementScale.value = material.displacementScale;
22886 uniforms.displacementBias.value = material.displacementBias;
22890 uniforms.referencePosition.value.copy( material.referencePosition );
22891 uniforms.nearDistance.value = material.nearDistance;
22892 uniforms.farDistance.value = material.farDistance;
22896 function refreshUniformsNormal( uniforms, material ) {
22898 if ( material.bumpMap ) {
22900 uniforms.bumpMap.value = material.bumpMap;
22901 uniforms.bumpScale.value = material.bumpScale;
22902 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22906 if ( material.normalMap ) {
22908 uniforms.normalMap.value = material.normalMap;
22909 uniforms.normalScale.value.copy( material.normalScale );
22910 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22914 if ( material.displacementMap ) {
22916 uniforms.displacementMap.value = material.displacementMap;
22917 uniforms.displacementScale.value = material.displacementScale;
22918 uniforms.displacementBias.value = material.displacementBias;
22925 refreshFogUniforms: refreshFogUniforms,
22926 refreshMaterialUniforms: refreshMaterialUniforms
22931 function createCanvasElement() {
22933 const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
22934 canvas.style.display = 'block';
22939 function WebGLRenderer( parameters ) {
22941 parameters = parameters || {};
22943 const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(),
22944 _context = parameters.context !== undefined ? parameters.context : null,
22946 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
22947 _depth = parameters.depth !== undefined ? parameters.depth : true,
22948 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
22949 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
22950 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
22951 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
22952 _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default',
22953 _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false;
22955 let currentRenderList = null;
22956 let currentRenderState = null;
22958 // render() can be called from within a callback triggered by another render.
22959 // We track this so that the nested render call gets its state isolated from the parent render call.
22961 const renderStateStack = [];
22963 // public properties
22965 this.domElement = _canvas;
22967 // Debug configuration container
22971 * Enables error checking and reporting when shader programs are being compiled
22974 checkShaderErrors: true
22979 this.autoClear = true;
22980 this.autoClearColor = true;
22981 this.autoClearDepth = true;
22982 this.autoClearStencil = true;
22986 this.sortObjects = true;
22988 // user-defined clipping
22990 this.clippingPlanes = [];
22991 this.localClippingEnabled = false;
22993 // physically based shading
22995 this.gammaFactor = 2.0; // for backwards compatibility
22996 this.outputEncoding = LinearEncoding;
23000 this.physicallyCorrectLights = false;
23004 this.toneMapping = NoToneMapping;
23005 this.toneMappingExposure = 1.0;
23009 this.maxMorphTargets = 8;
23010 this.maxMorphNormals = 4;
23012 // internal properties
23014 const _this = this;
23016 let _isContextLost = false;
23018 // internal state cache
23020 let _framebuffer = null;
23022 let _currentActiveCubeFace = 0;
23023 let _currentActiveMipmapLevel = 0;
23024 let _currentRenderTarget = null;
23025 let _currentFramebuffer = null;
23026 let _currentMaterialId = - 1;
23028 let _currentCamera = null;
23030 const _currentViewport = new Vector4();
23031 const _currentScissor = new Vector4();
23032 let _currentScissorTest = null;
23036 let _width = _canvas.width;
23037 let _height = _canvas.height;
23039 let _pixelRatio = 1;
23040 let _opaqueSort = null;
23041 let _transparentSort = null;
23043 const _viewport = new Vector4( 0, 0, _width, _height );
23044 const _scissor = new Vector4( 0, 0, _width, _height );
23045 let _scissorTest = false;
23049 const _frustum = new Frustum();
23053 let _clippingEnabled = false;
23054 let _localClippingEnabled = false;
23056 // camera matrices cache
23058 const _projScreenMatrix = new Matrix4();
23060 const _vector3 = new Vector3();
23062 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
23064 function getTargetPixelRatio() {
23066 return _currentRenderTarget === null ? _pixelRatio : 1;
23072 let _gl = _context;
23074 function getContext( contextNames, contextAttributes ) {
23076 for ( let i = 0; i < contextNames.length; i ++ ) {
23078 const contextName = contextNames[ i ];
23079 const context = _canvas.getContext( contextName, contextAttributes );
23080 if ( context !== null ) return context;
23090 const contextAttributes = {
23094 antialias: _antialias,
23095 premultipliedAlpha: _premultipliedAlpha,
23096 preserveDrawingBuffer: _preserveDrawingBuffer,
23097 powerPreference: _powerPreference,
23098 failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat
23101 // event listeners must be registered before WebGL context is created, see #12753
23103 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
23104 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
23106 if ( _gl === null ) {
23108 const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
23110 if ( _this.isWebGL1Renderer === true ) {
23112 contextNames.shift();
23116 _gl = getContext( contextNames, contextAttributes );
23118 if ( _gl === null ) {
23120 if ( getContext( contextNames ) ) {
23122 throw new Error( 'Error creating WebGL context with your selected attributes.' );
23126 throw new Error( 'Error creating WebGL context.' );
23134 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
23136 if ( _gl.getShaderPrecisionFormat === undefined ) {
23138 _gl.getShaderPrecisionFormat = function () {
23140 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
23146 } catch ( error ) {
23148 console.error( 'THREE.WebGLRenderer: ' + error.message );
23153 let extensions, capabilities, state, info;
23154 let properties, textures, cubemaps, attributes, geometries, objects;
23155 let programCache, materials, renderLists, renderStates, clipping;
23157 let background, morphtargets, bufferRenderer, indexedBufferRenderer;
23159 let utils, bindingStates;
23161 function initGLContext() {
23163 extensions = new WebGLExtensions( _gl );
23165 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
23167 extensions.init( capabilities );
23169 utils = new WebGLUtils( _gl, extensions, capabilities );
23171 state = new WebGLState( _gl, extensions, capabilities );
23172 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
23173 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
23175 info = new WebGLInfo( _gl );
23176 properties = new WebGLProperties();
23177 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
23178 cubemaps = new WebGLCubeMaps( _this );
23179 attributes = new WebGLAttributes( _gl, capabilities );
23180 bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
23181 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
23182 objects = new WebGLObjects( _gl, geometries, attributes, info );
23183 morphtargets = new WebGLMorphtargets( _gl );
23184 clipping = new WebGLClipping( properties );
23185 programCache = new WebGLPrograms( _this, cubemaps, extensions, capabilities, bindingStates, clipping );
23186 materials = new WebGLMaterials( properties );
23187 renderLists = new WebGLRenderLists( properties );
23188 renderStates = new WebGLRenderStates( extensions, capabilities );
23189 background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha );
23191 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
23192 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
23194 info.programs = programCache.programs;
23196 _this.capabilities = capabilities;
23197 _this.extensions = extensions;
23198 _this.properties = properties;
23199 _this.renderLists = renderLists;
23200 _this.state = state;
23209 const xr = new WebXRManager( _this, _gl );
23215 const shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
23217 this.shadowMap = shadowMap;
23221 this.getContext = function () {
23227 this.getContextAttributes = function () {
23229 return _gl.getContextAttributes();
23233 this.forceContextLoss = function () {
23235 const extension = extensions.get( 'WEBGL_lose_context' );
23236 if ( extension ) extension.loseContext();
23240 this.forceContextRestore = function () {
23242 const extension = extensions.get( 'WEBGL_lose_context' );
23243 if ( extension ) extension.restoreContext();
23247 this.getPixelRatio = function () {
23249 return _pixelRatio;
23253 this.setPixelRatio = function ( value ) {
23255 if ( value === undefined ) return;
23257 _pixelRatio = value;
23259 this.setSize( _width, _height, false );
23263 this.getSize = function ( target ) {
23265 if ( target === undefined ) {
23267 console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
23269 target = new Vector2();
23273 return target.set( _width, _height );
23277 this.setSize = function ( width, height, updateStyle ) {
23279 if ( xr.isPresenting ) {
23281 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
23289 _canvas.width = Math.floor( width * _pixelRatio );
23290 _canvas.height = Math.floor( height * _pixelRatio );
23292 if ( updateStyle !== false ) {
23294 _canvas.style.width = width + 'px';
23295 _canvas.style.height = height + 'px';
23299 this.setViewport( 0, 0, width, height );
23303 this.getDrawingBufferSize = function ( target ) {
23305 if ( target === undefined ) {
23307 console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
23309 target = new Vector2();
23313 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
23317 this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
23322 _pixelRatio = pixelRatio;
23324 _canvas.width = Math.floor( width * pixelRatio );
23325 _canvas.height = Math.floor( height * pixelRatio );
23327 this.setViewport( 0, 0, width, height );
23331 this.getCurrentViewport = function ( target ) {
23333 if ( target === undefined ) {
23335 console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' );
23337 target = new Vector4();
23341 return target.copy( _currentViewport );
23345 this.getViewport = function ( target ) {
23347 return target.copy( _viewport );
23351 this.setViewport = function ( x, y, width, height ) {
23353 if ( x.isVector4 ) {
23355 _viewport.set( x.x, x.y, x.z, x.w );
23359 _viewport.set( x, y, width, height );
23363 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
23367 this.getScissor = function ( target ) {
23369 return target.copy( _scissor );
23373 this.setScissor = function ( x, y, width, height ) {
23375 if ( x.isVector4 ) {
23377 _scissor.set( x.x, x.y, x.z, x.w );
23381 _scissor.set( x, y, width, height );
23385 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
23389 this.getScissorTest = function () {
23391 return _scissorTest;
23395 this.setScissorTest = function ( boolean ) {
23397 state.setScissorTest( _scissorTest = boolean );
23401 this.setOpaqueSort = function ( method ) {
23403 _opaqueSort = method;
23407 this.setTransparentSort = function ( method ) {
23409 _transparentSort = method;
23415 this.getClearColor = function ( target ) {
23417 if ( target === undefined ) {
23419 console.warn( 'WebGLRenderer: .getClearColor() now requires a Color as an argument' );
23421 target = new Color();
23425 return target.copy( background.getClearColor() );
23429 this.setClearColor = function () {
23431 background.setClearColor.apply( background, arguments );
23435 this.getClearAlpha = function () {
23437 return background.getClearAlpha();
23441 this.setClearAlpha = function () {
23443 background.setClearAlpha.apply( background, arguments );
23447 this.clear = function ( color, depth, stencil ) {
23451 if ( color === undefined || color ) bits |= 16384;
23452 if ( depth === undefined || depth ) bits |= 256;
23453 if ( stencil === undefined || stencil ) bits |= 1024;
23459 this.clearColor = function () {
23461 this.clear( true, false, false );
23465 this.clearDepth = function () {
23467 this.clear( false, true, false );
23471 this.clearStencil = function () {
23473 this.clear( false, false, true );
23479 this.dispose = function () {
23481 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
23482 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
23484 renderLists.dispose();
23485 renderStates.dispose();
23486 properties.dispose();
23487 cubemaps.dispose();
23489 bindingStates.dispose();
23499 function onContextLost( event ) {
23501 event.preventDefault();
23503 console.log( 'THREE.WebGLRenderer: Context Lost.' );
23505 _isContextLost = true;
23509 function onContextRestore( /* event */ ) {
23511 console.log( 'THREE.WebGLRenderer: Context Restored.' );
23513 _isContextLost = false;
23519 function onMaterialDispose( event ) {
23521 const material = event.target;
23523 material.removeEventListener( 'dispose', onMaterialDispose );
23525 deallocateMaterial( material );
23529 // Buffer deallocation
23531 function deallocateMaterial( material ) {
23533 releaseMaterialProgramReference( material );
23535 properties.remove( material );
23540 function releaseMaterialProgramReference( material ) {
23542 const programInfo = properties.get( material ).program;
23544 if ( programInfo !== undefined ) {
23546 programCache.releaseProgram( programInfo );
23552 // Buffer rendering
23554 function renderObjectImmediate( object, program ) {
23556 object.render( function ( object ) {
23558 _this.renderBufferImmediate( object, program );
23564 this.renderBufferImmediate = function ( object, program ) {
23566 bindingStates.initAttributes();
23568 const buffers = properties.get( object );
23570 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
23571 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
23572 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
23573 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
23575 const programAttributes = program.getAttributes();
23577 if ( object.hasPositions ) {
23579 _gl.bindBuffer( 34962, buffers.position );
23580 _gl.bufferData( 34962, object.positionArray, 35048 );
23582 bindingStates.enableAttribute( programAttributes.position );
23583 _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 );
23587 if ( object.hasNormals ) {
23589 _gl.bindBuffer( 34962, buffers.normal );
23590 _gl.bufferData( 34962, object.normalArray, 35048 );
23592 bindingStates.enableAttribute( programAttributes.normal );
23593 _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 );
23597 if ( object.hasUvs ) {
23599 _gl.bindBuffer( 34962, buffers.uv );
23600 _gl.bufferData( 34962, object.uvArray, 35048 );
23602 bindingStates.enableAttribute( programAttributes.uv );
23603 _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 );
23607 if ( object.hasColors ) {
23609 _gl.bindBuffer( 34962, buffers.color );
23610 _gl.bufferData( 34962, object.colorArray, 35048 );
23612 bindingStates.enableAttribute( programAttributes.color );
23613 _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 );
23617 bindingStates.disableUnusedAttributes();
23619 _gl.drawArrays( 4, 0, object.count );
23625 this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
23627 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
23629 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
23631 const program = setProgram( camera, scene, material, object );
23633 state.setMaterial( material, frontFaceCW );
23637 let index = geometry.index;
23638 const position = geometry.attributes.position;
23642 if ( index === null ) {
23644 if ( position === undefined || position.count === 0 ) return;
23646 } else if ( index.count === 0 ) {
23654 let rangeFactor = 1;
23656 if ( material.wireframe === true ) {
23658 index = geometries.getWireframeAttribute( geometry );
23663 if ( material.morphTargets || material.morphNormals ) {
23665 morphtargets.update( object, geometry, material, program );
23669 bindingStates.setup( object, material, program, geometry, index );
23672 let renderer = bufferRenderer;
23674 if ( index !== null ) {
23676 attribute = attributes.get( index );
23678 renderer = indexedBufferRenderer;
23679 renderer.setIndex( attribute );
23685 const dataCount = ( index !== null ) ? index.count : position.count;
23687 const rangeStart = geometry.drawRange.start * rangeFactor;
23688 const rangeCount = geometry.drawRange.count * rangeFactor;
23690 const groupStart = group !== null ? group.start * rangeFactor : 0;
23691 const groupCount = group !== null ? group.count * rangeFactor : Infinity;
23693 const drawStart = Math.max( rangeStart, groupStart );
23694 const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
23696 const drawCount = Math.max( 0, drawEnd - drawStart + 1 );
23698 if ( drawCount === 0 ) return;
23702 if ( object.isMesh ) {
23704 if ( material.wireframe === true ) {
23706 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
23707 renderer.setMode( 1 );
23711 renderer.setMode( 4 );
23715 } else if ( object.isLine ) {
23717 let lineWidth = material.linewidth;
23719 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
23721 state.setLineWidth( lineWidth * getTargetPixelRatio() );
23723 if ( object.isLineSegments ) {
23725 renderer.setMode( 1 );
23727 } else if ( object.isLineLoop ) {
23729 renderer.setMode( 2 );
23733 renderer.setMode( 3 );
23737 } else if ( object.isPoints ) {
23739 renderer.setMode( 0 );
23741 } else if ( object.isSprite ) {
23743 renderer.setMode( 4 );
23747 if ( object.isInstancedMesh ) {
23749 renderer.renderInstances( drawStart, drawCount, object.count );
23751 } else if ( geometry.isInstancedBufferGeometry ) {
23753 const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
23755 renderer.renderInstances( drawStart, drawCount, instanceCount );
23759 renderer.render( drawStart, drawCount );
23767 this.compile = function ( scene, camera ) {
23769 currentRenderState = renderStates.get( scene );
23770 currentRenderState.init();
23772 scene.traverseVisible( function ( object ) {
23774 if ( object.isLight && object.layers.test( camera.layers ) ) {
23776 currentRenderState.pushLight( object );
23778 if ( object.castShadow ) {
23780 currentRenderState.pushShadow( object );
23788 currentRenderState.setupLights();
23790 const compiled = new WeakMap();
23792 scene.traverse( function ( object ) {
23794 const material = object.material;
23798 if ( Array.isArray( material ) ) {
23800 for ( let i = 0; i < material.length; i ++ ) {
23802 const material2 = material[ i ];
23804 if ( compiled.has( material2 ) === false ) {
23806 initMaterial( material2, scene, object );
23807 compiled.set( material2 );
23813 } else if ( compiled.has( material ) === false ) {
23815 initMaterial( material, scene, object );
23816 compiled.set( material );
23828 let onAnimationFrameCallback = null;
23830 function onAnimationFrame( time ) {
23832 if ( xr.isPresenting ) return;
23833 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
23837 const animation = new WebGLAnimation();
23838 animation.setAnimationLoop( onAnimationFrame );
23840 if ( typeof window !== 'undefined' ) animation.setContext( window );
23842 this.setAnimationLoop = function ( callback ) {
23844 onAnimationFrameCallback = callback;
23845 xr.setAnimationLoop( callback );
23847 ( callback === null ) ? animation.stop() : animation.start();
23853 this.render = function ( scene, camera ) {
23855 let renderTarget, forceClear;
23857 if ( arguments[ 2 ] !== undefined ) {
23859 console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' );
23860 renderTarget = arguments[ 2 ];
23864 if ( arguments[ 3 ] !== undefined ) {
23866 console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' );
23867 forceClear = arguments[ 3 ];
23871 if ( camera !== undefined && camera.isCamera !== true ) {
23873 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
23878 if ( _isContextLost === true ) return;
23880 // reset caching for this frame
23882 bindingStates.resetDefaultState();
23883 _currentMaterialId = - 1;
23884 _currentCamera = null;
23886 // update scene graph
23888 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
23890 // update camera matrices and frustum
23892 if ( camera.parent === null ) camera.updateMatrixWorld();
23894 if ( xr.enabled === true && xr.isPresenting === true ) {
23896 camera = xr.getCamera( camera );
23901 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );
23903 currentRenderState = renderStates.get( scene, renderStateStack.length );
23904 currentRenderState.init();
23906 renderStateStack.push( currentRenderState );
23908 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
23909 _frustum.setFromProjectionMatrix( _projScreenMatrix );
23911 _localClippingEnabled = this.localClippingEnabled;
23912 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
23914 currentRenderList = renderLists.get( scene, camera );
23915 currentRenderList.init();
23917 projectObject( scene, camera, 0, _this.sortObjects );
23919 currentRenderList.finish();
23921 if ( _this.sortObjects === true ) {
23923 currentRenderList.sort( _opaqueSort, _transparentSort );
23929 if ( _clippingEnabled === true ) clipping.beginShadows();
23931 const shadowsArray = currentRenderState.state.shadowsArray;
23933 shadowMap.render( shadowsArray, scene, camera );
23935 currentRenderState.setupLights();
23936 currentRenderState.setupLightsView( camera );
23938 if ( _clippingEnabled === true ) clipping.endShadows();
23942 if ( this.info.autoReset === true ) this.info.reset();
23944 if ( renderTarget !== undefined ) {
23946 this.setRenderTarget( renderTarget );
23952 background.render( currentRenderList, scene, camera, forceClear );
23956 const opaqueObjects = currentRenderList.opaque;
23957 const transparentObjects = currentRenderList.transparent;
23959 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
23960 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
23964 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
23968 if ( _currentRenderTarget !== null ) {
23970 // Generate mipmap if we're using any kind of mipmap filtering
23972 textures.updateRenderTargetMipmap( _currentRenderTarget );
23974 // resolve multisample renderbuffers to a single-sample texture if necessary
23976 textures.updateMultisampleRenderTarget( _currentRenderTarget );
23980 // Ensure depth buffer writing is enabled so it can be cleared on next render
23982 state.buffers.depth.setTest( true );
23983 state.buffers.depth.setMask( true );
23984 state.buffers.color.setMask( true );
23986 state.setPolygonOffset( false );
23990 renderStateStack.pop();
23991 if ( renderStateStack.length > 0 ) {
23993 currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
23997 currentRenderState = null;
24001 currentRenderList = null;
24005 function projectObject( object, camera, groupOrder, sortObjects ) {
24007 if ( object.visible === false ) return;
24009 const visible = object.layers.test( camera.layers );
24013 if ( object.isGroup ) {
24015 groupOrder = object.renderOrder;
24017 } else if ( object.isLOD ) {
24019 if ( object.autoUpdate === true ) object.update( camera );
24021 } else if ( object.isLight ) {
24023 currentRenderState.pushLight( object );
24025 if ( object.castShadow ) {
24027 currentRenderState.pushShadow( object );
24031 } else if ( object.isSprite ) {
24033 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
24035 if ( sortObjects ) {
24037 _vector3.setFromMatrixPosition( object.matrixWorld )
24038 .applyMatrix4( _projScreenMatrix );
24042 const geometry = objects.update( object );
24043 const material = object.material;
24045 if ( material.visible ) {
24047 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
24053 } else if ( object.isImmediateRenderObject ) {
24055 if ( sortObjects ) {
24057 _vector3.setFromMatrixPosition( object.matrixWorld )
24058 .applyMatrix4( _projScreenMatrix );
24062 currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null );
24064 } else if ( object.isMesh || object.isLine || object.isPoints ) {
24066 if ( object.isSkinnedMesh ) {
24068 // update skeleton only once in a frame
24070 if ( object.skeleton.frame !== info.render.frame ) {
24072 object.skeleton.update();
24073 object.skeleton.frame = info.render.frame;
24079 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
24081 if ( sortObjects ) {
24083 _vector3.setFromMatrixPosition( object.matrixWorld )
24084 .applyMatrix4( _projScreenMatrix );
24088 const geometry = objects.update( object );
24089 const material = object.material;
24091 if ( Array.isArray( material ) ) {
24093 const groups = geometry.groups;
24095 for ( let i = 0, l = groups.length; i < l; i ++ ) {
24097 const group = groups[ i ];
24098 const groupMaterial = material[ group.materialIndex ];
24100 if ( groupMaterial && groupMaterial.visible ) {
24102 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
24108 } else if ( material.visible ) {
24110 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
24120 const children = object.children;
24122 for ( let i = 0, l = children.length; i < l; i ++ ) {
24124 projectObject( children[ i ], camera, groupOrder, sortObjects );
24130 function renderObjects( renderList, scene, camera ) {
24132 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
24134 for ( let i = 0, l = renderList.length; i < l; i ++ ) {
24136 const renderItem = renderList[ i ];
24138 const object = renderItem.object;
24139 const geometry = renderItem.geometry;
24140 const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
24141 const group = renderItem.group;
24143 if ( camera.isArrayCamera ) {
24145 const cameras = camera.cameras;
24147 for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
24149 const camera2 = cameras[ j ];
24151 if ( object.layers.test( camera2.layers ) ) {
24153 state.viewport( _currentViewport.copy( camera2.viewport ) );
24155 currentRenderState.setupLightsView( camera2 );
24157 renderObject( object, scene, camera2, geometry, material, group );
24165 renderObject( object, scene, camera, geometry, material, group );
24173 function renderObject( object, scene, camera, geometry, material, group ) {
24175 object.onBeforeRender( _this, scene, camera, geometry, material, group );
24177 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
24178 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
24180 if ( object.isImmediateRenderObject ) {
24182 const program = setProgram( camera, scene, material, object );
24184 state.setMaterial( material );
24186 bindingStates.reset();
24188 renderObjectImmediate( object, program );
24192 _this.renderBufferDirect( camera, scene, geometry, material, object, group );
24196 object.onAfterRender( _this, scene, camera, geometry, material, group );
24200 function initMaterial( material, scene, object ) {
24202 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
24204 const materialProperties = properties.get( material );
24206 const lights = currentRenderState.state.lights;
24207 const shadowsArray = currentRenderState.state.shadowsArray;
24209 const lightsStateVersion = lights.state.version;
24211 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
24212 const programCacheKey = programCache.getProgramCacheKey( parameters );
24214 let program = materialProperties.program;
24215 let programChange = true;
24217 // always update environment and fog - changing these trigger an initMaterial call, but it's possible that the program doesn't change
24219 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
24220 materialProperties.fog = scene.fog;
24221 materialProperties.envMap = cubemaps.get( material.envMap || materialProperties.environment );
24223 if ( program === undefined ) {
24226 material.addEventListener( 'dispose', onMaterialDispose );
24228 } else if ( program.cacheKey !== programCacheKey ) {
24230 // changed glsl or parameters
24231 releaseMaterialProgramReference( material );
24233 } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) {
24235 programChange = false;
24237 } else if ( parameters.shaderID !== undefined ) {
24239 // same glsl and uniform list
24244 // only rebuild uniform list
24245 programChange = false;
24249 if ( programChange ) {
24251 parameters.uniforms = programCache.getUniforms( material );
24253 material.onBeforeCompile( parameters, _this );
24255 program = programCache.acquireProgram( parameters, programCacheKey );
24257 materialProperties.program = program;
24258 materialProperties.uniforms = parameters.uniforms;
24259 materialProperties.outputEncoding = parameters.outputEncoding;
24263 const uniforms = materialProperties.uniforms;
24265 if ( ! material.isShaderMaterial &&
24266 ! material.isRawShaderMaterial ||
24267 material.clipping === true ) {
24269 materialProperties.numClippingPlanes = clipping.numPlanes;
24270 materialProperties.numIntersection = clipping.numIntersection;
24271 uniforms.clippingPlanes = clipping.uniform;
24275 // store the light setup it was created for
24277 materialProperties.needsLights = materialNeedsLights( material );
24278 materialProperties.lightsStateVersion = lightsStateVersion;
24280 if ( materialProperties.needsLights ) {
24282 // wire up the material to this renderer's lighting state
24284 uniforms.ambientLightColor.value = lights.state.ambient;
24285 uniforms.lightProbe.value = lights.state.probe;
24286 uniforms.directionalLights.value = lights.state.directional;
24287 uniforms.directionalLightShadows.value = lights.state.directionalShadow;
24288 uniforms.spotLights.value = lights.state.spot;
24289 uniforms.spotLightShadows.value = lights.state.spotShadow;
24290 uniforms.rectAreaLights.value = lights.state.rectArea;
24291 uniforms.ltc_1.value = lights.state.rectAreaLTC1;
24292 uniforms.ltc_2.value = lights.state.rectAreaLTC2;
24293 uniforms.pointLights.value = lights.state.point;
24294 uniforms.pointLightShadows.value = lights.state.pointShadow;
24295 uniforms.hemisphereLights.value = lights.state.hemi;
24297 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
24298 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
24299 uniforms.spotShadowMap.value = lights.state.spotShadowMap;
24300 uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
24301 uniforms.pointShadowMap.value = lights.state.pointShadowMap;
24302 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
24303 // TODO (abelnation): add area lights shadow info to uniforms
24307 const progUniforms = materialProperties.program.getUniforms();
24308 const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
24310 materialProperties.uniformsList = uniformsList;
24314 function setProgram( camera, scene, material, object ) {
24316 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
24318 textures.resetTextureUnits();
24320 const fog = scene.fog;
24321 const environment = material.isMeshStandardMaterial ? scene.environment : null;
24322 const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
24323 const envMap = cubemaps.get( material.envMap || environment );
24325 const materialProperties = properties.get( material );
24326 const lights = currentRenderState.state.lights;
24328 if ( _clippingEnabled === true ) {
24330 if ( _localClippingEnabled === true || camera !== _currentCamera ) {
24333 camera === _currentCamera &&
24334 material.id === _currentMaterialId;
24336 // we might want to call this function with some ClippingGroup
24337 // object instead of the material, once it becomes feasible
24339 clipping.setState( material, camera, useCache );
24345 if ( material.version === materialProperties.__version ) {
24347 if ( material.fog && materialProperties.fog !== fog ) {
24349 initMaterial( material, scene, object );
24351 } else if ( materialProperties.environment !== environment ) {
24353 initMaterial( material, scene, object );
24355 } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
24357 initMaterial( material, scene, object );
24359 } else if ( materialProperties.numClippingPlanes !== undefined &&
24360 ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
24361 materialProperties.numIntersection !== clipping.numIntersection ) ) {
24363 initMaterial( material, scene, object );
24365 } else if ( materialProperties.outputEncoding !== encoding ) {
24367 initMaterial( material, scene, object );
24369 } else if ( materialProperties.envMap !== envMap ) {
24371 initMaterial( material, scene, object );
24377 initMaterial( material, scene, object );
24378 materialProperties.__version = material.version;
24382 let refreshProgram = false;
24383 let refreshMaterial = false;
24384 let refreshLights = false;
24386 const program = materialProperties.program,
24387 p_uniforms = program.getUniforms(),
24388 m_uniforms = materialProperties.uniforms;
24390 if ( state.useProgram( program.program ) ) {
24392 refreshProgram = true;
24393 refreshMaterial = true;
24394 refreshLights = true;
24398 if ( material.id !== _currentMaterialId ) {
24400 _currentMaterialId = material.id;
24402 refreshMaterial = true;
24406 if ( refreshProgram || _currentCamera !== camera ) {
24408 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
24410 if ( capabilities.logarithmicDepthBuffer ) {
24412 p_uniforms.setValue( _gl, 'logDepthBufFC',
24413 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
24417 if ( _currentCamera !== camera ) {
24419 _currentCamera = camera;
24421 // lighting uniforms depend on the camera so enforce an update
24422 // now, in case this material supports lights - or later, when
24423 // the next material that does gets activated:
24425 refreshMaterial = true; // set to true on material change
24426 refreshLights = true; // remains set until update done
24430 // load material specific uniforms
24431 // (shader material also gets them for the sake of genericity)
24433 if ( material.isShaderMaterial ||
24434 material.isMeshPhongMaterial ||
24435 material.isMeshToonMaterial ||
24436 material.isMeshStandardMaterial ||
24437 material.envMap ) {
24439 const uCamPos = p_uniforms.map.cameraPosition;
24441 if ( uCamPos !== undefined ) {
24443 uCamPos.setValue( _gl,
24444 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
24450 if ( material.isMeshPhongMaterial ||
24451 material.isMeshToonMaterial ||
24452 material.isMeshLambertMaterial ||
24453 material.isMeshBasicMaterial ||
24454 material.isMeshStandardMaterial ||
24455 material.isShaderMaterial ) {
24457 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
24461 if ( material.isMeshPhongMaterial ||
24462 material.isMeshToonMaterial ||
24463 material.isMeshLambertMaterial ||
24464 material.isMeshBasicMaterial ||
24465 material.isMeshStandardMaterial ||
24466 material.isShaderMaterial ||
24467 material.isShadowMaterial ||
24468 material.skinning ) {
24470 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
24476 // skinning uniforms must be set even if material didn't change
24477 // auto-setting of texture unit for bone texture must go before other textures
24478 // otherwise textures used for skinning can take over texture units reserved for other material textures
24480 if ( material.skinning ) {
24482 p_uniforms.setOptional( _gl, object, 'bindMatrix' );
24483 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
24485 const skeleton = object.skeleton;
24489 const bones = skeleton.bones;
24491 if ( capabilities.floatVertexTextures ) {
24493 if ( skeleton.boneTexture === null ) {
24495 // layout (1 matrix = 4 pixels)
24496 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
24497 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
24498 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
24499 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
24500 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
24503 let size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
24504 size = MathUtils.ceilPowerOfTwo( size );
24505 size = Math.max( size, 4 );
24507 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
24508 boneMatrices.set( skeleton.boneMatrices ); // copy current values
24510 const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
24512 skeleton.boneMatrices = boneMatrices;
24513 skeleton.boneTexture = boneTexture;
24514 skeleton.boneTextureSize = size;
24518 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
24519 p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
24523 p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
24531 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
24533 materialProperties.receiveShadow = object.receiveShadow;
24534 p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
24538 if ( refreshMaterial ) {
24540 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
24542 if ( materialProperties.needsLights ) {
24544 // the current material requires lighting info
24546 // note: all lighting uniforms are always set correctly
24547 // they simply reference the renderer's state for their
24550 // use the current material's .needsUpdate flags to set
24551 // the GL state when required
24553 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
24557 // refresh uniforms common to several materials
24559 if ( fog && material.fog ) {
24561 materials.refreshFogUniforms( m_uniforms, fog );
24565 materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height );
24567 WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
24571 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
24573 WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
24574 material.uniformsNeedUpdate = false;
24578 if ( material.isSpriteMaterial ) {
24580 p_uniforms.setValue( _gl, 'center', object.center );
24586 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
24587 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
24588 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
24594 // If uniforms are marked as clean, they don't need to be loaded to the GPU.
24596 function markUniformsLightsNeedsUpdate( uniforms, value ) {
24598 uniforms.ambientLightColor.needsUpdate = value;
24599 uniforms.lightProbe.needsUpdate = value;
24601 uniforms.directionalLights.needsUpdate = value;
24602 uniforms.directionalLightShadows.needsUpdate = value;
24603 uniforms.pointLights.needsUpdate = value;
24604 uniforms.pointLightShadows.needsUpdate = value;
24605 uniforms.spotLights.needsUpdate = value;
24606 uniforms.spotLightShadows.needsUpdate = value;
24607 uniforms.rectAreaLights.needsUpdate = value;
24608 uniforms.hemisphereLights.needsUpdate = value;
24612 function materialNeedsLights( material ) {
24614 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
24615 material.isMeshStandardMaterial || material.isShadowMaterial ||
24616 ( material.isShaderMaterial && material.lights === true );
24621 this.setFramebuffer = function ( value ) {
24623 if ( _framebuffer !== value && _currentRenderTarget === null ) _gl.bindFramebuffer( 36160, value );
24625 _framebuffer = value;
24629 this.getActiveCubeFace = function () {
24631 return _currentActiveCubeFace;
24635 this.getActiveMipmapLevel = function () {
24637 return _currentActiveMipmapLevel;
24641 this.getRenderList = function () {
24643 return currentRenderList;
24647 this.setRenderList = function ( renderList ) {
24649 currentRenderList = renderList;
24653 this.getRenderTarget = function () {
24655 return _currentRenderTarget;
24659 this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
24661 _currentRenderTarget = renderTarget;
24662 _currentActiveCubeFace = activeCubeFace;
24663 _currentActiveMipmapLevel = activeMipmapLevel;
24665 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
24667 textures.setupRenderTarget( renderTarget );
24671 let framebuffer = _framebuffer;
24672 let isCube = false;
24674 if ( renderTarget ) {
24676 const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
24678 if ( renderTarget.isWebGLCubeRenderTarget ) {
24680 framebuffer = __webglFramebuffer[ activeCubeFace ];
24683 } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
24685 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
24689 framebuffer = __webglFramebuffer;
24693 _currentViewport.copy( renderTarget.viewport );
24694 _currentScissor.copy( renderTarget.scissor );
24695 _currentScissorTest = renderTarget.scissorTest;
24699 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
24700 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
24701 _currentScissorTest = _scissorTest;
24705 if ( _currentFramebuffer !== framebuffer ) {
24707 _gl.bindFramebuffer( 36160, framebuffer );
24708 _currentFramebuffer = framebuffer;
24712 state.viewport( _currentViewport );
24713 state.scissor( _currentScissor );
24714 state.setScissorTest( _currentScissorTest );
24718 const textureProperties = properties.get( renderTarget.texture );
24719 _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
24725 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
24727 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
24729 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
24734 let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
24736 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
24738 framebuffer = framebuffer[ activeCubeFaceIndex ];
24742 if ( framebuffer ) {
24744 let restore = false;
24746 if ( framebuffer !== _currentFramebuffer ) {
24748 _gl.bindFramebuffer( 36160, framebuffer );
24756 const texture = renderTarget.texture;
24757 const textureFormat = texture.format;
24758 const textureType = texture.type;
24760 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) {
24762 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
24767 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
24769 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513)
24770 ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
24771 ! halfFloatSupportedByExt ) {
24773 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
24778 if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) {
24780 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
24782 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
24784 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
24790 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
24798 _gl.bindFramebuffer( 36160, _currentFramebuffer );
24808 this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
24810 const levelScale = Math.pow( 2, - level );
24811 const width = Math.floor( texture.image.width * levelScale );
24812 const height = Math.floor( texture.image.height * levelScale );
24813 const glFormat = utils.convert( texture.format );
24815 textures.setTexture2D( texture, 0 );
24817 _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 );
24819 state.unbindTexture();
24823 this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
24825 const width = srcTexture.image.width;
24826 const height = srcTexture.image.height;
24827 const glFormat = utils.convert( dstTexture.format );
24828 const glType = utils.convert( dstTexture.type );
24830 textures.setTexture2D( dstTexture, 0 );
24832 // As another texture upload may have changed pixelStorei
24833 // parameters, make sure they are correct for the dstTexture
24834 _gl.pixelStorei( 37440, dstTexture.flipY );
24835 _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
24836 _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
24838 if ( srcTexture.isDataTexture ) {
24840 _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
24844 if ( srcTexture.isCompressedTexture ) {
24846 _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
24850 _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image );
24856 // Generate mipmaps only when copying level 0
24857 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 );
24859 state.unbindTexture();
24863 this.initTexture = function ( texture ) {
24865 textures.setTexture2D( texture, 0 );
24867 state.unbindTexture();
24871 this.resetState = function () {
24874 bindingStates.reset();
24878 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
24880 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
24886 function WebGL1Renderer( parameters ) {
24888 WebGLRenderer.call( this, parameters );
24892 WebGL1Renderer.prototype = Object.assign( Object.create( WebGLRenderer.prototype ), {
24894 constructor: WebGL1Renderer,
24896 isWebGL1Renderer: true
24902 constructor( color, density ) {
24904 Object.defineProperty( this, 'isFogExp2', { value: true } );
24908 this.color = new Color( color );
24909 this.density = ( density !== undefined ) ? density : 0.00025;
24915 return new FogExp2( this.color, this.density );
24919 toJSON( /* meta */ ) {
24923 color: this.color.getHex(),
24924 density: this.density
24933 constructor( color, near, far ) {
24935 Object.defineProperty( this, 'isFog', { value: true } );
24939 this.color = new Color( color );
24941 this.near = ( near !== undefined ) ? near : 1;
24942 this.far = ( far !== undefined ) ? far : 1000;
24948 return new Fog( this.color, this.near, this.far );
24952 toJSON( /* meta */ ) {
24956 color: this.color.getHex(),
24965 class Scene extends Object3D {
24971 Object.defineProperty( this, 'isScene', { value: true } );
24973 this.type = 'Scene';
24975 this.background = null;
24976 this.environment = null;
24979 this.overrideMaterial = null;
24981 this.autoUpdate = true; // checked by the renderer
24983 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
24985 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
24991 copy( source, recursive ) {
24993 super.copy( source, recursive );
24995 if ( source.background !== null ) this.background = source.background.clone();
24996 if ( source.environment !== null ) this.environment = source.environment.clone();
24997 if ( source.fog !== null ) this.fog = source.fog.clone();
24999 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
25001 this.autoUpdate = source.autoUpdate;
25002 this.matrixAutoUpdate = source.matrixAutoUpdate;
25010 const data = super.toJSON( meta );
25012 if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
25013 if ( this.environment !== null ) data.object.environment = this.environment.toJSON( meta );
25014 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
25022 function InterleavedBuffer( array, stride ) {
25024 this.array = array;
25025 this.stride = stride;
25026 this.count = array !== undefined ? array.length / stride : 0;
25028 this.usage = StaticDrawUsage;
25029 this.updateRange = { offset: 0, count: - 1 };
25033 this.uuid = MathUtils.generateUUID();
25037 Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
25039 set: function ( value ) {
25041 if ( value === true ) this.version ++;
25047 Object.assign( InterleavedBuffer.prototype, {
25049 isInterleavedBuffer: true,
25051 onUploadCallback: function () {},
25053 setUsage: function ( value ) {
25055 this.usage = value;
25061 copy: function ( source ) {
25063 this.array = new source.array.constructor( source.array );
25064 this.count = source.count;
25065 this.stride = source.stride;
25066 this.usage = source.usage;
25072 copyAt: function ( index1, attribute, index2 ) {
25074 index1 *= this.stride;
25075 index2 *= attribute.stride;
25077 for ( let i = 0, l = this.stride; i < l; i ++ ) {
25079 this.array[ index1 + i ] = attribute.array[ index2 + i ];
25087 set: function ( value, offset = 0 ) {
25089 this.array.set( value, offset );
25095 clone: function ( data ) {
25097 if ( data.arrayBuffers === undefined ) {
25099 data.arrayBuffers = {};
25103 if ( this.array.buffer._uuid === undefined ) {
25105 this.array.buffer._uuid = MathUtils.generateUUID();
25109 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
25111 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
25115 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
25117 const ib = new InterleavedBuffer( array, this.stride );
25118 ib.setUsage( this.usage );
25124 onUpload: function ( callback ) {
25126 this.onUploadCallback = callback;
25132 toJSON: function ( data ) {
25134 if ( data.arrayBuffers === undefined ) {
25136 data.arrayBuffers = {};
25140 // generate UUID for array buffer if necessary
25142 if ( this.array.buffer._uuid === undefined ) {
25144 this.array.buffer._uuid = MathUtils.generateUUID();
25148 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
25150 data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) );
25158 buffer: this.array.buffer._uuid,
25159 type: this.array.constructor.name,
25160 stride: this.stride
25167 const _vector$6 = new Vector3();
25169 function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
25173 this.data = interleavedBuffer;
25174 this.itemSize = itemSize;
25175 this.offset = offset;
25177 this.normalized = normalized === true;
25181 Object.defineProperties( InterleavedBufferAttribute.prototype, {
25187 return this.data.count;
25197 return this.data.array;
25205 set: function ( value ) {
25207 this.data.needsUpdate = value;
25215 Object.assign( InterleavedBufferAttribute.prototype, {
25217 isInterleavedBufferAttribute: true,
25219 applyMatrix4: function ( m ) {
25221 for ( let i = 0, l = this.data.count; i < l; i ++ ) {
25223 _vector$6.x = this.getX( i );
25224 _vector$6.y = this.getY( i );
25225 _vector$6.z = this.getZ( i );
25227 _vector$6.applyMatrix4( m );
25229 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
25237 setX: function ( index, x ) {
25239 this.data.array[ index * this.data.stride + this.offset ] = x;
25245 setY: function ( index, y ) {
25247 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
25253 setZ: function ( index, z ) {
25255 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
25261 setW: function ( index, w ) {
25263 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
25269 getX: function ( index ) {
25271 return this.data.array[ index * this.data.stride + this.offset ];
25275 getY: function ( index ) {
25277 return this.data.array[ index * this.data.stride + this.offset + 1 ];
25281 getZ: function ( index ) {
25283 return this.data.array[ index * this.data.stride + this.offset + 2 ];
25287 getW: function ( index ) {
25289 return this.data.array[ index * this.data.stride + this.offset + 3 ];
25293 setXY: function ( index, x, y ) {
25295 index = index * this.data.stride + this.offset;
25297 this.data.array[ index + 0 ] = x;
25298 this.data.array[ index + 1 ] = y;
25304 setXYZ: function ( index, x, y, z ) {
25306 index = index * this.data.stride + this.offset;
25308 this.data.array[ index + 0 ] = x;
25309 this.data.array[ index + 1 ] = y;
25310 this.data.array[ index + 2 ] = z;
25316 setXYZW: function ( index, x, y, z, w ) {
25318 index = index * this.data.stride + this.offset;
25320 this.data.array[ index + 0 ] = x;
25321 this.data.array[ index + 1 ] = y;
25322 this.data.array[ index + 2 ] = z;
25323 this.data.array[ index + 3 ] = w;
25329 clone: function ( data ) {
25331 if ( data === undefined ) {
25333 console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' );
25337 for ( let i = 0; i < this.count; i ++ ) {
25339 const index = i * this.data.stride + this.offset;
25341 for ( let j = 0; j < this.itemSize; j ++ ) {
25343 array.push( this.data.array[ index + j ] );
25349 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
25353 if ( data.interleavedBuffers === undefined ) {
25355 data.interleavedBuffers = {};
25359 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
25361 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
25365 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
25371 toJSON: function ( data ) {
25373 if ( data === undefined ) {
25375 console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' );
25379 for ( let i = 0; i < this.count; i ++ ) {
25381 const index = i * this.data.stride + this.offset;
25383 for ( let j = 0; j < this.itemSize; j ++ ) {
25385 array.push( this.data.array[ index + j ] );
25391 // deinterleave data and save it as an ordinary buffer attribute for now
25394 itemSize: this.itemSize,
25395 type: this.array.constructor.name,
25397 normalized: this.normalized
25402 // save as true interlaved attribtue
25404 if ( data.interleavedBuffers === undefined ) {
25406 data.interleavedBuffers = {};
25410 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
25412 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
25417 isInterleavedBufferAttribute: true,
25418 itemSize: this.itemSize,
25419 data: this.data.uuid,
25420 offset: this.offset,
25421 normalized: this.normalized
25433 * map: new THREE.Texture( <Image> ),
25434 * alphaMap: new THREE.Texture( <Image> ),
25435 * rotation: <float>,
25436 * sizeAttenuation: <bool>
25440 function SpriteMaterial( parameters ) {
25442 Material.call( this );
25444 this.type = 'SpriteMaterial';
25446 this.color = new Color( 0xffffff );
25450 this.alphaMap = null;
25454 this.sizeAttenuation = true;
25456 this.transparent = true;
25458 this.setValues( parameters );
25462 SpriteMaterial.prototype = Object.create( Material.prototype );
25463 SpriteMaterial.prototype.constructor = SpriteMaterial;
25464 SpriteMaterial.prototype.isSpriteMaterial = true;
25466 SpriteMaterial.prototype.copy = function ( source ) {
25468 Material.prototype.copy.call( this, source );
25470 this.color.copy( source.color );
25472 this.map = source.map;
25474 this.alphaMap = source.alphaMap;
25476 this.rotation = source.rotation;
25478 this.sizeAttenuation = source.sizeAttenuation;
25486 const _intersectPoint = new Vector3();
25487 const _worldScale = new Vector3();
25488 const _mvPosition = new Vector3();
25490 const _alignedPosition = new Vector2();
25491 const _rotatedPosition = new Vector2();
25492 const _viewWorldMatrix = new Matrix4();
25494 const _vA$1 = new Vector3();
25495 const _vB$1 = new Vector3();
25496 const _vC$1 = new Vector3();
25498 const _uvA$1 = new Vector2();
25499 const _uvB$1 = new Vector2();
25500 const _uvC$1 = new Vector2();
25502 function Sprite( material ) {
25504 Object3D.call( this );
25506 this.type = 'Sprite';
25508 if ( _geometry === undefined ) {
25510 _geometry = new BufferGeometry();
25512 const float32Array = new Float32Array( [
25513 - 0.5, - 0.5, 0, 0, 0,
25514 0.5, - 0.5, 0, 1, 0,
25516 - 0.5, 0.5, 0, 0, 1
25519 const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
25521 _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
25522 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
25523 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
25527 this.geometry = _geometry;
25528 this.material = ( material !== undefined ) ? material : new SpriteMaterial();
25530 this.center = new Vector2( 0.5, 0.5 );
25534 Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
25536 constructor: Sprite,
25540 raycast: function ( raycaster, intersects ) {
25542 if ( raycaster.camera === null ) {
25544 console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
25548 _worldScale.setFromMatrixScale( this.matrixWorld );
25550 _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
25551 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
25553 _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
25555 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
25557 _worldScale.multiplyScalar( - _mvPosition.z );
25561 const rotation = this.material.rotation;
25564 if ( rotation !== 0 ) {
25566 cos = Math.cos( rotation );
25567 sin = Math.sin( rotation );
25571 const center = this.center;
25573 transformVertex( _vA$1.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25574 transformVertex( _vB$1.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25575 transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25577 _uvA$1.set( 0, 0 );
25578 _uvB$1.set( 1, 0 );
25579 _uvC$1.set( 1, 1 );
25581 // check first triangle
25582 let intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint );
25584 if ( intersect === null ) {
25586 // check second triangle
25587 transformVertex( _vB$1.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25588 _uvB$1.set( 0, 1 );
25590 intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint );
25591 if ( intersect === null ) {
25599 const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
25601 if ( distance < raycaster.near || distance > raycaster.far ) return;
25605 distance: distance,
25606 point: _intersectPoint.clone(),
25607 uv: Triangle.getUV( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ),
25615 copy: function ( source ) {
25617 Object3D.prototype.copy.call( this, source );
25619 if ( source.center !== undefined ) this.center.copy( source.center );
25621 this.material = source.material;
25629 function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
25631 // compute position in camera space
25632 _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
25634 // to check if rotation is not zero
25635 if ( sin !== undefined ) {
25637 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
25638 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
25642 _rotatedPosition.copy( _alignedPosition );
25647 vertexPosition.copy( mvPosition );
25648 vertexPosition.x += _rotatedPosition.x;
25649 vertexPosition.y += _rotatedPosition.y;
25651 // transform to world space
25652 vertexPosition.applyMatrix4( _viewWorldMatrix );
25656 const _v1$4 = new Vector3();
25657 const _v2$2 = new Vector3();
25661 Object3D.call( this );
25663 this._currentLevel = 0;
25667 Object.defineProperties( this, {
25674 this.autoUpdate = true;
25678 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
25684 copy: function ( source ) {
25686 Object3D.prototype.copy.call( this, source, false );
25688 const levels = source.levels;
25690 for ( let i = 0, l = levels.length; i < l; i ++ ) {
25692 const level = levels[ i ];
25694 this.addLevel( level.object.clone(), level.distance );
25698 this.autoUpdate = source.autoUpdate;
25704 addLevel: function ( object, distance = 0 ) {
25706 distance = Math.abs( distance );
25708 const levels = this.levels;
25712 for ( l = 0; l < levels.length; l ++ ) {
25714 if ( distance < levels[ l ].distance ) {
25722 levels.splice( l, 0, { distance: distance, object: object } );
25724 this.add( object );
25730 getCurrentLevel: function () {
25732 return this._currentLevel;
25736 getObjectForDistance: function ( distance ) {
25738 const levels = this.levels;
25740 if ( levels.length > 0 ) {
25744 for ( i = 1, l = levels.length; i < l; i ++ ) {
25746 if ( distance < levels[ i ].distance ) {
25754 return levels[ i - 1 ].object;
25762 raycast: function ( raycaster, intersects ) {
25764 const levels = this.levels;
25766 if ( levels.length > 0 ) {
25768 _v1$4.setFromMatrixPosition( this.matrixWorld );
25770 const distance = raycaster.ray.origin.distanceTo( _v1$4 );
25772 this.getObjectForDistance( distance ).raycast( raycaster, intersects );
25778 update: function ( camera ) {
25780 const levels = this.levels;
25782 if ( levels.length > 1 ) {
25784 _v1$4.setFromMatrixPosition( camera.matrixWorld );
25785 _v2$2.setFromMatrixPosition( this.matrixWorld );
25787 const distance = _v1$4.distanceTo( _v2$2 ) / camera.zoom;
25789 levels[ 0 ].object.visible = true;
25793 for ( i = 1, l = levels.length; i < l; i ++ ) {
25795 if ( distance >= levels[ i ].distance ) {
25797 levels[ i - 1 ].object.visible = false;
25798 levels[ i ].object.visible = true;
25808 this._currentLevel = i - 1;
25810 for ( ; i < l; i ++ ) {
25812 levels[ i ].object.visible = false;
25820 toJSON: function ( meta ) {
25822 const data = Object3D.prototype.toJSON.call( this, meta );
25824 if ( this.autoUpdate === false ) data.object.autoUpdate = false;
25826 data.object.levels = [];
25828 const levels = this.levels;
25830 for ( let i = 0, l = levels.length; i < l; i ++ ) {
25832 const level = levels[ i ];
25834 data.object.levels.push( {
25835 object: level.object.uuid,
25836 distance: level.distance
25847 const _basePosition = new Vector3();
25849 const _skinIndex = new Vector4();
25850 const _skinWeight = new Vector4();
25852 const _vector$7 = new Vector3();
25853 const _matrix$1 = new Matrix4();
25855 function SkinnedMesh( geometry, material ) {
25857 if ( geometry && geometry.isGeometry ) {
25859 console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
25863 Mesh.call( this, geometry, material );
25865 this.type = 'SkinnedMesh';
25867 this.bindMode = 'attached';
25868 this.bindMatrix = new Matrix4();
25869 this.bindMatrixInverse = new Matrix4();
25873 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
25875 constructor: SkinnedMesh,
25877 isSkinnedMesh: true,
25879 copy: function ( source ) {
25881 Mesh.prototype.copy.call( this, source );
25883 this.bindMode = source.bindMode;
25884 this.bindMatrix.copy( source.bindMatrix );
25885 this.bindMatrixInverse.copy( source.bindMatrixInverse );
25887 this.skeleton = source.skeleton;
25893 bind: function ( skeleton, bindMatrix ) {
25895 this.skeleton = skeleton;
25897 if ( bindMatrix === undefined ) {
25899 this.updateMatrixWorld( true );
25901 this.skeleton.calculateInverses();
25903 bindMatrix = this.matrixWorld;
25907 this.bindMatrix.copy( bindMatrix );
25908 this.bindMatrixInverse.copy( bindMatrix ).invert();
25912 pose: function () {
25914 this.skeleton.pose();
25918 normalizeSkinWeights: function () {
25920 const vector = new Vector4();
25922 const skinWeight = this.geometry.attributes.skinWeight;
25924 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
25926 vector.x = skinWeight.getX( i );
25927 vector.y = skinWeight.getY( i );
25928 vector.z = skinWeight.getZ( i );
25929 vector.w = skinWeight.getW( i );
25931 const scale = 1.0 / vector.manhattanLength();
25933 if ( scale !== Infinity ) {
25935 vector.multiplyScalar( scale );
25939 vector.set( 1, 0, 0, 0 ); // do something reasonable
25943 skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
25949 updateMatrixWorld: function ( force ) {
25951 Mesh.prototype.updateMatrixWorld.call( this, force );
25953 if ( this.bindMode === 'attached' ) {
25955 this.bindMatrixInverse.copy( this.matrixWorld ).invert();
25957 } else if ( this.bindMode === 'detached' ) {
25959 this.bindMatrixInverse.copy( this.bindMatrix ).invert();
25963 console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
25969 boneTransform: function ( index, target ) {
25971 const skeleton = this.skeleton;
25972 const geometry = this.geometry;
25974 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
25975 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
25977 _basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
25979 target.set( 0, 0, 0 );
25981 for ( let i = 0; i < 4; i ++ ) {
25983 const weight = _skinWeight.getComponent( i );
25985 if ( weight !== 0 ) {
25987 const boneIndex = _skinIndex.getComponent( i );
25989 _matrix$1.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
25991 target.addScaledVector( _vector$7.copy( _basePosition ).applyMatrix4( _matrix$1 ), weight );
25997 return target.applyMatrix4( this.bindMatrixInverse );
26005 Object3D.call( this );
26007 this.type = 'Bone';
26011 Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
26019 const _offsetMatrix = new Matrix4();
26020 const _identityMatrix = new Matrix4();
26022 function Skeleton( bones = [], boneInverses = [] ) {
26024 this.uuid = MathUtils.generateUUID();
26026 this.bones = bones.slice( 0 );
26027 this.boneInverses = boneInverses;
26028 this.boneMatrices = null;
26030 this.boneTexture = null;
26031 this.boneTextureSize = 0;
26039 Object.assign( Skeleton.prototype, {
26041 init: function () {
26043 const bones = this.bones;
26044 const boneInverses = this.boneInverses;
26046 this.boneMatrices = new Float32Array( bones.length * 16 );
26048 // calculate inverse bone matrices if necessary
26050 if ( boneInverses.length === 0 ) {
26052 this.calculateInverses();
26056 // handle special case
26058 if ( bones.length !== boneInverses.length ) {
26060 console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
26062 this.boneInverses = [];
26064 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26066 this.boneInverses.push( new Matrix4() );
26076 calculateInverses: function () {
26078 this.boneInverses.length = 0;
26080 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26082 const inverse = new Matrix4();
26084 if ( this.bones[ i ] ) {
26086 inverse.copy( this.bones[ i ].matrixWorld ).invert();
26090 this.boneInverses.push( inverse );
26096 pose: function () {
26098 // recover the bind-time world matrices
26100 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26102 const bone = this.bones[ i ];
26106 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
26112 // compute the local matrices, positions, rotations and scales
26114 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26116 const bone = this.bones[ i ];
26120 if ( bone.parent && bone.parent.isBone ) {
26122 bone.matrix.copy( bone.parent.matrixWorld ).invert();
26123 bone.matrix.multiply( bone.matrixWorld );
26127 bone.matrix.copy( bone.matrixWorld );
26131 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
26139 update: function () {
26141 const bones = this.bones;
26142 const boneInverses = this.boneInverses;
26143 const boneMatrices = this.boneMatrices;
26144 const boneTexture = this.boneTexture;
26146 // flatten bone matrices to array
26148 for ( let i = 0, il = bones.length; i < il; i ++ ) {
26150 // compute the offset between the current and the original transform
26152 const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix;
26154 _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
26155 _offsetMatrix.toArray( boneMatrices, i * 16 );
26159 if ( boneTexture !== null ) {
26161 boneTexture.needsUpdate = true;
26167 clone: function () {
26169 return new Skeleton( this.bones, this.boneInverses );
26173 getBoneByName: function ( name ) {
26175 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26177 const bone = this.bones[ i ];
26179 if ( bone.name === name ) {
26191 dispose: function ( ) {
26193 if ( this.boneTexture !== null ) {
26195 this.boneTexture.dispose();
26197 this.boneTexture = null;
26203 fromJSON: function ( json, bones ) {
26205 this.uuid = json.uuid;
26207 for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
26209 const uuid = json.bones[ i ];
26210 let bone = bones[ uuid ];
26212 if ( bone === undefined ) {
26214 console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
26219 this.bones.push( bone );
26220 this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
26230 toJSON: function () {
26236 generator: 'Skeleton.toJSON'
26242 data.uuid = this.uuid;
26244 const bones = this.bones;
26245 const boneInverses = this.boneInverses;
26247 for ( let i = 0, l = bones.length; i < l; i ++ ) {
26249 const bone = bones[ i ];
26250 data.bones.push( bone.uuid );
26252 const boneInverse = boneInverses[ i ];
26253 data.boneInverses.push( boneInverse.toArray() );
26263 const _instanceLocalMatrix = new Matrix4();
26264 const _instanceWorldMatrix = new Matrix4();
26266 const _instanceIntersects = [];
26268 const _mesh = new Mesh();
26270 function InstancedMesh( geometry, material, count ) {
26272 Mesh.call( this, geometry, material );
26274 this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
26275 this.instanceColor = null;
26277 this.count = count;
26279 this.frustumCulled = false;
26283 InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
26285 constructor: InstancedMesh,
26287 isInstancedMesh: true,
26289 copy: function ( source ) {
26291 Mesh.prototype.copy.call( this, source );
26293 this.instanceMatrix.copy( source.instanceMatrix );
26295 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
26297 this.count = source.count;
26303 getColorAt: function ( index, color ) {
26305 color.fromArray( this.instanceColor.array, index * 3 );
26309 getMatrixAt: function ( index, matrix ) {
26311 matrix.fromArray( this.instanceMatrix.array, index * 16 );
26315 raycast: function ( raycaster, intersects ) {
26317 const matrixWorld = this.matrixWorld;
26318 const raycastTimes = this.count;
26320 _mesh.geometry = this.geometry;
26321 _mesh.material = this.material;
26323 if ( _mesh.material === undefined ) return;
26325 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
26327 // calculate the world matrix for each instance
26329 this.getMatrixAt( instanceId, _instanceLocalMatrix );
26331 _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
26333 // the mesh represents this single instance
26335 _mesh.matrixWorld = _instanceWorldMatrix;
26337 _mesh.raycast( raycaster, _instanceIntersects );
26339 // process the result of raycast
26341 for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
26343 const intersect = _instanceIntersects[ i ];
26344 intersect.instanceId = instanceId;
26345 intersect.object = this;
26346 intersects.push( intersect );
26350 _instanceIntersects.length = 0;
26356 setColorAt: function ( index, color ) {
26358 if ( this.instanceColor === null ) {
26360 this.instanceColor = new BufferAttribute( new Float32Array( this.count * 3 ), 3 );
26364 color.toArray( this.instanceColor.array, index * 3 );
26368 setMatrixAt: function ( index, matrix ) {
26370 matrix.toArray( this.instanceMatrix.array, index * 16 );
26374 updateMorphTargets: function () {
26378 dispose: function () {
26380 this.dispatchEvent( { type: 'dispose' } );
26389 * opacity: <float>,
26391 * linewidth: <float>,
26392 * linecap: "round",
26393 * linejoin: "round"
26397 function LineBasicMaterial( parameters ) {
26399 Material.call( this );
26401 this.type = 'LineBasicMaterial';
26403 this.color = new Color( 0xffffff );
26405 this.linewidth = 1;
26406 this.linecap = 'round';
26407 this.linejoin = 'round';
26409 this.morphTargets = false;
26411 this.setValues( parameters );
26415 LineBasicMaterial.prototype = Object.create( Material.prototype );
26416 LineBasicMaterial.prototype.constructor = LineBasicMaterial;
26418 LineBasicMaterial.prototype.isLineBasicMaterial = true;
26420 LineBasicMaterial.prototype.copy = function ( source ) {
26422 Material.prototype.copy.call( this, source );
26424 this.color.copy( source.color );
26426 this.linewidth = source.linewidth;
26427 this.linecap = source.linecap;
26428 this.linejoin = source.linejoin;
26430 this.morphTargets = source.morphTargets;
26436 const _start = new Vector3();
26437 const _end = new Vector3();
26438 const _inverseMatrix$1 = new Matrix4();
26439 const _ray$1 = new Ray();
26440 const _sphere$2 = new Sphere();
26442 function Line( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
26444 Object3D.call( this );
26446 this.type = 'Line';
26448 this.geometry = geometry;
26449 this.material = material;
26451 this.updateMorphTargets();
26455 Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
26461 copy: function ( source ) {
26463 Object3D.prototype.copy.call( this, source );
26465 this.material = source.material;
26466 this.geometry = source.geometry;
26472 computeLineDistances: function () {
26474 const geometry = this.geometry;
26476 if ( geometry.isBufferGeometry ) {
26478 // we assume non-indexed geometry
26480 if ( geometry.index === null ) {
26482 const positionAttribute = geometry.attributes.position;
26483 const lineDistances = [ 0 ];
26485 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
26487 _start.fromBufferAttribute( positionAttribute, i - 1 );
26488 _end.fromBufferAttribute( positionAttribute, i );
26490 lineDistances[ i ] = lineDistances[ i - 1 ];
26491 lineDistances[ i ] += _start.distanceTo( _end );
26495 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
26499 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
26503 } else if ( geometry.isGeometry ) {
26505 console.error( 'THREE.Line.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
26513 raycast: function ( raycaster, intersects ) {
26515 const geometry = this.geometry;
26516 const matrixWorld = this.matrixWorld;
26517 const threshold = raycaster.params.Line.threshold;
26519 // Checking boundingSphere distance to ray
26521 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
26523 _sphere$2.copy( geometry.boundingSphere );
26524 _sphere$2.applyMatrix4( matrixWorld );
26525 _sphere$2.radius += threshold;
26527 if ( raycaster.ray.intersectsSphere( _sphere$2 ) === false ) return;
26531 _inverseMatrix$1.copy( matrixWorld ).invert();
26532 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
26534 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
26535 const localThresholdSq = localThreshold * localThreshold;
26537 const vStart = new Vector3();
26538 const vEnd = new Vector3();
26539 const interSegment = new Vector3();
26540 const interRay = new Vector3();
26541 const step = this.isLineSegments ? 2 : 1;
26543 if ( geometry.isBufferGeometry ) {
26545 const index = geometry.index;
26546 const attributes = geometry.attributes;
26547 const positionAttribute = attributes.position;
26549 if ( index !== null ) {
26551 const indices = index.array;
26553 for ( let i = 0, l = indices.length - 1; i < l; i += step ) {
26555 const a = indices[ i ];
26556 const b = indices[ i + 1 ];
26558 vStart.fromBufferAttribute( positionAttribute, a );
26559 vEnd.fromBufferAttribute( positionAttribute, b );
26561 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
26563 if ( distSq > localThresholdSq ) continue;
26565 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
26567 const distance = raycaster.ray.origin.distanceTo( interRay );
26569 if ( distance < raycaster.near || distance > raycaster.far ) continue;
26573 distance: distance,
26574 // What do we want? intersection point on the ray or on the segment??
26575 // point: raycaster.ray.at( distance ),
26576 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
26588 for ( let i = 0, l = positionAttribute.count - 1; i < l; i += step ) {
26590 vStart.fromBufferAttribute( positionAttribute, i );
26591 vEnd.fromBufferAttribute( positionAttribute, i + 1 );
26593 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
26595 if ( distSq > localThresholdSq ) continue;
26597 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
26599 const distance = raycaster.ray.origin.distanceTo( interRay );
26601 if ( distance < raycaster.near || distance > raycaster.far ) continue;
26605 distance: distance,
26606 // What do we want? intersection point on the ray or on the segment??
26607 // point: raycaster.ray.at( distance ),
26608 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
26620 } else if ( geometry.isGeometry ) {
26622 console.error( 'THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
26628 updateMorphTargets: function () {
26630 const geometry = this.geometry;
26632 if ( geometry.isBufferGeometry ) {
26634 const morphAttributes = geometry.morphAttributes;
26635 const keys = Object.keys( morphAttributes );
26637 if ( keys.length > 0 ) {
26639 const morphAttribute = morphAttributes[ keys[ 0 ] ];
26641 if ( morphAttribute !== undefined ) {
26643 this.morphTargetInfluences = [];
26644 this.morphTargetDictionary = {};
26646 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
26648 const name = morphAttribute[ m ].name || String( m );
26650 this.morphTargetInfluences.push( 0 );
26651 this.morphTargetDictionary[ name ] = m;
26661 const morphTargets = geometry.morphTargets;
26663 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
26665 console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
26675 const _start$1 = new Vector3();
26676 const _end$1 = new Vector3();
26678 function LineSegments( geometry, material ) {
26680 Line.call( this, geometry, material );
26682 this.type = 'LineSegments';
26686 LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
26688 constructor: LineSegments,
26690 isLineSegments: true,
26692 computeLineDistances: function () {
26694 const geometry = this.geometry;
26696 if ( geometry.isBufferGeometry ) {
26698 // we assume non-indexed geometry
26700 if ( geometry.index === null ) {
26702 const positionAttribute = geometry.attributes.position;
26703 const lineDistances = [];
26705 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
26707 _start$1.fromBufferAttribute( positionAttribute, i );
26708 _end$1.fromBufferAttribute( positionAttribute, i + 1 );
26710 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
26711 lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
26715 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
26719 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
26723 } else if ( geometry.isGeometry ) {
26725 console.error( 'THREE.LineSegments.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
26735 function LineLoop( geometry, material ) {
26737 Line.call( this, geometry, material );
26739 this.type = 'LineLoop';
26743 LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
26745 constructor: LineLoop,
26754 * opacity: <float>,
26755 * map: new THREE.Texture( <Image> ),
26756 * alphaMap: new THREE.Texture( <Image> ),
26759 * sizeAttenuation: <bool>
26761 * morphTargets: <bool>
26765 function PointsMaterial( parameters ) {
26767 Material.call( this );
26769 this.type = 'PointsMaterial';
26771 this.color = new Color( 0xffffff );
26775 this.alphaMap = null;
26778 this.sizeAttenuation = true;
26780 this.morphTargets = false;
26782 this.setValues( parameters );
26786 PointsMaterial.prototype = Object.create( Material.prototype );
26787 PointsMaterial.prototype.constructor = PointsMaterial;
26789 PointsMaterial.prototype.isPointsMaterial = true;
26791 PointsMaterial.prototype.copy = function ( source ) {
26793 Material.prototype.copy.call( this, source );
26795 this.color.copy( source.color );
26797 this.map = source.map;
26799 this.alphaMap = source.alphaMap;
26801 this.size = source.size;
26802 this.sizeAttenuation = source.sizeAttenuation;
26804 this.morphTargets = source.morphTargets;
26810 const _inverseMatrix$2 = new Matrix4();
26811 const _ray$2 = new Ray();
26812 const _sphere$3 = new Sphere();
26813 const _position$1 = new Vector3();
26815 function Points( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
26817 Object3D.call( this );
26819 this.type = 'Points';
26821 this.geometry = geometry;
26822 this.material = material;
26824 this.updateMorphTargets();
26828 Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
26830 constructor: Points,
26834 copy: function ( source ) {
26836 Object3D.prototype.copy.call( this, source );
26838 this.material = source.material;
26839 this.geometry = source.geometry;
26845 raycast: function ( raycaster, intersects ) {
26847 const geometry = this.geometry;
26848 const matrixWorld = this.matrixWorld;
26849 const threshold = raycaster.params.Points.threshold;
26851 // Checking boundingSphere distance to ray
26853 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
26855 _sphere$3.copy( geometry.boundingSphere );
26856 _sphere$3.applyMatrix4( matrixWorld );
26857 _sphere$3.radius += threshold;
26859 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
26863 _inverseMatrix$2.copy( matrixWorld ).invert();
26864 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
26866 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
26867 const localThresholdSq = localThreshold * localThreshold;
26869 if ( geometry.isBufferGeometry ) {
26871 const index = geometry.index;
26872 const attributes = geometry.attributes;
26873 const positionAttribute = attributes.position;
26875 if ( index !== null ) {
26877 const indices = index.array;
26879 for ( let i = 0, il = indices.length; i < il; i ++ ) {
26881 const a = indices[ i ];
26883 _position$1.fromBufferAttribute( positionAttribute, a );
26885 testPoint( _position$1, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
26891 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
26893 _position$1.fromBufferAttribute( positionAttribute, i );
26895 testPoint( _position$1, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
26903 console.error( 'THREE.Points.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
26909 updateMorphTargets: function () {
26911 const geometry = this.geometry;
26913 if ( geometry.isBufferGeometry ) {
26915 const morphAttributes = geometry.morphAttributes;
26916 const keys = Object.keys( morphAttributes );
26918 if ( keys.length > 0 ) {
26920 const morphAttribute = morphAttributes[ keys[ 0 ] ];
26922 if ( morphAttribute !== undefined ) {
26924 this.morphTargetInfluences = [];
26925 this.morphTargetDictionary = {};
26927 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
26929 const name = morphAttribute[ m ].name || String( m );
26931 this.morphTargetInfluences.push( 0 );
26932 this.morphTargetDictionary[ name ] = m;
26942 const morphTargets = geometry.morphTargets;
26944 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
26946 console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
26956 function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
26958 const rayPointDistanceSq = _ray$2.distanceSqToPoint( point );
26960 if ( rayPointDistanceSq < localThresholdSq ) {
26962 const intersectPoint = new Vector3();
26964 _ray$2.closestPointToPoint( point, intersectPoint );
26965 intersectPoint.applyMatrix4( matrixWorld );
26967 const distance = raycaster.ray.origin.distanceTo( intersectPoint );
26969 if ( distance < raycaster.near || distance > raycaster.far ) return;
26973 distance: distance,
26974 distanceToRay: Math.sqrt( rayPointDistanceSq ),
26975 point: intersectPoint,
26986 function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
26988 Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
26990 this.format = format !== undefined ? format : RGBFormat;
26992 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
26993 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
26995 this.generateMipmaps = false;
26997 const scope = this;
26999 function updateVideo() {
27001 scope.needsUpdate = true;
27002 video.requestVideoFrameCallback( updateVideo );
27006 if ( 'requestVideoFrameCallback' in video ) {
27008 video.requestVideoFrameCallback( updateVideo );
27014 VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), {
27016 constructor: VideoTexture,
27018 clone: function () {
27020 return new this.constructor( this.image ).copy( this );
27024 isVideoTexture: true,
27026 update: function () {
27028 const video = this.image;
27029 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
27031 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
27033 this.needsUpdate = true;
27041 function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
27043 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
27045 this.image = { width: width, height: height };
27046 this.mipmaps = mipmaps;
27048 // no flipping for cube textures
27049 // (also flipping doesn't work for compressed textures )
27051 this.flipY = false;
27053 // can't generate mipmaps for compressed textures
27054 // mips must be embedded in DDS files
27056 this.generateMipmaps = false;
27060 CompressedTexture.prototype = Object.create( Texture.prototype );
27061 CompressedTexture.prototype.constructor = CompressedTexture;
27063 CompressedTexture.prototype.isCompressedTexture = true;
27065 function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
27067 Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
27069 this.needsUpdate = true;
27073 CanvasTexture.prototype = Object.create( Texture.prototype );
27074 CanvasTexture.prototype.constructor = CanvasTexture;
27075 CanvasTexture.prototype.isCanvasTexture = true;
27077 function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
27079 format = format !== undefined ? format : DepthFormat;
27081 if ( format !== DepthFormat && format !== DepthStencilFormat ) {
27083 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
27087 if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
27088 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
27090 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
27092 this.image = { width: width, height: height };
27094 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
27095 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
27097 this.flipY = false;
27098 this.generateMipmaps = false;
27102 DepthTexture.prototype = Object.create( Texture.prototype );
27103 DepthTexture.prototype.constructor = DepthTexture;
27104 DepthTexture.prototype.isDepthTexture = true;
27106 class CircleGeometry extends BufferGeometry {
27108 constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) {
27112 this.type = 'CircleGeometry';
27114 this.parameters = {
27116 segments: segments,
27117 thetaStart: thetaStart,
27118 thetaLength: thetaLength
27121 segments = Math.max( 3, segments );
27125 const indices = [];
27126 const vertices = [];
27127 const normals = [];
27130 // helper variables
27132 const vertex = new Vector3();
27133 const uv = new Vector2();
27137 vertices.push( 0, 0, 0 );
27138 normals.push( 0, 0, 1 );
27139 uvs.push( 0.5, 0.5 );
27141 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
27143 const segment = thetaStart + s / segments * thetaLength;
27147 vertex.x = radius * Math.cos( segment );
27148 vertex.y = radius * Math.sin( segment );
27150 vertices.push( vertex.x, vertex.y, vertex.z );
27154 normals.push( 0, 0, 1 );
27158 uv.x = ( vertices[ i ] / radius + 1 ) / 2;
27159 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
27161 uvs.push( uv.x, uv.y );
27167 for ( let i = 1; i <= segments; i ++ ) {
27169 indices.push( i, i + 1, 0 );
27175 this.setIndex( indices );
27176 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
27177 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
27178 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
27184 class CylinderGeometry extends BufferGeometry {
27186 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
27189 this.type = 'CylinderGeometry';
27191 this.parameters = {
27192 radiusTop: radiusTop,
27193 radiusBottom: radiusBottom,
27195 radialSegments: radialSegments,
27196 heightSegments: heightSegments,
27197 openEnded: openEnded,
27198 thetaStart: thetaStart,
27199 thetaLength: thetaLength
27202 const scope = this;
27204 radialSegments = Math.floor( radialSegments );
27205 heightSegments = Math.floor( heightSegments );
27209 const indices = [];
27210 const vertices = [];
27211 const normals = [];
27214 // helper variables
27217 const indexArray = [];
27218 const halfHeight = height / 2;
27219 let groupStart = 0;
27221 // generate geometry
27225 if ( openEnded === false ) {
27227 if ( radiusTop > 0 ) generateCap( true );
27228 if ( radiusBottom > 0 ) generateCap( false );
27234 this.setIndex( indices );
27235 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
27236 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
27237 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
27239 function generateTorso() {
27241 const normal = new Vector3();
27242 const vertex = new Vector3();
27244 let groupCount = 0;
27246 // this will be used to calculate the normal
27247 const slope = ( radiusBottom - radiusTop ) / height;
27249 // generate vertices, normals and uvs
27251 for ( let y = 0; y <= heightSegments; y ++ ) {
27253 const indexRow = [];
27255 const v = y / heightSegments;
27257 // calculate the radius of the current row
27259 const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
27261 for ( let x = 0; x <= radialSegments; x ++ ) {
27263 const u = x / radialSegments;
27265 const theta = u * thetaLength + thetaStart;
27267 const sinTheta = Math.sin( theta );
27268 const cosTheta = Math.cos( theta );
27272 vertex.x = radius * sinTheta;
27273 vertex.y = - v * height + halfHeight;
27274 vertex.z = radius * cosTheta;
27275 vertices.push( vertex.x, vertex.y, vertex.z );
27279 normal.set( sinTheta, slope, cosTheta ).normalize();
27280 normals.push( normal.x, normal.y, normal.z );
27284 uvs.push( u, 1 - v );
27286 // save index of vertex in respective row
27288 indexRow.push( index ++ );
27292 // now save vertices of the row in our index array
27294 indexArray.push( indexRow );
27298 // generate indices
27300 for ( let x = 0; x < radialSegments; x ++ ) {
27302 for ( let y = 0; y < heightSegments; y ++ ) {
27304 // we use the index array to access the correct indices
27306 const a = indexArray[ y ][ x ];
27307 const b = indexArray[ y + 1 ][ x ];
27308 const c = indexArray[ y + 1 ][ x + 1 ];
27309 const d = indexArray[ y ][ x + 1 ];
27313 indices.push( a, b, d );
27314 indices.push( b, c, d );
27316 // update group counter
27324 // add a group to the geometry. this will ensure multi material support
27326 scope.addGroup( groupStart, groupCount, 0 );
27328 // calculate new start value for groups
27330 groupStart += groupCount;
27334 function generateCap( top ) {
27336 // save the index of the first center vertex
27337 const centerIndexStart = index;
27339 const uv = new Vector2();
27340 const vertex = new Vector3();
27342 let groupCount = 0;
27344 const radius = ( top === true ) ? radiusTop : radiusBottom;
27345 const sign = ( top === true ) ? 1 : - 1;
27347 // first we generate the center vertex data of the cap.
27348 // because the geometry needs one set of uvs per face,
27349 // we must generate a center vertex per face/segment
27351 for ( let x = 1; x <= radialSegments; x ++ ) {
27355 vertices.push( 0, halfHeight * sign, 0 );
27359 normals.push( 0, sign, 0 );
27363 uvs.push( 0.5, 0.5 );
27371 // save the index of the last center vertex
27372 const centerIndexEnd = index;
27374 // now we generate the surrounding vertices, normals and uvs
27376 for ( let x = 0; x <= radialSegments; x ++ ) {
27378 const u = x / radialSegments;
27379 const theta = u * thetaLength + thetaStart;
27381 const cosTheta = Math.cos( theta );
27382 const sinTheta = Math.sin( theta );
27386 vertex.x = radius * sinTheta;
27387 vertex.y = halfHeight * sign;
27388 vertex.z = radius * cosTheta;
27389 vertices.push( vertex.x, vertex.y, vertex.z );
27393 normals.push( 0, sign, 0 );
27397 uv.x = ( cosTheta * 0.5 ) + 0.5;
27398 uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
27399 uvs.push( uv.x, uv.y );
27407 // generate indices
27409 for ( let x = 0; x < radialSegments; x ++ ) {
27411 const c = centerIndexStart + x;
27412 const i = centerIndexEnd + x;
27414 if ( top === true ) {
27418 indices.push( i, i + 1, c );
27424 indices.push( i + 1, i, c );
27432 // add a group to the geometry. this will ensure multi material support
27434 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
27436 // calculate new start value for groups
27438 groupStart += groupCount;
27446 class ConeGeometry extends CylinderGeometry {
27448 constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
27450 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
27452 this.type = 'ConeGeometry';
27454 this.parameters = {
27457 radialSegments: radialSegments,
27458 heightSegments: heightSegments,
27459 openEnded: openEnded,
27460 thetaStart: thetaStart,
27461 thetaLength: thetaLength
27468 class PolyhedronGeometry extends BufferGeometry {
27470 constructor( vertices, indices, radius = 1, detail = 0 ) {
27474 this.type = 'PolyhedronGeometry';
27476 this.parameters = {
27477 vertices: vertices,
27483 // default buffer data
27485 const vertexBuffer = [];
27486 const uvBuffer = [];
27488 // the subdivision creates the vertex buffer data
27490 subdivide( detail );
27492 // all vertices should lie on a conceptual sphere with a given radius
27494 applyRadius( radius );
27496 // finally, create the uv data
27500 // build non-indexed geometry
27502 this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
27503 this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
27504 this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
27506 if ( detail === 0 ) {
27508 this.computeVertexNormals(); // flat normals
27512 this.normalizeNormals(); // smooth normals
27516 // helper functions
27518 function subdivide( detail ) {
27520 const a = new Vector3();
27521 const b = new Vector3();
27522 const c = new Vector3();
27524 // iterate over all faces and apply a subdivison with the given detail value
27526 for ( let i = 0; i < indices.length; i += 3 ) {
27528 // get the vertices of the face
27530 getVertexByIndex( indices[ i + 0 ], a );
27531 getVertexByIndex( indices[ i + 1 ], b );
27532 getVertexByIndex( indices[ i + 2 ], c );
27534 // perform subdivision
27536 subdivideFace( a, b, c, detail );
27542 function subdivideFace( a, b, c, detail ) {
27544 const cols = detail + 1;
27546 // we use this multidimensional array as a data structure for creating the subdivision
27550 // construct all of the vertices for this subdivision
27552 for ( let i = 0; i <= cols; i ++ ) {
27556 const aj = a.clone().lerp( c, i / cols );
27557 const bj = b.clone().lerp( c, i / cols );
27559 const rows = cols - i;
27561 for ( let j = 0; j <= rows; j ++ ) {
27563 if ( j === 0 && i === cols ) {
27569 v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
27577 // construct all of the faces
27579 for ( let i = 0; i < cols; i ++ ) {
27581 for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
27583 const k = Math.floor( j / 2 );
27585 if ( j % 2 === 0 ) {
27587 pushVertex( v[ i ][ k + 1 ] );
27588 pushVertex( v[ i + 1 ][ k ] );
27589 pushVertex( v[ i ][ k ] );
27593 pushVertex( v[ i ][ k + 1 ] );
27594 pushVertex( v[ i + 1 ][ k + 1 ] );
27595 pushVertex( v[ i + 1 ][ k ] );
27605 function applyRadius( radius ) {
27607 const vertex = new Vector3();
27609 // iterate over the entire buffer and apply the radius to each vertex
27611 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
27613 vertex.x = vertexBuffer[ i + 0 ];
27614 vertex.y = vertexBuffer[ i + 1 ];
27615 vertex.z = vertexBuffer[ i + 2 ];
27617 vertex.normalize().multiplyScalar( radius );
27619 vertexBuffer[ i + 0 ] = vertex.x;
27620 vertexBuffer[ i + 1 ] = vertex.y;
27621 vertexBuffer[ i + 2 ] = vertex.z;
27627 function generateUVs() {
27629 const vertex = new Vector3();
27631 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
27633 vertex.x = vertexBuffer[ i + 0 ];
27634 vertex.y = vertexBuffer[ i + 1 ];
27635 vertex.z = vertexBuffer[ i + 2 ];
27637 const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
27638 const v = inclination( vertex ) / Math.PI + 0.5;
27639 uvBuffer.push( u, 1 - v );
27649 function correctSeam() {
27651 // handle case when face straddles the seam, see #3269
27653 for ( let i = 0; i < uvBuffer.length; i += 6 ) {
27655 // uv data of a single face
27657 const x0 = uvBuffer[ i + 0 ];
27658 const x1 = uvBuffer[ i + 2 ];
27659 const x2 = uvBuffer[ i + 4 ];
27661 const max = Math.max( x0, x1, x2 );
27662 const min = Math.min( x0, x1, x2 );
27664 // 0.9 is somewhat arbitrary
27666 if ( max > 0.9 && min < 0.1 ) {
27668 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
27669 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
27670 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
27678 function pushVertex( vertex ) {
27680 vertexBuffer.push( vertex.x, vertex.y, vertex.z );
27684 function getVertexByIndex( index, vertex ) {
27686 const stride = index * 3;
27688 vertex.x = vertices[ stride + 0 ];
27689 vertex.y = vertices[ stride + 1 ];
27690 vertex.z = vertices[ stride + 2 ];
27694 function correctUVs() {
27696 const a = new Vector3();
27697 const b = new Vector3();
27698 const c = new Vector3();
27700 const centroid = new Vector3();
27702 const uvA = new Vector2();
27703 const uvB = new Vector2();
27704 const uvC = new Vector2();
27706 for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
27708 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
27709 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
27710 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
27712 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
27713 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
27714 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
27716 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
27718 const azi = azimuth( centroid );
27720 correctUV( uvA, j + 0, a, azi );
27721 correctUV( uvB, j + 2, b, azi );
27722 correctUV( uvC, j + 4, c, azi );
27728 function correctUV( uv, stride, vector, azimuth ) {
27730 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
27732 uvBuffer[ stride ] = uv.x - 1;
27736 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
27738 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
27744 // Angle around the Y axis, counter-clockwise when looking from above.
27746 function azimuth( vector ) {
27748 return Math.atan2( vector.z, - vector.x );
27753 // Angle above the XZ plane.
27755 function inclination( vector ) {
27757 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
27765 class DodecahedronGeometry extends PolyhedronGeometry {
27767 constructor( radius = 1, detail = 0 ) {
27769 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
27775 - 1, - 1, - 1, - 1, - 1, 1,
27776 - 1, 1, - 1, - 1, 1, 1,
27777 1, - 1, - 1, 1, - 1, 1,
27778 1, 1, - 1, 1, 1, 1,
27780 // (0, ±1/φ, ±φ)
27781 0, - r, - t, 0, - r, t,
27782 0, r, - t, 0, r, t,
27784 // (±1/φ, ±φ, 0)
27785 - r, - t, 0, - r, t, 0,
27786 r, - t, 0, r, t, 0,
27788 // (±φ, 0, ±1/φ)
27789 - t, 0, - r, t, 0, - r,
27794 3, 11, 7, 3, 7, 15, 3, 15, 13,
27795 7, 19, 17, 7, 17, 6, 7, 6, 15,
27796 17, 4, 8, 17, 8, 10, 17, 10, 6,
27797 8, 0, 16, 8, 16, 2, 8, 2, 10,
27798 0, 12, 1, 0, 1, 18, 0, 18, 16,
27799 6, 10, 2, 6, 2, 13, 6, 13, 15,
27800 2, 16, 18, 2, 18, 3, 2, 3, 13,
27801 18, 1, 9, 18, 9, 11, 18, 11, 3,
27802 4, 14, 12, 4, 12, 0, 4, 0, 8,
27803 11, 9, 5, 11, 5, 19, 11, 19, 7,
27804 19, 5, 14, 19, 14, 4, 19, 4, 17,
27805 1, 12, 14, 1, 14, 5, 1, 5, 9
27808 super( vertices, indices, radius, detail );
27810 this.type = 'DodecahedronGeometry';
27812 this.parameters = {
27821 const _v0$2 = new Vector3();
27822 const _v1$5 = new Vector3();
27823 const _normal$1 = new Vector3();
27824 const _triangle = new Triangle();
27826 class EdgesGeometry extends BufferGeometry {
27828 constructor( geometry, thresholdAngle ) {
27832 this.type = 'EdgesGeometry';
27834 this.parameters = {
27835 thresholdAngle: thresholdAngle
27838 thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
27840 if ( geometry.isGeometry === true ) {
27842 console.error( 'THREE.EdgesGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
27847 const precisionPoints = 4;
27848 const precision = Math.pow( 10, precisionPoints );
27849 const thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle );
27851 const indexAttr = geometry.getIndex();
27852 const positionAttr = geometry.getAttribute( 'position' );
27853 const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
27855 const indexArr = [ 0, 0, 0 ];
27856 const vertKeys = [ 'a', 'b', 'c' ];
27857 const hashes = new Array( 3 );
27859 const edgeData = {};
27860 const vertices = [];
27861 for ( let i = 0; i < indexCount; i += 3 ) {
27865 indexArr[ 0 ] = indexAttr.getX( i );
27866 indexArr[ 1 ] = indexAttr.getX( i + 1 );
27867 indexArr[ 2 ] = indexAttr.getX( i + 2 );
27872 indexArr[ 1 ] = i + 1;
27873 indexArr[ 2 ] = i + 2;
27877 const { a, b, c } = _triangle;
27878 a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
27879 b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
27880 c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
27881 _triangle.getNormal( _normal$1 );
27883 // create hashes for the edge from the vertices
27884 hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
27885 hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
27886 hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
27888 // skip degenerate triangles
27889 if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
27895 // iterate over every edge
27896 for ( let j = 0; j < 3; j ++ ) {
27898 // get the first and next vertex making up the edge
27899 const jNext = ( j + 1 ) % 3;
27900 const vecHash0 = hashes[ j ];
27901 const vecHash1 = hashes[ jNext ];
27902 const v0 = _triangle[ vertKeys[ j ] ];
27903 const v1 = _triangle[ vertKeys[ jNext ] ];
27905 const hash = `${ vecHash0 }_${ vecHash1 }`;
27906 const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
27908 if ( reverseHash in edgeData && edgeData[ reverseHash ] ) {
27910 // if we found a sibling edge add it into the vertex array if
27911 // it meets the angle threshold and delete the edge from the map.
27912 if ( _normal$1.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
27914 vertices.push( v0.x, v0.y, v0.z );
27915 vertices.push( v1.x, v1.y, v1.z );
27919 edgeData[ reverseHash ] = null;
27921 } else if ( ! ( hash in edgeData ) ) {
27923 // if we've already got an edge here then skip adding a new one
27924 edgeData[ hash ] = {
27926 index0: indexArr[ j ],
27927 index1: indexArr[ jNext ],
27928 normal: _normal$1.clone(),
27938 // iterate over all remaining, unmatched edges and add them to the vertex array
27939 for ( const key in edgeData ) {
27941 if ( edgeData[ key ] ) {
27943 const { index0, index1 } = edgeData[ key ];
27944 _v0$2.fromBufferAttribute( positionAttr, index0 );
27945 _v1$5.fromBufferAttribute( positionAttr, index1 );
27947 vertices.push( _v0$2.x, _v0$2.y, _v0$2.z );
27948 vertices.push( _v1$5.x, _v1$5.y, _v1$5.z );
27954 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
27961 * Port from https://github.com/mapbox/earcut (v2.2.2)
27966 triangulate: function ( data, holeIndices, dim ) {
27970 const hasHoles = holeIndices && holeIndices.length;
27971 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
27972 let outerNode = linkedList( data, 0, outerLen, dim, true );
27973 const triangles = [];
27975 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
27977 let minX, minY, maxX, maxY, x, y, invSize;
27979 if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
27981 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
27982 if ( data.length > 80 * dim ) {
27984 minX = maxX = data[ 0 ];
27985 minY = maxY = data[ 1 ];
27987 for ( let i = dim; i < outerLen; i += dim ) {
27991 if ( x < minX ) minX = x;
27992 if ( y < minY ) minY = y;
27993 if ( x > maxX ) maxX = x;
27994 if ( y > maxY ) maxY = y;
27998 // minX, minY and invSize are later used to transform coords into integers for z-order calculation
27999 invSize = Math.max( maxX - minX, maxY - minY );
28000 invSize = invSize !== 0 ? 1 / invSize : 0;
28004 earcutLinked( outerNode, triangles, dim, minX, minY, invSize );
28012 // create a circular doubly linked list from polygon points in the specified winding order
28013 function linkedList( data, start, end, dim, clockwise ) {
28017 if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
28019 for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
28023 for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
28027 if ( last && equals( last, last.next ) ) {
28029 removeNode( last );
28038 // eliminate colinear or duplicate points
28039 function filterPoints( start, end ) {
28041 if ( ! start ) return start;
28042 if ( ! end ) end = start;
28050 if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
28054 if ( p === p.next ) break;
28063 } while ( again || p !== end );
28069 // main ear slicing loop which triangulates a polygon (given as a linked list)
28070 function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
28072 if ( ! ear ) return;
28074 // interlink polygon nodes in z-order
28075 if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
28080 // iterate through ears, slicing them one by one
28081 while ( ear.prev !== ear.next ) {
28086 if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
28088 // cut off the triangle
28089 triangles.push( prev.i / dim );
28090 triangles.push( ear.i / dim );
28091 triangles.push( next.i / dim );
28095 // skipping the next vertex leads to less sliver triangles
28105 // if we looped through the whole remaining polygon and can't find any more ears
28106 if ( ear === stop ) {
28108 // try filtering points and slicing again
28111 earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
28113 // if this didn't work, try curing all small self-intersections locally
28115 } else if ( pass === 1 ) {
28117 ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
28118 earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
28120 // as a last resort, try splitting the remaining polygon into two
28122 } else if ( pass === 2 ) {
28124 splitEarcut( ear, triangles, dim, minX, minY, invSize );
28136 // check whether a polygon node forms a valid ear with adjacent nodes
28137 function isEar( ear ) {
28139 const a = ear.prev,
28143 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
28145 // now make sure we don't have other points inside the potential ear
28146 let p = ear.next.next;
28148 while ( p !== ear.prev ) {
28150 if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
28151 area( p.prev, p, p.next ) >= 0 ) return false;
28160 function isEarHashed( ear, minX, minY, invSize ) {
28162 const a = ear.prev,
28166 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
28168 // triangle bbox; min & max are calculated like this for speed
28169 const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
28170 minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
28171 maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
28172 maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
28174 // z-order range for the current triangle bbox;
28175 const minZ = zOrder( minTX, minTY, minX, minY, invSize ),
28176 maxZ = zOrder( maxTX, maxTY, minX, minY, invSize );
28181 // look for points inside the triangle in both directions
28182 while ( p && p.z >= minZ && n && n.z <= maxZ ) {
28184 if ( p !== ear.prev && p !== ear.next &&
28185 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
28186 area( p.prev, p, p.next ) >= 0 ) return false;
28189 if ( n !== ear.prev && n !== ear.next &&
28190 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
28191 area( n.prev, n, n.next ) >= 0 ) return false;
28196 // look for remaining points in decreasing z-order
28197 while ( p && p.z >= minZ ) {
28199 if ( p !== ear.prev && p !== ear.next &&
28200 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
28201 area( p.prev, p, p.next ) >= 0 ) return false;
28206 // look for remaining points in increasing z-order
28207 while ( n && n.z <= maxZ ) {
28209 if ( n !== ear.prev && n !== ear.next &&
28210 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
28211 area( n.prev, n, n.next ) >= 0 ) return false;
28220 // go through all polygon nodes and cure small local self-intersections
28221 function cureLocalIntersections( start, triangles, dim ) {
28229 if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
28231 triangles.push( a.i / dim );
28232 triangles.push( p.i / dim );
28233 triangles.push( b.i / dim );
28235 // remove two nodes involved
28237 removeNode( p.next );
28245 } while ( p !== start );
28247 return filterPoints( p );
28251 // try splitting polygon into two and triangulate them independently
28252 function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
28254 // look for a valid diagonal that divides the polygon into two
28258 let b = a.next.next;
28259 while ( b !== a.prev ) {
28261 if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
28263 // split the polygon in two by the diagonal
28264 let c = splitPolygon( a, b );
28266 // filter colinear points around the cuts
28267 a = filterPoints( a, a.next );
28268 c = filterPoints( c, c.next );
28270 // run earcut on each half
28271 earcutLinked( a, triangles, dim, minX, minY, invSize );
28272 earcutLinked( c, triangles, dim, minX, minY, invSize );
28283 } while ( a !== start );
28287 // link every hole into the outer loop, producing a single-ring polygon without holes
28288 function eliminateHoles( data, holeIndices, outerNode, dim ) {
28291 let i, len, start, end, list;
28293 for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
28295 start = holeIndices[ i ] * dim;
28296 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
28297 list = linkedList( data, start, end, dim, false );
28298 if ( list === list.next ) list.steiner = true;
28299 queue.push( getLeftmost( list ) );
28303 queue.sort( compareX );
28305 // process holes from left to right
28306 for ( i = 0; i < queue.length; i ++ ) {
28308 eliminateHole( queue[ i ], outerNode );
28309 outerNode = filterPoints( outerNode, outerNode.next );
28317 function compareX( a, b ) {
28323 // find a bridge between vertices that connects hole with an outer ring and and link it
28324 function eliminateHole( hole, outerNode ) {
28326 outerNode = findHoleBridge( hole, outerNode );
28329 const b = splitPolygon( outerNode, hole );
28331 // filter collinear points around the cuts
28332 filterPoints( outerNode, outerNode.next );
28333 filterPoints( b, b.next );
28339 // David Eberly's algorithm for finding a bridge between hole and outer polygon
28340 function findHoleBridge( hole, outerNode ) {
28345 let qx = - Infinity, m;
28347 // find a segment intersected by a ray from the hole's leftmost point to the left;
28348 // segment's endpoint with lesser x will be potential connection point
28351 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
28353 const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
28354 if ( x <= hx && x > qx ) {
28359 if ( hy === p.y ) return p;
28360 if ( hy === p.next.y ) return p.next;
28364 m = p.x < p.next.x ? p : p.next;
28372 } while ( p !== outerNode );
28374 if ( ! m ) return null;
28376 if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
28378 // look for points inside the triangle of hole point, segment intersection and endpoint;
28379 // if there are no points found, we have a valid connection;
28380 // otherwise choose the point of the minimum angle with the ray as connection point
28385 let tanMin = Infinity, tan;
28391 if ( hx >= p.x && p.x >= mx && hx !== p.x &&
28392 pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
28394 tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
28396 if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
28407 } while ( p !== stop );
28413 // whether sector in vertex m contains sector in vertex p in the same coordinates
28414 function sectorContainsSector( m, p ) {
28416 return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
28420 // interlink polygon nodes in z-order
28421 function indexCurve( start, minX, minY, invSize ) {
28426 if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
28431 } while ( p !== start );
28433 p.prevZ.nextZ = null;
28440 // Simon Tatham's linked list merge sort algorithm
28441 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
28442 function sortLinked( list ) {
28444 let i, p, q, e, tail, numMerges, pSize, qSize,
28459 for ( i = 0; i < inSize; i ++ ) {
28469 while ( pSize > 0 || ( qSize > 0 && q ) ) {
28471 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
28485 if ( tail ) tail.nextZ = e;
28500 } while ( numMerges > 1 );
28506 // z-order of a point given coords and inverse of the longer side of data bbox
28507 function zOrder( x, y, minX, minY, invSize ) {
28509 // coords are transformed into non-negative 15-bit integer range
28510 x = 32767 * ( x - minX ) * invSize;
28511 y = 32767 * ( y - minY ) * invSize;
28513 x = ( x | ( x << 8 ) ) & 0x00FF00FF;
28514 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
28515 x = ( x | ( x << 2 ) ) & 0x33333333;
28516 x = ( x | ( x << 1 ) ) & 0x55555555;
28518 y = ( y | ( y << 8 ) ) & 0x00FF00FF;
28519 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
28520 y = ( y | ( y << 2 ) ) & 0x33333333;
28521 y = ( y | ( y << 1 ) ) & 0x55555555;
28523 return x | ( y << 1 );
28527 // find the leftmost node of a polygon ring
28528 function getLeftmost( start ) {
28534 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
28537 } while ( p !== start );
28543 // check if a point lies within a convex triangle
28544 function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
28546 return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
28547 ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
28548 ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
28552 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
28553 function isValidDiagonal( a, b ) {
28555 return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
28556 ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
28557 ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
28558 equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
28562 // signed area of a triangle
28563 function area( p, q, r ) {
28565 return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
28569 // check if two points are equal
28570 function equals( p1, p2 ) {
28572 return p1.x === p2.x && p1.y === p2.y;
28576 // check if two segments intersect
28577 function intersects( p1, q1, p2, q2 ) {
28579 const o1 = sign( area( p1, q1, p2 ) );
28580 const o2 = sign( area( p1, q1, q2 ) );
28581 const o3 = sign( area( p2, q2, p1 ) );
28582 const o4 = sign( area( p2, q2, q1 ) );
28584 if ( o1 !== o2 && o3 !== o4 ) return true; // general case
28586 if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
28587 if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
28588 if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
28589 if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
28595 // for collinear points p, q, r, check if point q lies on segment pr
28596 function onSegment( p, q, r ) {
28598 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 );
28602 function sign( num ) {
28604 return num > 0 ? 1 : num < 0 ? - 1 : 0;
28608 // check if a polygon diagonal intersects any polygon segments
28609 function intersectsPolygon( a, b ) {
28614 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
28615 intersects( p, p.next, a, b ) ) return true;
28618 } while ( p !== a );
28624 // check if a polygon diagonal is locally inside the polygon
28625 function locallyInside( a, b ) {
28627 return area( a.prev, a, a.next ) < 0 ?
28628 area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
28629 area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
28633 // check if the middle point of a polygon diagonal is inside the polygon
28634 function middleInside( a, b ) {
28638 const px = ( a.x + b.x ) / 2,
28639 py = ( a.y + b.y ) / 2;
28642 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
28643 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
28647 } while ( p !== a );
28653 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
28654 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
28655 function splitPolygon( a, b ) {
28657 const a2 = new Node( a.i, a.x, a.y ),
28658 b2 = new Node( b.i, b.x, b.y ),
28678 // create a node and optionally link it with previous one (in a circular doubly linked list)
28679 function insertNode( i, x, y, last ) {
28681 const p = new Node( i, x, y );
28690 p.next = last.next;
28692 last.next.prev = p;
28701 function removeNode( p ) {
28703 p.next.prev = p.prev;
28704 p.prev.next = p.next;
28706 if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
28707 if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
28711 function Node( i, x, y ) {
28713 // vertex index in coordinates array
28716 // vertex coordinates
28720 // previous and next vertex nodes in a polygon ring
28724 // z-order curve value
28727 // previous and next nodes in z-order
28731 // indicates whether this is a steiner point
28732 this.steiner = false;
28736 function signedArea( data, start, end, dim ) {
28739 for ( let i = start, j = end - dim; i < end; i += dim ) {
28741 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
28750 const ShapeUtils = {
28752 // calculate area of the contour polygon
28754 area: function ( contour ) {
28756 const n = contour.length;
28759 for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
28761 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
28769 isClockWise: function ( pts ) {
28771 return ShapeUtils.area( pts ) < 0;
28775 triangulateShape: function ( contour, holes ) {
28777 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
28778 const holeIndices = []; // array of hole indices
28779 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
28781 removeDupEndPts( contour );
28782 addContour( vertices, contour );
28786 let holeIndex = contour.length;
28788 holes.forEach( removeDupEndPts );
28790 for ( let i = 0; i < holes.length; i ++ ) {
28792 holeIndices.push( holeIndex );
28793 holeIndex += holes[ i ].length;
28794 addContour( vertices, holes[ i ] );
28800 const triangles = Earcut.triangulate( vertices, holeIndices );
28804 for ( let i = 0; i < triangles.length; i += 3 ) {
28806 faces.push( triangles.slice( i, i + 3 ) );
28816 function removeDupEndPts( points ) {
28818 const l = points.length;
28820 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
28828 function addContour( vertices, contour ) {
28830 for ( let i = 0; i < contour.length; i ++ ) {
28832 vertices.push( contour[ i ].x );
28833 vertices.push( contour[ i ].y );
28840 * Creates extruded geometry from a path shape.
28844 * curveSegments: <int>, // number of points on the curves
28845 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
28846 * depth: <float>, // Depth to extrude the shape
28848 * bevelEnabled: <bool>, // turn on bevel
28849 * bevelThickness: <float>, // how deep into the original shape bevel goes
28850 * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
28851 * bevelOffset: <float>, // how far from shape outline does bevel start
28852 * bevelSegments: <int>, // number of bevel layers
28854 * extrudePath: <THREE.Curve> // curve to extrude shape along
28856 * UVGenerator: <Object> // object that provides UV generator functions
28861 class ExtrudeGeometry extends BufferGeometry {
28863 constructor( shapes, options ) {
28867 this.type = 'ExtrudeGeometry';
28869 this.parameters = {
28874 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
28876 const scope = this;
28878 const verticesArray = [];
28879 const uvArray = [];
28881 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
28883 const shape = shapes[ i ];
28890 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
28891 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
28893 this.computeVertexNormals();
28897 function addShape( shape ) {
28899 const placeholder = [];
28903 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
28904 const steps = options.steps !== undefined ? options.steps : 1;
28905 let depth = options.depth !== undefined ? options.depth : 100;
28907 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
28908 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
28909 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
28910 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
28911 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
28913 const extrudePath = options.extrudePath;
28915 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
28917 // deprecated options
28919 if ( options.amount !== undefined ) {
28921 console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
28922 depth = options.amount;
28928 let extrudePts, extrudeByPath = false;
28929 let splineTube, binormal, normal, position2;
28931 if ( extrudePath ) {
28933 extrudePts = extrudePath.getSpacedPoints( steps );
28935 extrudeByPath = true;
28936 bevelEnabled = false; // bevels not supported for path extrusion
28938 // SETUP TNB variables
28940 // TODO1 - have a .isClosed in spline?
28942 splineTube = extrudePath.computeFrenetFrames( steps, false );
28944 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
28946 binormal = new Vector3();
28947 normal = new Vector3();
28948 position2 = new Vector3();
28952 // Safeguards if bevels are not enabled
28954 if ( ! bevelEnabled ) {
28957 bevelThickness = 0;
28963 // Variables initialization
28965 const shapePoints = shape.extractPoints( curveSegments );
28967 let vertices = shapePoints.shape;
28968 const holes = shapePoints.holes;
28970 const reverse = ! ShapeUtils.isClockWise( vertices );
28974 vertices = vertices.reverse();
28976 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
28978 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
28980 const ahole = holes[ h ];
28982 if ( ShapeUtils.isClockWise( ahole ) ) {
28984 holes[ h ] = ahole.reverse();
28993 const faces = ShapeUtils.triangulateShape( vertices, holes );
28997 const contour = vertices; // vertices has all points but contour has only points of circumference
28999 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
29001 const ahole = holes[ h ];
29003 vertices = vertices.concat( ahole );
29008 function scalePt2( pt, vec, size ) {
29010 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
29012 return vec.clone().multiplyScalar( size ).add( pt );
29016 const vlen = vertices.length, flen = faces.length;
29019 // Find directions for point movement
29022 function getBevelVec( inPt, inPrev, inNext ) {
29024 // computes for inPt the corresponding point inPt' on a new contour
29025 // shifted by 1 unit (length of normalized vector) to the left
29026 // if we walk along contour clockwise, this new contour is outside the old one
29028 // inPt' is the intersection of the two lines parallel to the two
29029 // adjacent edges of inPt at a distance of 1 unit on the left side.
29031 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
29033 // good reading for geometry algorithms (here: line-line intersection)
29034 // http://geomalgorithms.com/a05-_intersect-1.html
29036 const v_prev_x = inPt.x - inPrev.x,
29037 v_prev_y = inPt.y - inPrev.y;
29038 const v_next_x = inNext.x - inPt.x,
29039 v_next_y = inNext.y - inPt.y;
29041 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
29043 // check for collinear edges
29044 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
29046 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
29050 // length of vectors for normalizing
29052 const v_prev_len = Math.sqrt( v_prev_lensq );
29053 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
29055 // shift adjacent points by unit vectors to the left
29057 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
29058 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
29060 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
29061 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
29063 // scaling factor for v_prev to intersection point
29065 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
29066 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
29067 ( v_prev_x * v_next_y - v_prev_y * v_next_x );
29069 // vector from inPt to intersection point
29071 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
29072 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
29074 // Don't normalize!, otherwise sharp corners become ugly
29075 // but prevent crazy spikes
29076 const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
29077 if ( v_trans_lensq <= 2 ) {
29079 return new Vector2( v_trans_x, v_trans_y );
29083 shrink_by = Math.sqrt( v_trans_lensq / 2 );
29089 // handle special case of collinear edges
29091 let direction_eq = false; // assumes: opposite
29093 if ( v_prev_x > Number.EPSILON ) {
29095 if ( v_next_x > Number.EPSILON ) {
29097 direction_eq = true;
29103 if ( v_prev_x < - Number.EPSILON ) {
29105 if ( v_next_x < - Number.EPSILON ) {
29107 direction_eq = true;
29113 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
29115 direction_eq = true;
29123 if ( direction_eq ) {
29125 // console.log("Warning: lines are a straight sequence");
29126 v_trans_x = - v_prev_y;
29127 v_trans_y = v_prev_x;
29128 shrink_by = Math.sqrt( v_prev_lensq );
29132 // console.log("Warning: lines are a straight spike");
29133 v_trans_x = v_prev_x;
29134 v_trans_y = v_prev_y;
29135 shrink_by = Math.sqrt( v_prev_lensq / 2 );
29141 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
29146 const contourMovements = [];
29148 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
29150 if ( j === il ) j = 0;
29151 if ( k === il ) k = 0;
29154 // console.log('i,j,k', i, j , k)
29156 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
29160 const holesMovements = [];
29161 let oneHoleMovements, verticesMovements = contourMovements.concat();
29163 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
29165 const ahole = holes[ h ];
29167 oneHoleMovements = [];
29169 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
29171 if ( j === il ) j = 0;
29172 if ( k === il ) k = 0;
29175 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
29179 holesMovements.push( oneHoleMovements );
29180 verticesMovements = verticesMovements.concat( oneHoleMovements );
29185 // Loop bevelSegments, 1 for the front, 1 for the back
29187 for ( let b = 0; b < bevelSegments; b ++ ) {
29189 //for ( b = bevelSegments; b > 0; b -- ) {
29191 const t = b / bevelSegments;
29192 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
29193 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
29197 for ( let i = 0, il = contour.length; i < il; i ++ ) {
29199 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
29201 v( vert.x, vert.y, - z );
29207 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
29209 const ahole = holes[ h ];
29210 oneHoleMovements = holesMovements[ h ];
29212 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
29214 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
29216 v( vert.x, vert.y, - z );
29224 const bs = bevelSize + bevelOffset;
29226 // Back facing vertices
29228 for ( let i = 0; i < vlen; i ++ ) {
29230 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
29232 if ( ! extrudeByPath ) {
29234 v( vert.x, vert.y, 0 );
29238 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
29240 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
29241 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
29243 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
29245 v( position2.x, position2.y, position2.z );
29251 // Add stepped vertices...
29252 // Including front facing vertices
29254 for ( let s = 1; s <= steps; s ++ ) {
29256 for ( let i = 0; i < vlen; i ++ ) {
29258 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
29260 if ( ! extrudeByPath ) {
29262 v( vert.x, vert.y, depth / steps * s );
29266 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
29268 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
29269 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
29271 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
29273 v( position2.x, position2.y, position2.z );
29282 // Add bevel segments planes
29284 //for ( b = 1; b <= bevelSegments; b ++ ) {
29285 for ( let b = bevelSegments - 1; b >= 0; b -- ) {
29287 const t = b / bevelSegments;
29288 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
29289 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
29293 for ( let i = 0, il = contour.length; i < il; i ++ ) {
29295 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
29296 v( vert.x, vert.y, depth + z );
29302 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
29304 const ahole = holes[ h ];
29305 oneHoleMovements = holesMovements[ h ];
29307 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
29309 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
29311 if ( ! extrudeByPath ) {
29313 v( vert.x, vert.y, depth + z );
29317 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
29329 // Top and bottom faces
29338 ///// Internal functions
29340 function buildLidFaces() {
29342 const start = verticesArray.length / 3;
29344 if ( bevelEnabled ) {
29346 let layer = 0; // steps + 1
29347 let offset = vlen * layer;
29351 for ( let i = 0; i < flen; i ++ ) {
29353 const face = faces[ i ];
29354 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
29358 layer = steps + bevelSegments * 2;
29359 offset = vlen * layer;
29363 for ( let i = 0; i < flen; i ++ ) {
29365 const face = faces[ i ];
29366 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
29374 for ( let i = 0; i < flen; i ++ ) {
29376 const face = faces[ i ];
29377 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
29383 for ( let i = 0; i < flen; i ++ ) {
29385 const face = faces[ i ];
29386 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
29392 scope.addGroup( start, verticesArray.length / 3 - start, 0 );
29396 // Create faces for the z-sides of the shape
29398 function buildSideFaces() {
29400 const start = verticesArray.length / 3;
29401 let layeroffset = 0;
29402 sidewalls( contour, layeroffset );
29403 layeroffset += contour.length;
29405 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
29407 const ahole = holes[ h ];
29408 sidewalls( ahole, layeroffset );
29411 layeroffset += ahole.length;
29416 scope.addGroup( start, verticesArray.length / 3 - start, 1 );
29421 function sidewalls( contour, layeroffset ) {
29423 let i = contour.length;
29425 while ( -- i >= 0 ) {
29429 if ( k < 0 ) k = contour.length - 1;
29431 //console.log('b', i,j, i-1, k,vertices.length);
29433 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
29435 const slen1 = vlen * s;
29436 const slen2 = vlen * ( s + 1 );
29438 const a = layeroffset + j + slen1,
29439 b = layeroffset + k + slen1,
29440 c = layeroffset + k + slen2,
29441 d = layeroffset + j + slen2;
29451 function v( x, y, z ) {
29453 placeholder.push( x );
29454 placeholder.push( y );
29455 placeholder.push( z );
29460 function f3( a, b, c ) {
29466 const nextIndex = verticesArray.length / 3;
29467 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
29475 function f4( a, b, c, d ) {
29486 const nextIndex = verticesArray.length / 3;
29487 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
29499 function addVertex( index ) {
29501 verticesArray.push( placeholder[ index * 3 + 0 ] );
29502 verticesArray.push( placeholder[ index * 3 + 1 ] );
29503 verticesArray.push( placeholder[ index * 3 + 2 ] );
29508 function addUV( vector2 ) {
29510 uvArray.push( vector2.x );
29511 uvArray.push( vector2.y );
29521 const data = BufferGeometry.prototype.toJSON.call( this );
29523 const shapes = this.parameters.shapes;
29524 const options = this.parameters.options;
29526 return toJSON( shapes, options, data );
29532 const WorldUVGenerator = {
29534 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
29536 const a_x = vertices[ indexA * 3 ];
29537 const a_y = vertices[ indexA * 3 + 1 ];
29538 const b_x = vertices[ indexB * 3 ];
29539 const b_y = vertices[ indexB * 3 + 1 ];
29540 const c_x = vertices[ indexC * 3 ];
29541 const c_y = vertices[ indexC * 3 + 1 ];
29544 new Vector2( a_x, a_y ),
29545 new Vector2( b_x, b_y ),
29546 new Vector2( c_x, c_y )
29551 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
29553 const a_x = vertices[ indexA * 3 ];
29554 const a_y = vertices[ indexA * 3 + 1 ];
29555 const a_z = vertices[ indexA * 3 + 2 ];
29556 const b_x = vertices[ indexB * 3 ];
29557 const b_y = vertices[ indexB * 3 + 1 ];
29558 const b_z = vertices[ indexB * 3 + 2 ];
29559 const c_x = vertices[ indexC * 3 ];
29560 const c_y = vertices[ indexC * 3 + 1 ];
29561 const c_z = vertices[ indexC * 3 + 2 ];
29562 const d_x = vertices[ indexD * 3 ];
29563 const d_y = vertices[ indexD * 3 + 1 ];
29564 const d_z = vertices[ indexD * 3 + 2 ];
29566 if ( Math.abs( a_y - b_y ) < 0.01 ) {
29569 new Vector2( a_x, 1 - a_z ),
29570 new Vector2( b_x, 1 - b_z ),
29571 new Vector2( c_x, 1 - c_z ),
29572 new Vector2( d_x, 1 - d_z )
29578 new Vector2( a_y, 1 - a_z ),
29579 new Vector2( b_y, 1 - b_z ),
29580 new Vector2( c_y, 1 - c_z ),
29581 new Vector2( d_y, 1 - d_z )
29590 function toJSON( shapes, options, data ) {
29594 if ( Array.isArray( shapes ) ) {
29596 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
29598 const shape = shapes[ i ];
29600 data.shapes.push( shape.uuid );
29606 data.shapes.push( shapes.uuid );
29610 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
29616 class IcosahedronGeometry extends PolyhedronGeometry {
29618 constructor( radius = 1, detail = 0 ) {
29620 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
29623 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
29624 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
29625 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
29629 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
29630 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
29631 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
29632 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
29635 super( vertices, indices, radius, detail );
29637 this.type = 'IcosahedronGeometry';
29639 this.parameters = {
29648 class LatheGeometry extends BufferGeometry {
29650 constructor( points, segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {
29654 this.type = 'LatheGeometry';
29656 this.parameters = {
29658 segments: segments,
29659 phiStart: phiStart,
29660 phiLength: phiLength
29663 segments = Math.floor( segments );
29665 // clamp phiLength so it's in range of [ 0, 2PI ]
29667 phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 );
29671 const indices = [];
29672 const vertices = [];
29675 // helper variables
29677 const inverseSegments = 1.0 / segments;
29678 const vertex = new Vector3();
29679 const uv = new Vector2();
29681 // generate vertices and uvs
29683 for ( let i = 0; i <= segments; i ++ ) {
29685 const phi = phiStart + i * inverseSegments * phiLength;
29687 const sin = Math.sin( phi );
29688 const cos = Math.cos( phi );
29690 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
29694 vertex.x = points[ j ].x * sin;
29695 vertex.y = points[ j ].y;
29696 vertex.z = points[ j ].x * cos;
29698 vertices.push( vertex.x, vertex.y, vertex.z );
29702 uv.x = i / segments;
29703 uv.y = j / ( points.length - 1 );
29705 uvs.push( uv.x, uv.y );
29714 for ( let i = 0; i < segments; i ++ ) {
29716 for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
29718 const base = j + i * points.length;
29721 const b = base + points.length;
29722 const c = base + points.length + 1;
29723 const d = base + 1;
29727 indices.push( a, b, d );
29728 indices.push( b, c, d );
29736 this.setIndex( indices );
29737 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29738 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
29740 // generate normals
29742 this.computeVertexNormals();
29744 // if the geometry is closed, we need to average the normals along the seam.
29745 // because the corresponding vertices are identical (but still have different UVs).
29747 if ( phiLength === Math.PI * 2 ) {
29749 const normals = this.attributes.normal.array;
29750 const n1 = new Vector3();
29751 const n2 = new Vector3();
29752 const n = new Vector3();
29754 // this is the buffer offset for the last line of vertices
29756 const base = segments * points.length * 3;
29758 for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
29760 // select the normal of the vertex in the first line
29762 n1.x = normals[ j + 0 ];
29763 n1.y = normals[ j + 1 ];
29764 n1.z = normals[ j + 2 ];
29766 // select the normal of the vertex in the last line
29768 n2.x = normals[ base + j + 0 ];
29769 n2.y = normals[ base + j + 1 ];
29770 n2.z = normals[ base + j + 2 ];
29774 n.addVectors( n1, n2 ).normalize();
29776 // assign the new values to both normals
29778 normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
29779 normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
29780 normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
29790 class OctahedronGeometry extends PolyhedronGeometry {
29792 constructor( radius = 1, detail = 0 ) {
29795 1, 0, 0, - 1, 0, 0, 0, 1, 0,
29796 0, - 1, 0, 0, 0, 1, 0, 0, - 1
29800 0, 2, 4, 0, 4, 3, 0, 3, 5,
29801 0, 5, 2, 1, 2, 5, 1, 5, 3,
29805 super( vertices, indices, radius, detail );
29807 this.type = 'OctahedronGeometry';
29809 this.parameters = {
29819 * Parametric Surfaces Geometry
29820 * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
29823 function ParametricGeometry( func, slices, stacks ) {
29825 BufferGeometry.call( this );
29827 this.type = 'ParametricGeometry';
29829 this.parameters = {
29837 const indices = [];
29838 const vertices = [];
29839 const normals = [];
29842 const EPS = 0.00001;
29844 const normal = new Vector3();
29846 const p0 = new Vector3(), p1 = new Vector3();
29847 const pu = new Vector3(), pv = new Vector3();
29849 if ( func.length < 3 ) {
29851 console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
29855 // generate vertices, normals and uvs
29857 const sliceCount = slices + 1;
29859 for ( let i = 0; i <= stacks; i ++ ) {
29861 const v = i / stacks;
29863 for ( let j = 0; j <= slices; j ++ ) {
29865 const u = j / slices;
29870 vertices.push( p0.x, p0.y, p0.z );
29874 // approximate tangent vectors via finite differences
29876 if ( u - EPS >= 0 ) {
29878 func( u - EPS, v, p1 );
29879 pu.subVectors( p0, p1 );
29883 func( u + EPS, v, p1 );
29884 pu.subVectors( p1, p0 );
29888 if ( v - EPS >= 0 ) {
29890 func( u, v - EPS, p1 );
29891 pv.subVectors( p0, p1 );
29895 func( u, v + EPS, p1 );
29896 pv.subVectors( p1, p0 );
29900 // cross product of tangent vectors returns surface normal
29902 normal.crossVectors( pu, pv ).normalize();
29903 normals.push( normal.x, normal.y, normal.z );
29913 // generate indices
29915 for ( let i = 0; i < stacks; i ++ ) {
29917 for ( let j = 0; j < slices; j ++ ) {
29919 const a = i * sliceCount + j;
29920 const b = i * sliceCount + j + 1;
29921 const c = ( i + 1 ) * sliceCount + j + 1;
29922 const d = ( i + 1 ) * sliceCount + j;
29924 // faces one and two
29926 indices.push( a, b, d );
29927 indices.push( b, c, d );
29935 this.setIndex( indices );
29936 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29937 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
29938 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
29942 ParametricGeometry.prototype = Object.create( BufferGeometry.prototype );
29943 ParametricGeometry.prototype.constructor = ParametricGeometry;
29945 class RingGeometry extends BufferGeometry {
29947 constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
29951 this.type = 'RingGeometry';
29953 this.parameters = {
29954 innerRadius: innerRadius,
29955 outerRadius: outerRadius,
29956 thetaSegments: thetaSegments,
29957 phiSegments: phiSegments,
29958 thetaStart: thetaStart,
29959 thetaLength: thetaLength
29962 thetaSegments = Math.max( 3, thetaSegments );
29963 phiSegments = Math.max( 1, phiSegments );
29967 const indices = [];
29968 const vertices = [];
29969 const normals = [];
29972 // some helper variables
29974 let radius = innerRadius;
29975 const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
29976 const vertex = new Vector3();
29977 const uv = new Vector2();
29979 // generate vertices, normals and uvs
29981 for ( let j = 0; j <= phiSegments; j ++ ) {
29983 for ( let i = 0; i <= thetaSegments; i ++ ) {
29985 // values are generate from the inside of the ring to the outside
29987 const segment = thetaStart + i / thetaSegments * thetaLength;
29991 vertex.x = radius * Math.cos( segment );
29992 vertex.y = radius * Math.sin( segment );
29994 vertices.push( vertex.x, vertex.y, vertex.z );
29998 normals.push( 0, 0, 1 );
30002 uv.x = ( vertex.x / outerRadius + 1 ) / 2;
30003 uv.y = ( vertex.y / outerRadius + 1 ) / 2;
30005 uvs.push( uv.x, uv.y );
30009 // increase the radius for next row of vertices
30011 radius += radiusStep;
30017 for ( let j = 0; j < phiSegments; j ++ ) {
30019 const thetaSegmentLevel = j * ( thetaSegments + 1 );
30021 for ( let i = 0; i < thetaSegments; i ++ ) {
30023 const segment = i + thetaSegmentLevel;
30026 const b = segment + thetaSegments + 1;
30027 const c = segment + thetaSegments + 2;
30028 const d = segment + 1;
30032 indices.push( a, b, d );
30033 indices.push( b, c, d );
30041 this.setIndex( indices );
30042 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30043 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30044 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30050 class ShapeGeometry extends BufferGeometry {
30052 constructor( shapes, curveSegments = 12 ) {
30055 this.type = 'ShapeGeometry';
30057 this.parameters = {
30059 curveSegments: curveSegments
30064 const indices = [];
30065 const vertices = [];
30066 const normals = [];
30069 // helper variables
30071 let groupStart = 0;
30072 let groupCount = 0;
30074 // allow single and array values for "shapes" parameter
30076 if ( Array.isArray( shapes ) === false ) {
30078 addShape( shapes );
30082 for ( let i = 0; i < shapes.length; i ++ ) {
30084 addShape( shapes[ i ] );
30086 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
30088 groupStart += groupCount;
30097 this.setIndex( indices );
30098 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30099 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30100 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30103 // helper functions
30105 function addShape( shape ) {
30107 const indexOffset = vertices.length / 3;
30108 const points = shape.extractPoints( curveSegments );
30110 let shapeVertices = points.shape;
30111 const shapeHoles = points.holes;
30113 // check direction of vertices
30115 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
30117 shapeVertices = shapeVertices.reverse();
30121 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
30123 const shapeHole = shapeHoles[ i ];
30125 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
30127 shapeHoles[ i ] = shapeHole.reverse();
30133 const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
30135 // join vertices of inner and outer paths to a single array
30137 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
30139 const shapeHole = shapeHoles[ i ];
30140 shapeVertices = shapeVertices.concat( shapeHole );
30144 // vertices, normals, uvs
30146 for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
30148 const vertex = shapeVertices[ i ];
30150 vertices.push( vertex.x, vertex.y, 0 );
30151 normals.push( 0, 0, 1 );
30152 uvs.push( vertex.x, vertex.y ); // world uvs
30158 for ( let i = 0, l = faces.length; i < l; i ++ ) {
30160 const face = faces[ i ];
30162 const a = face[ 0 ] + indexOffset;
30163 const b = face[ 1 ] + indexOffset;
30164 const c = face[ 2 ] + indexOffset;
30166 indices.push( a, b, c );
30177 const data = BufferGeometry.prototype.toJSON.call( this );
30179 const shapes = this.parameters.shapes;
30181 return toJSON$1( shapes, data );
30187 function toJSON$1( shapes, data ) {
30191 if ( Array.isArray( shapes ) ) {
30193 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
30195 const shape = shapes[ i ];
30197 data.shapes.push( shape.uuid );
30203 data.shapes.push( shapes.uuid );
30211 class SphereGeometry extends BufferGeometry {
30213 constructor( radius = 1, widthSegments = 8, heightSegments = 6, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
30216 this.type = 'SphereGeometry';
30218 this.parameters = {
30220 widthSegments: widthSegments,
30221 heightSegments: heightSegments,
30222 phiStart: phiStart,
30223 phiLength: phiLength,
30224 thetaStart: thetaStart,
30225 thetaLength: thetaLength
30228 widthSegments = Math.max( 3, Math.floor( widthSegments ) );
30229 heightSegments = Math.max( 2, Math.floor( heightSegments ) );
30231 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
30236 const vertex = new Vector3();
30237 const normal = new Vector3();
30241 const indices = [];
30242 const vertices = [];
30243 const normals = [];
30246 // generate vertices, normals and uvs
30248 for ( let iy = 0; iy <= heightSegments; iy ++ ) {
30250 const verticesRow = [];
30252 const v = iy / heightSegments;
30254 // special case for the poles
30258 if ( iy == 0 && thetaStart == 0 ) {
30260 uOffset = 0.5 / widthSegments;
30262 } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
30264 uOffset = - 0.5 / widthSegments;
30268 for ( let ix = 0; ix <= widthSegments; ix ++ ) {
30270 const u = ix / widthSegments;
30274 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
30275 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
30276 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
30278 vertices.push( vertex.x, vertex.y, vertex.z );
30282 normal.copy( vertex ).normalize();
30283 normals.push( normal.x, normal.y, normal.z );
30287 uvs.push( u + uOffset, 1 - v );
30289 verticesRow.push( index ++ );
30293 grid.push( verticesRow );
30299 for ( let iy = 0; iy < heightSegments; iy ++ ) {
30301 for ( let ix = 0; ix < widthSegments; ix ++ ) {
30303 const a = grid[ iy ][ ix + 1 ];
30304 const b = grid[ iy ][ ix ];
30305 const c = grid[ iy + 1 ][ ix ];
30306 const d = grid[ iy + 1 ][ ix + 1 ];
30308 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
30309 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
30317 this.setIndex( indices );
30318 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30319 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30320 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30326 class TetrahedronGeometry extends PolyhedronGeometry {
30328 constructor( radius = 1, detail = 0 ) {
30331 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
30335 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
30338 super( vertices, indices, radius, detail );
30340 this.type = 'TetrahedronGeometry';
30342 this.parameters = {
30355 * font: <THREE.Font>, // font
30357 * size: <float>, // size of the text
30358 * height: <float>, // thickness to extrude text
30359 * curveSegments: <int>, // number of points on the curves
30361 * bevelEnabled: <bool>, // turn on bevel
30362 * bevelThickness: <float>, // how deep into text bevel goes
30363 * bevelSize: <float>, // how far from text outline (including bevelOffset) is bevel
30364 * bevelOffset: <float> // how far from text outline does bevel start
30368 class TextGeometry extends ExtrudeGeometry {
30370 constructor( text, parameters = {} ) {
30372 const font = parameters.font;
30374 if ( ! ( font && font.isFont ) ) {
30376 console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
30377 return new BufferGeometry();
30381 const shapes = font.generateShapes( text, parameters.size );
30383 // translate parameters to ExtrudeGeometry API
30385 parameters.depth = parameters.height !== undefined ? parameters.height : 50;
30389 if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
30390 if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
30391 if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
30393 super( shapes, parameters );
30395 this.type = 'TextGeometry';
30401 class TorusGeometry extends BufferGeometry {
30403 constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) {
30406 this.type = 'TorusGeometry';
30408 this.parameters = {
30411 radialSegments: radialSegments,
30412 tubularSegments: tubularSegments,
30416 radialSegments = Math.floor( radialSegments );
30417 tubularSegments = Math.floor( tubularSegments );
30421 const indices = [];
30422 const vertices = [];
30423 const normals = [];
30426 // helper variables
30428 const center = new Vector3();
30429 const vertex = new Vector3();
30430 const normal = new Vector3();
30432 // generate vertices, normals and uvs
30434 for ( let j = 0; j <= radialSegments; j ++ ) {
30436 for ( let i = 0; i <= tubularSegments; i ++ ) {
30438 const u = i / tubularSegments * arc;
30439 const v = j / radialSegments * Math.PI * 2;
30443 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
30444 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
30445 vertex.z = tube * Math.sin( v );
30447 vertices.push( vertex.x, vertex.y, vertex.z );
30451 center.x = radius * Math.cos( u );
30452 center.y = radius * Math.sin( u );
30453 normal.subVectors( vertex, center ).normalize();
30455 normals.push( normal.x, normal.y, normal.z );
30459 uvs.push( i / tubularSegments );
30460 uvs.push( j / radialSegments );
30466 // generate indices
30468 for ( let j = 1; j <= radialSegments; j ++ ) {
30470 for ( let i = 1; i <= tubularSegments; i ++ ) {
30474 const a = ( tubularSegments + 1 ) * j + i - 1;
30475 const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
30476 const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
30477 const d = ( tubularSegments + 1 ) * j + i;
30481 indices.push( a, b, d );
30482 indices.push( b, c, d );
30490 this.setIndex( indices );
30491 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30492 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30493 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30499 class TorusKnotGeometry extends BufferGeometry {
30501 constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
30504 this.type = 'TorusKnotGeometry';
30506 this.parameters = {
30509 tubularSegments: tubularSegments,
30510 radialSegments: radialSegments,
30515 tubularSegments = Math.floor( tubularSegments );
30516 radialSegments = Math.floor( radialSegments );
30520 const indices = [];
30521 const vertices = [];
30522 const normals = [];
30525 // helper variables
30527 const vertex = new Vector3();
30528 const normal = new Vector3();
30530 const P1 = new Vector3();
30531 const P2 = new Vector3();
30533 const B = new Vector3();
30534 const T = new Vector3();
30535 const N = new Vector3();
30537 // generate vertices, normals and uvs
30539 for ( let i = 0; i <= tubularSegments; ++ i ) {
30541 // the radian "u" is used to calculate the position on the torus curve of the current tubular segement
30543 const u = i / tubularSegments * p * Math.PI * 2;
30545 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
30546 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
30548 calculatePositionOnCurve( u, p, q, radius, P1 );
30549 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
30551 // calculate orthonormal basis
30553 T.subVectors( P2, P1 );
30554 N.addVectors( P2, P1 );
30555 B.crossVectors( T, N );
30556 N.crossVectors( B, T );
30558 // normalize B, N. T can be ignored, we don't use it
30563 for ( let j = 0; j <= radialSegments; ++ j ) {
30565 // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
30566 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
30568 const v = j / radialSegments * Math.PI * 2;
30569 const cx = - tube * Math.cos( v );
30570 const cy = tube * Math.sin( v );
30572 // now calculate the final vertex position.
30573 // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
30575 vertex.x = P1.x + ( cx * N.x + cy * B.x );
30576 vertex.y = P1.y + ( cx * N.y + cy * B.y );
30577 vertex.z = P1.z + ( cx * N.z + cy * B.z );
30579 vertices.push( vertex.x, vertex.y, vertex.z );
30581 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
30583 normal.subVectors( vertex, P1 ).normalize();
30585 normals.push( normal.x, normal.y, normal.z );
30589 uvs.push( i / tubularSegments );
30590 uvs.push( j / radialSegments );
30596 // generate indices
30598 for ( let j = 1; j <= tubularSegments; j ++ ) {
30600 for ( let i = 1; i <= radialSegments; i ++ ) {
30604 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
30605 const b = ( radialSegments + 1 ) * j + ( i - 1 );
30606 const c = ( radialSegments + 1 ) * j + i;
30607 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
30611 indices.push( a, b, d );
30612 indices.push( b, c, d );
30620 this.setIndex( indices );
30621 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30622 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30623 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30625 // this function calculates the current position on the torus curve
30627 function calculatePositionOnCurve( u, p, q, radius, position ) {
30629 const cu = Math.cos( u );
30630 const su = Math.sin( u );
30631 const quOverP = q / p * u;
30632 const cs = Math.cos( quOverP );
30634 position.x = radius * ( 2 + cs ) * 0.5 * cu;
30635 position.y = radius * ( 2 + cs ) * su * 0.5;
30636 position.z = radius * Math.sin( quOverP ) * 0.5;
30644 class TubeGeometry extends BufferGeometry {
30646 constructor( path, tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
30649 this.type = 'TubeGeometry';
30651 this.parameters = {
30653 tubularSegments: tubularSegments,
30655 radialSegments: radialSegments,
30659 const frames = path.computeFrenetFrames( tubularSegments, closed );
30661 // expose internals
30663 this.tangents = frames.tangents;
30664 this.normals = frames.normals;
30665 this.binormals = frames.binormals;
30667 // helper variables
30669 const vertex = new Vector3();
30670 const normal = new Vector3();
30671 const uv = new Vector2();
30672 let P = new Vector3();
30676 const vertices = [];
30677 const normals = [];
30679 const indices = [];
30681 // create buffer data
30683 generateBufferData();
30687 this.setIndex( indices );
30688 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30689 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30690 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30694 function generateBufferData() {
30696 for ( let i = 0; i < tubularSegments; i ++ ) {
30698 generateSegment( i );
30702 // if the geometry is not closed, generate the last row of vertices and normals
30703 // at the regular position on the given path
30705 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
30707 generateSegment( ( closed === false ) ? tubularSegments : 0 );
30709 // uvs are generated in a separate function.
30710 // this makes it easy compute correct values for closed geometries
30714 // finally create faces
30720 function generateSegment( i ) {
30722 // we use getPointAt to sample evenly distributed points from the given path
30724 P = path.getPointAt( i / tubularSegments, P );
30726 // retrieve corresponding normal and binormal
30728 const N = frames.normals[ i ];
30729 const B = frames.binormals[ i ];
30731 // generate normals and vertices for the current segment
30733 for ( let j = 0; j <= radialSegments; j ++ ) {
30735 const v = j / radialSegments * Math.PI * 2;
30737 const sin = Math.sin( v );
30738 const cos = - Math.cos( v );
30742 normal.x = ( cos * N.x + sin * B.x );
30743 normal.y = ( cos * N.y + sin * B.y );
30744 normal.z = ( cos * N.z + sin * B.z );
30745 normal.normalize();
30747 normals.push( normal.x, normal.y, normal.z );
30751 vertex.x = P.x + radius * normal.x;
30752 vertex.y = P.y + radius * normal.y;
30753 vertex.z = P.z + radius * normal.z;
30755 vertices.push( vertex.x, vertex.y, vertex.z );
30761 function generateIndices() {
30763 for ( let j = 1; j <= tubularSegments; j ++ ) {
30765 for ( let i = 1; i <= radialSegments; i ++ ) {
30767 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
30768 const b = ( radialSegments + 1 ) * j + ( i - 1 );
30769 const c = ( radialSegments + 1 ) * j + i;
30770 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
30774 indices.push( a, b, d );
30775 indices.push( b, c, d );
30783 function generateUVs() {
30785 for ( let i = 0; i <= tubularSegments; i ++ ) {
30787 for ( let j = 0; j <= radialSegments; j ++ ) {
30789 uv.x = i / tubularSegments;
30790 uv.y = j / radialSegments;
30792 uvs.push( uv.x, uv.y );
30803 const data = BufferGeometry.prototype.toJSON.call( this );
30805 data.path = this.parameters.path.toJSON();
30813 class WireframeGeometry extends BufferGeometry {
30815 constructor( geometry ) {
30818 this.type = 'WireframeGeometry';
30820 if ( geometry.isGeometry === true ) {
30822 console.error( 'THREE.WireframeGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
30829 const vertices = [];
30831 // helper variables
30833 const edge = [ 0, 0 ], edges = {};
30835 const vertex = new Vector3();
30837 if ( geometry.index !== null ) {
30839 // indexed BufferGeometry
30841 const position = geometry.attributes.position;
30842 const indices = geometry.index;
30843 let groups = geometry.groups;
30845 if ( groups.length === 0 ) {
30847 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
30851 // create a data structure that contains all eges without duplicates
30853 for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
30855 const group = groups[ o ];
30857 const start = group.start;
30858 const count = group.count;
30860 for ( let i = start, l = ( start + count ); i < l; i += 3 ) {
30862 for ( let j = 0; j < 3; j ++ ) {
30864 const edge1 = indices.getX( i + j );
30865 const edge2 = indices.getX( i + ( j + 1 ) % 3 );
30866 edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
30867 edge[ 1 ] = Math.max( edge1, edge2 );
30869 const key = edge[ 0 ] + ',' + edge[ 1 ];
30871 if ( edges[ key ] === undefined ) {
30873 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
30883 // generate vertices
30885 for ( const key in edges ) {
30887 const e = edges[ key ];
30889 vertex.fromBufferAttribute( position, e.index1 );
30890 vertices.push( vertex.x, vertex.y, vertex.z );
30892 vertex.fromBufferAttribute( position, e.index2 );
30893 vertices.push( vertex.x, vertex.y, vertex.z );
30899 // non-indexed BufferGeometry
30901 const position = geometry.attributes.position;
30903 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
30905 for ( let j = 0; j < 3; j ++ ) {
30907 // three edges per triangle, an edge is represented as (index1, index2)
30908 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
30910 const index1 = 3 * i + j;
30911 vertex.fromBufferAttribute( position, index1 );
30912 vertices.push( vertex.x, vertex.y, vertex.z );
30914 const index2 = 3 * i + ( ( j + 1 ) % 3 );
30915 vertex.fromBufferAttribute( position, index2 );
30916 vertices.push( vertex.x, vertex.y, vertex.z );
30926 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30932 var Geometries = /*#__PURE__*/Object.freeze({
30934 BoxGeometry: BoxGeometry,
30935 BoxBufferGeometry: BoxGeometry,
30936 CircleGeometry: CircleGeometry,
30937 CircleBufferGeometry: CircleGeometry,
30938 ConeGeometry: ConeGeometry,
30939 ConeBufferGeometry: ConeGeometry,
30940 CylinderGeometry: CylinderGeometry,
30941 CylinderBufferGeometry: CylinderGeometry,
30942 DodecahedronGeometry: DodecahedronGeometry,
30943 DodecahedronBufferGeometry: DodecahedronGeometry,
30944 EdgesGeometry: EdgesGeometry,
30945 ExtrudeGeometry: ExtrudeGeometry,
30946 ExtrudeBufferGeometry: ExtrudeGeometry,
30947 IcosahedronGeometry: IcosahedronGeometry,
30948 IcosahedronBufferGeometry: IcosahedronGeometry,
30949 LatheGeometry: LatheGeometry,
30950 LatheBufferGeometry: LatheGeometry,
30951 OctahedronGeometry: OctahedronGeometry,
30952 OctahedronBufferGeometry: OctahedronGeometry,
30953 ParametricGeometry: ParametricGeometry,
30954 ParametricBufferGeometry: ParametricGeometry,
30955 PlaneGeometry: PlaneGeometry,
30956 PlaneBufferGeometry: PlaneGeometry,
30957 PolyhedronGeometry: PolyhedronGeometry,
30958 PolyhedronBufferGeometry: PolyhedronGeometry,
30959 RingGeometry: RingGeometry,
30960 RingBufferGeometry: RingGeometry,
30961 ShapeGeometry: ShapeGeometry,
30962 ShapeBufferGeometry: ShapeGeometry,
30963 SphereGeometry: SphereGeometry,
30964 SphereBufferGeometry: SphereGeometry,
30965 TetrahedronGeometry: TetrahedronGeometry,
30966 TetrahedronBufferGeometry: TetrahedronGeometry,
30967 TextGeometry: TextGeometry,
30968 TextBufferGeometry: TextGeometry,
30969 TorusGeometry: TorusGeometry,
30970 TorusBufferGeometry: TorusGeometry,
30971 TorusKnotGeometry: TorusKnotGeometry,
30972 TorusKnotBufferGeometry: TorusKnotGeometry,
30973 TubeGeometry: TubeGeometry,
30974 TubeBufferGeometry: TubeGeometry,
30975 WireframeGeometry: WireframeGeometry
30980 * color: <THREE.Color>
30984 function ShadowMaterial( parameters ) {
30986 Material.call( this );
30988 this.type = 'ShadowMaterial';
30990 this.color = new Color( 0x000000 );
30991 this.transparent = true;
30993 this.setValues( parameters );
30997 ShadowMaterial.prototype = Object.create( Material.prototype );
30998 ShadowMaterial.prototype.constructor = ShadowMaterial;
31000 ShadowMaterial.prototype.isShadowMaterial = true;
31002 ShadowMaterial.prototype.copy = function ( source ) {
31004 Material.prototype.copy.call( this, source );
31006 this.color.copy( source.color );
31012 function RawShaderMaterial( parameters ) {
31014 ShaderMaterial.call( this, parameters );
31016 this.type = 'RawShaderMaterial';
31020 RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
31021 RawShaderMaterial.prototype.constructor = RawShaderMaterial;
31023 RawShaderMaterial.prototype.isRawShaderMaterial = true;
31028 * roughness: <float>,
31029 * metalness: <float>,
31030 * opacity: <float>,
31032 * map: new THREE.Texture( <Image> ),
31034 * lightMap: new THREE.Texture( <Image> ),
31035 * lightMapIntensity: <float>
31037 * aoMap: new THREE.Texture( <Image> ),
31038 * aoMapIntensity: <float>
31041 * emissiveIntensity: <float>
31042 * emissiveMap: new THREE.Texture( <Image> ),
31044 * bumpMap: new THREE.Texture( <Image> ),
31045 * bumpScale: <float>,
31047 * normalMap: new THREE.Texture( <Image> ),
31048 * normalMapType: THREE.TangentSpaceNormalMap,
31049 * normalScale: <Vector2>,
31051 * displacementMap: new THREE.Texture( <Image> ),
31052 * displacementScale: <float>,
31053 * displacementBias: <float>,
31055 * roughnessMap: new THREE.Texture( <Image> ),
31057 * metalnessMap: new THREE.Texture( <Image> ),
31059 * alphaMap: new THREE.Texture( <Image> ),
31061 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
31062 * envMapIntensity: <float>
31064 * refractionRatio: <float>,
31066 * wireframe: <boolean>,
31067 * wireframeLinewidth: <float>,
31069 * skinning: <bool>,
31070 * morphTargets: <bool>,
31071 * morphNormals: <bool>
31075 function MeshStandardMaterial( parameters ) {
31077 Material.call( this );
31079 this.defines = { 'STANDARD': '' };
31081 this.type = 'MeshStandardMaterial';
31083 this.color = new Color( 0xffffff ); // diffuse
31084 this.roughness = 1.0;
31085 this.metalness = 0.0;
31089 this.lightMap = null;
31090 this.lightMapIntensity = 1.0;
31093 this.aoMapIntensity = 1.0;
31095 this.emissive = new Color( 0x000000 );
31096 this.emissiveIntensity = 1.0;
31097 this.emissiveMap = null;
31099 this.bumpMap = null;
31100 this.bumpScale = 1;
31102 this.normalMap = null;
31103 this.normalMapType = TangentSpaceNormalMap;
31104 this.normalScale = new Vector2( 1, 1 );
31106 this.displacementMap = null;
31107 this.displacementScale = 1;
31108 this.displacementBias = 0;
31110 this.roughnessMap = null;
31112 this.metalnessMap = null;
31114 this.alphaMap = null;
31116 this.envMap = null;
31117 this.envMapIntensity = 1.0;
31119 this.refractionRatio = 0.98;
31121 this.wireframe = false;
31122 this.wireframeLinewidth = 1;
31123 this.wireframeLinecap = 'round';
31124 this.wireframeLinejoin = 'round';
31126 this.skinning = false;
31127 this.morphTargets = false;
31128 this.morphNormals = false;
31130 this.vertexTangents = false;
31132 this.setValues( parameters );
31136 MeshStandardMaterial.prototype = Object.create( Material.prototype );
31137 MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
31139 MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
31141 MeshStandardMaterial.prototype.copy = function ( source ) {
31143 Material.prototype.copy.call( this, source );
31145 this.defines = { 'STANDARD': '' };
31147 this.color.copy( source.color );
31148 this.roughness = source.roughness;
31149 this.metalness = source.metalness;
31151 this.map = source.map;
31153 this.lightMap = source.lightMap;
31154 this.lightMapIntensity = source.lightMapIntensity;
31156 this.aoMap = source.aoMap;
31157 this.aoMapIntensity = source.aoMapIntensity;
31159 this.emissive.copy( source.emissive );
31160 this.emissiveMap = source.emissiveMap;
31161 this.emissiveIntensity = source.emissiveIntensity;
31163 this.bumpMap = source.bumpMap;
31164 this.bumpScale = source.bumpScale;
31166 this.normalMap = source.normalMap;
31167 this.normalMapType = source.normalMapType;
31168 this.normalScale.copy( source.normalScale );
31170 this.displacementMap = source.displacementMap;
31171 this.displacementScale = source.displacementScale;
31172 this.displacementBias = source.displacementBias;
31174 this.roughnessMap = source.roughnessMap;
31176 this.metalnessMap = source.metalnessMap;
31178 this.alphaMap = source.alphaMap;
31180 this.envMap = source.envMap;
31181 this.envMapIntensity = source.envMapIntensity;
31183 this.refractionRatio = source.refractionRatio;
31185 this.wireframe = source.wireframe;
31186 this.wireframeLinewidth = source.wireframeLinewidth;
31187 this.wireframeLinecap = source.wireframeLinecap;
31188 this.wireframeLinejoin = source.wireframeLinejoin;
31190 this.skinning = source.skinning;
31191 this.morphTargets = source.morphTargets;
31192 this.morphNormals = source.morphNormals;
31194 this.vertexTangents = source.vertexTangents;
31202 * clearcoat: <float>,
31203 * clearcoatMap: new THREE.Texture( <Image> ),
31204 * clearcoatRoughness: <float>,
31205 * clearcoatRoughnessMap: new THREE.Texture( <Image> ),
31206 * clearcoatNormalScale: <Vector2>,
31207 * clearcoatNormalMap: new THREE.Texture( <Image> ),
31209 * reflectivity: <float>,
31214 * transmission: <float>,
31215 * transmissionMap: new THREE.Texture( <Image> )
31219 function MeshPhysicalMaterial( parameters ) {
31221 MeshStandardMaterial.call( this );
31230 this.type = 'MeshPhysicalMaterial';
31232 this.clearcoat = 0.0;
31233 this.clearcoatMap = null;
31234 this.clearcoatRoughness = 0.0;
31235 this.clearcoatRoughnessMap = null;
31236 this.clearcoatNormalScale = new Vector2( 1, 1 );
31237 this.clearcoatNormalMap = null;
31239 this.reflectivity = 0.5; // maps to F0 = 0.04
31241 Object.defineProperty( this, 'ior', {
31244 return ( 1 + 0.4 * this.reflectivity ) / ( 1 - 0.4 * this.reflectivity );
31247 set: function ( ior ) {
31249 this.reflectivity = MathUtils.clamp( 2.5 * ( ior - 1 ) / ( ior + 1 ), 0, 1 );
31254 this.sheen = null; // null will disable sheen bsdf
31256 this.transmission = 0.0;
31257 this.transmissionMap = null;
31259 this.setValues( parameters );
31263 MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
31264 MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
31266 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
31268 MeshPhysicalMaterial.prototype.copy = function ( source ) {
31270 MeshStandardMaterial.prototype.copy.call( this, source );
31279 this.clearcoat = source.clearcoat;
31280 this.clearcoatMap = source.clearcoatMap;
31281 this.clearcoatRoughness = source.clearcoatRoughness;
31282 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
31283 this.clearcoatNormalMap = source.clearcoatNormalMap;
31284 this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
31286 this.reflectivity = source.reflectivity;
31288 if ( source.sheen ) {
31290 this.sheen = ( this.sheen || new Color() ).copy( source.sheen );
31298 this.transmission = source.transmission;
31299 this.transmissionMap = source.transmissionMap;
31309 * shininess: <float>,
31310 * opacity: <float>,
31312 * map: new THREE.Texture( <Image> ),
31314 * lightMap: new THREE.Texture( <Image> ),
31315 * lightMapIntensity: <float>
31317 * aoMap: new THREE.Texture( <Image> ),
31318 * aoMapIntensity: <float>
31321 * emissiveIntensity: <float>
31322 * emissiveMap: new THREE.Texture( <Image> ),
31324 * bumpMap: new THREE.Texture( <Image> ),
31325 * bumpScale: <float>,
31327 * normalMap: new THREE.Texture( <Image> ),
31328 * normalMapType: THREE.TangentSpaceNormalMap,
31329 * normalScale: <Vector2>,
31331 * displacementMap: new THREE.Texture( <Image> ),
31332 * displacementScale: <float>,
31333 * displacementBias: <float>,
31335 * specularMap: new THREE.Texture( <Image> ),
31337 * alphaMap: new THREE.Texture( <Image> ),
31339 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
31340 * combine: THREE.MultiplyOperation,
31341 * reflectivity: <float>,
31342 * refractionRatio: <float>,
31344 * wireframe: <boolean>,
31345 * wireframeLinewidth: <float>,
31347 * skinning: <bool>,
31348 * morphTargets: <bool>,
31349 * morphNormals: <bool>
31353 function MeshPhongMaterial( parameters ) {
31355 Material.call( this );
31357 this.type = 'MeshPhongMaterial';
31359 this.color = new Color( 0xffffff ); // diffuse
31360 this.specular = new Color( 0x111111 );
31361 this.shininess = 30;
31365 this.lightMap = null;
31366 this.lightMapIntensity = 1.0;
31369 this.aoMapIntensity = 1.0;
31371 this.emissive = new Color( 0x000000 );
31372 this.emissiveIntensity = 1.0;
31373 this.emissiveMap = null;
31375 this.bumpMap = null;
31376 this.bumpScale = 1;
31378 this.normalMap = null;
31379 this.normalMapType = TangentSpaceNormalMap;
31380 this.normalScale = new Vector2( 1, 1 );
31382 this.displacementMap = null;
31383 this.displacementScale = 1;
31384 this.displacementBias = 0;
31386 this.specularMap = null;
31388 this.alphaMap = null;
31390 this.envMap = null;
31391 this.combine = MultiplyOperation;
31392 this.reflectivity = 1;
31393 this.refractionRatio = 0.98;
31395 this.wireframe = false;
31396 this.wireframeLinewidth = 1;
31397 this.wireframeLinecap = 'round';
31398 this.wireframeLinejoin = 'round';
31400 this.skinning = false;
31401 this.morphTargets = false;
31402 this.morphNormals = false;
31404 this.setValues( parameters );
31408 MeshPhongMaterial.prototype = Object.create( Material.prototype );
31409 MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
31411 MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
31413 MeshPhongMaterial.prototype.copy = function ( source ) {
31415 Material.prototype.copy.call( this, source );
31417 this.color.copy( source.color );
31418 this.specular.copy( source.specular );
31419 this.shininess = source.shininess;
31421 this.map = source.map;
31423 this.lightMap = source.lightMap;
31424 this.lightMapIntensity = source.lightMapIntensity;
31426 this.aoMap = source.aoMap;
31427 this.aoMapIntensity = source.aoMapIntensity;
31429 this.emissive.copy( source.emissive );
31430 this.emissiveMap = source.emissiveMap;
31431 this.emissiveIntensity = source.emissiveIntensity;
31433 this.bumpMap = source.bumpMap;
31434 this.bumpScale = source.bumpScale;
31436 this.normalMap = source.normalMap;
31437 this.normalMapType = source.normalMapType;
31438 this.normalScale.copy( source.normalScale );
31440 this.displacementMap = source.displacementMap;
31441 this.displacementScale = source.displacementScale;
31442 this.displacementBias = source.displacementBias;
31444 this.specularMap = source.specularMap;
31446 this.alphaMap = source.alphaMap;
31448 this.envMap = source.envMap;
31449 this.combine = source.combine;
31450 this.reflectivity = source.reflectivity;
31451 this.refractionRatio = source.refractionRatio;
31453 this.wireframe = source.wireframe;
31454 this.wireframeLinewidth = source.wireframeLinewidth;
31455 this.wireframeLinecap = source.wireframeLinecap;
31456 this.wireframeLinejoin = source.wireframeLinejoin;
31458 this.skinning = source.skinning;
31459 this.morphTargets = source.morphTargets;
31460 this.morphNormals = source.morphNormals;
31470 * map: new THREE.Texture( <Image> ),
31471 * gradientMap: new THREE.Texture( <Image> ),
31473 * lightMap: new THREE.Texture( <Image> ),
31474 * lightMapIntensity: <float>
31476 * aoMap: new THREE.Texture( <Image> ),
31477 * aoMapIntensity: <float>
31480 * emissiveIntensity: <float>
31481 * emissiveMap: new THREE.Texture( <Image> ),
31483 * bumpMap: new THREE.Texture( <Image> ),
31484 * bumpScale: <float>,
31486 * normalMap: new THREE.Texture( <Image> ),
31487 * normalMapType: THREE.TangentSpaceNormalMap,
31488 * normalScale: <Vector2>,
31490 * displacementMap: new THREE.Texture( <Image> ),
31491 * displacementScale: <float>,
31492 * displacementBias: <float>,
31494 * alphaMap: new THREE.Texture( <Image> ),
31496 * wireframe: <boolean>,
31497 * wireframeLinewidth: <float>,
31499 * skinning: <bool>,
31500 * morphTargets: <bool>,
31501 * morphNormals: <bool>
31505 function MeshToonMaterial( parameters ) {
31507 Material.call( this );
31509 this.defines = { 'TOON': '' };
31511 this.type = 'MeshToonMaterial';
31513 this.color = new Color( 0xffffff );
31516 this.gradientMap = null;
31518 this.lightMap = null;
31519 this.lightMapIntensity = 1.0;
31522 this.aoMapIntensity = 1.0;
31524 this.emissive = new Color( 0x000000 );
31525 this.emissiveIntensity = 1.0;
31526 this.emissiveMap = null;
31528 this.bumpMap = null;
31529 this.bumpScale = 1;
31531 this.normalMap = null;
31532 this.normalMapType = TangentSpaceNormalMap;
31533 this.normalScale = new Vector2( 1, 1 );
31535 this.displacementMap = null;
31536 this.displacementScale = 1;
31537 this.displacementBias = 0;
31539 this.alphaMap = null;
31541 this.wireframe = false;
31542 this.wireframeLinewidth = 1;
31543 this.wireframeLinecap = 'round';
31544 this.wireframeLinejoin = 'round';
31546 this.skinning = false;
31547 this.morphTargets = false;
31548 this.morphNormals = false;
31550 this.setValues( parameters );
31554 MeshToonMaterial.prototype = Object.create( Material.prototype );
31555 MeshToonMaterial.prototype.constructor = MeshToonMaterial;
31557 MeshToonMaterial.prototype.isMeshToonMaterial = true;
31559 MeshToonMaterial.prototype.copy = function ( source ) {
31561 Material.prototype.copy.call( this, source );
31563 this.color.copy( source.color );
31565 this.map = source.map;
31566 this.gradientMap = source.gradientMap;
31568 this.lightMap = source.lightMap;
31569 this.lightMapIntensity = source.lightMapIntensity;
31571 this.aoMap = source.aoMap;
31572 this.aoMapIntensity = source.aoMapIntensity;
31574 this.emissive.copy( source.emissive );
31575 this.emissiveMap = source.emissiveMap;
31576 this.emissiveIntensity = source.emissiveIntensity;
31578 this.bumpMap = source.bumpMap;
31579 this.bumpScale = source.bumpScale;
31581 this.normalMap = source.normalMap;
31582 this.normalMapType = source.normalMapType;
31583 this.normalScale.copy( source.normalScale );
31585 this.displacementMap = source.displacementMap;
31586 this.displacementScale = source.displacementScale;
31587 this.displacementBias = source.displacementBias;
31589 this.alphaMap = source.alphaMap;
31591 this.wireframe = source.wireframe;
31592 this.wireframeLinewidth = source.wireframeLinewidth;
31593 this.wireframeLinecap = source.wireframeLinecap;
31594 this.wireframeLinejoin = source.wireframeLinejoin;
31596 this.skinning = source.skinning;
31597 this.morphTargets = source.morphTargets;
31598 this.morphNormals = source.morphNormals;
31606 * opacity: <float>,
31608 * bumpMap: new THREE.Texture( <Image> ),
31609 * bumpScale: <float>,
31611 * normalMap: new THREE.Texture( <Image> ),
31612 * normalMapType: THREE.TangentSpaceNormalMap,
31613 * normalScale: <Vector2>,
31615 * displacementMap: new THREE.Texture( <Image> ),
31616 * displacementScale: <float>,
31617 * displacementBias: <float>,
31619 * wireframe: <boolean>,
31620 * wireframeLinewidth: <float>
31622 * skinning: <bool>,
31623 * morphTargets: <bool>,
31624 * morphNormals: <bool>
31628 function MeshNormalMaterial( parameters ) {
31630 Material.call( this );
31632 this.type = 'MeshNormalMaterial';
31634 this.bumpMap = null;
31635 this.bumpScale = 1;
31637 this.normalMap = null;
31638 this.normalMapType = TangentSpaceNormalMap;
31639 this.normalScale = new Vector2( 1, 1 );
31641 this.displacementMap = null;
31642 this.displacementScale = 1;
31643 this.displacementBias = 0;
31645 this.wireframe = false;
31646 this.wireframeLinewidth = 1;
31650 this.skinning = false;
31651 this.morphTargets = false;
31652 this.morphNormals = false;
31654 this.setValues( parameters );
31658 MeshNormalMaterial.prototype = Object.create( Material.prototype );
31659 MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
31661 MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
31663 MeshNormalMaterial.prototype.copy = function ( source ) {
31665 Material.prototype.copy.call( this, source );
31667 this.bumpMap = source.bumpMap;
31668 this.bumpScale = source.bumpScale;
31670 this.normalMap = source.normalMap;
31671 this.normalMapType = source.normalMapType;
31672 this.normalScale.copy( source.normalScale );
31674 this.displacementMap = source.displacementMap;
31675 this.displacementScale = source.displacementScale;
31676 this.displacementBias = source.displacementBias;
31678 this.wireframe = source.wireframe;
31679 this.wireframeLinewidth = source.wireframeLinewidth;
31681 this.skinning = source.skinning;
31682 this.morphTargets = source.morphTargets;
31683 this.morphNormals = source.morphNormals;
31692 * opacity: <float>,
31694 * map: new THREE.Texture( <Image> ),
31696 * lightMap: new THREE.Texture( <Image> ),
31697 * lightMapIntensity: <float>
31699 * aoMap: new THREE.Texture( <Image> ),
31700 * aoMapIntensity: <float>
31703 * emissiveIntensity: <float>
31704 * emissiveMap: new THREE.Texture( <Image> ),
31706 * specularMap: new THREE.Texture( <Image> ),
31708 * alphaMap: new THREE.Texture( <Image> ),
31710 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
31711 * combine: THREE.Multiply,
31712 * reflectivity: <float>,
31713 * refractionRatio: <float>,
31715 * wireframe: <boolean>,
31716 * wireframeLinewidth: <float>,
31718 * skinning: <bool>,
31719 * morphTargets: <bool>,
31720 * morphNormals: <bool>
31724 function MeshLambertMaterial( parameters ) {
31726 Material.call( this );
31728 this.type = 'MeshLambertMaterial';
31730 this.color = new Color( 0xffffff ); // diffuse
31734 this.lightMap = null;
31735 this.lightMapIntensity = 1.0;
31738 this.aoMapIntensity = 1.0;
31740 this.emissive = new Color( 0x000000 );
31741 this.emissiveIntensity = 1.0;
31742 this.emissiveMap = null;
31744 this.specularMap = null;
31746 this.alphaMap = null;
31748 this.envMap = null;
31749 this.combine = MultiplyOperation;
31750 this.reflectivity = 1;
31751 this.refractionRatio = 0.98;
31753 this.wireframe = false;
31754 this.wireframeLinewidth = 1;
31755 this.wireframeLinecap = 'round';
31756 this.wireframeLinejoin = 'round';
31758 this.skinning = false;
31759 this.morphTargets = false;
31760 this.morphNormals = false;
31762 this.setValues( parameters );
31766 MeshLambertMaterial.prototype = Object.create( Material.prototype );
31767 MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
31769 MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
31771 MeshLambertMaterial.prototype.copy = function ( source ) {
31773 Material.prototype.copy.call( this, source );
31775 this.color.copy( source.color );
31777 this.map = source.map;
31779 this.lightMap = source.lightMap;
31780 this.lightMapIntensity = source.lightMapIntensity;
31782 this.aoMap = source.aoMap;
31783 this.aoMapIntensity = source.aoMapIntensity;
31785 this.emissive.copy( source.emissive );
31786 this.emissiveMap = source.emissiveMap;
31787 this.emissiveIntensity = source.emissiveIntensity;
31789 this.specularMap = source.specularMap;
31791 this.alphaMap = source.alphaMap;
31793 this.envMap = source.envMap;
31794 this.combine = source.combine;
31795 this.reflectivity = source.reflectivity;
31796 this.refractionRatio = source.refractionRatio;
31798 this.wireframe = source.wireframe;
31799 this.wireframeLinewidth = source.wireframeLinewidth;
31800 this.wireframeLinecap = source.wireframeLinecap;
31801 this.wireframeLinejoin = source.wireframeLinejoin;
31803 this.skinning = source.skinning;
31804 this.morphTargets = source.morphTargets;
31805 this.morphNormals = source.morphNormals;
31814 * opacity: <float>,
31816 * matcap: new THREE.Texture( <Image> ),
31818 * map: new THREE.Texture( <Image> ),
31820 * bumpMap: new THREE.Texture( <Image> ),
31821 * bumpScale: <float>,
31823 * normalMap: new THREE.Texture( <Image> ),
31824 * normalMapType: THREE.TangentSpaceNormalMap,
31825 * normalScale: <Vector2>,
31827 * displacementMap: new THREE.Texture( <Image> ),
31828 * displacementScale: <float>,
31829 * displacementBias: <float>,
31831 * alphaMap: new THREE.Texture( <Image> ),
31833 * skinning: <bool>,
31834 * morphTargets: <bool>,
31835 * morphNormals: <bool>
31839 function MeshMatcapMaterial( parameters ) {
31841 Material.call( this );
31843 this.defines = { 'MATCAP': '' };
31845 this.type = 'MeshMatcapMaterial';
31847 this.color = new Color( 0xffffff ); // diffuse
31849 this.matcap = null;
31853 this.bumpMap = null;
31854 this.bumpScale = 1;
31856 this.normalMap = null;
31857 this.normalMapType = TangentSpaceNormalMap;
31858 this.normalScale = new Vector2( 1, 1 );
31860 this.displacementMap = null;
31861 this.displacementScale = 1;
31862 this.displacementBias = 0;
31864 this.alphaMap = null;
31866 this.skinning = false;
31867 this.morphTargets = false;
31868 this.morphNormals = false;
31870 this.setValues( parameters );
31874 MeshMatcapMaterial.prototype = Object.create( Material.prototype );
31875 MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial;
31877 MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true;
31879 MeshMatcapMaterial.prototype.copy = function ( source ) {
31881 Material.prototype.copy.call( this, source );
31883 this.defines = { 'MATCAP': '' };
31885 this.color.copy( source.color );
31887 this.matcap = source.matcap;
31889 this.map = source.map;
31891 this.bumpMap = source.bumpMap;
31892 this.bumpScale = source.bumpScale;
31894 this.normalMap = source.normalMap;
31895 this.normalMapType = source.normalMapType;
31896 this.normalScale.copy( source.normalScale );
31898 this.displacementMap = source.displacementMap;
31899 this.displacementScale = source.displacementScale;
31900 this.displacementBias = source.displacementBias;
31902 this.alphaMap = source.alphaMap;
31904 this.skinning = source.skinning;
31905 this.morphTargets = source.morphTargets;
31906 this.morphNormals = source.morphNormals;
31915 * opacity: <float>,
31917 * linewidth: <float>,
31920 * dashSize: <float>,
31925 function LineDashedMaterial( parameters ) {
31927 LineBasicMaterial.call( this );
31929 this.type = 'LineDashedMaterial';
31935 this.setValues( parameters );
31939 LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
31940 LineDashedMaterial.prototype.constructor = LineDashedMaterial;
31942 LineDashedMaterial.prototype.isLineDashedMaterial = true;
31944 LineDashedMaterial.prototype.copy = function ( source ) {
31946 LineBasicMaterial.prototype.copy.call( this, source );
31948 this.scale = source.scale;
31949 this.dashSize = source.dashSize;
31950 this.gapSize = source.gapSize;
31956 var Materials = /*#__PURE__*/Object.freeze({
31958 ShadowMaterial: ShadowMaterial,
31959 SpriteMaterial: SpriteMaterial,
31960 RawShaderMaterial: RawShaderMaterial,
31961 ShaderMaterial: ShaderMaterial,
31962 PointsMaterial: PointsMaterial,
31963 MeshPhysicalMaterial: MeshPhysicalMaterial,
31964 MeshStandardMaterial: MeshStandardMaterial,
31965 MeshPhongMaterial: MeshPhongMaterial,
31966 MeshToonMaterial: MeshToonMaterial,
31967 MeshNormalMaterial: MeshNormalMaterial,
31968 MeshLambertMaterial: MeshLambertMaterial,
31969 MeshDepthMaterial: MeshDepthMaterial,
31970 MeshDistanceMaterial: MeshDistanceMaterial,
31971 MeshBasicMaterial: MeshBasicMaterial,
31972 MeshMatcapMaterial: MeshMatcapMaterial,
31973 LineDashedMaterial: LineDashedMaterial,
31974 LineBasicMaterial: LineBasicMaterial,
31978 const AnimationUtils = {
31980 // same as Array.prototype.slice, but also works on typed arrays
31981 arraySlice: function ( array, from, to ) {
31983 if ( AnimationUtils.isTypedArray( array ) ) {
31985 // in ios9 array.subarray(from, undefined) will return empty array
31986 // but array.subarray(from) or array.subarray(from, len) is correct
31987 return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
31991 return array.slice( from, to );
31995 // converts an array to a specific type
31996 convertArray: function ( array, type, forceClone ) {
31998 if ( ! array || // let 'undefined' and 'null' pass
31999 ! forceClone && array.constructor === type ) return array;
32001 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
32003 return new type( array ); // create typed array
32007 return Array.prototype.slice.call( array ); // create Array
32011 isTypedArray: function ( object ) {
32013 return ArrayBuffer.isView( object ) &&
32014 ! ( object instanceof DataView );
32018 // returns an array by which times and values can be sorted
32019 getKeyframeOrder: function ( times ) {
32021 function compareTime( i, j ) {
32023 return times[ i ] - times[ j ];
32027 const n = times.length;
32028 const result = new Array( n );
32029 for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
32031 result.sort( compareTime );
32037 // uses the array previously returned by 'getKeyframeOrder' to sort data
32038 sortedArray: function ( values, stride, order ) {
32040 const nValues = values.length;
32041 const result = new values.constructor( nValues );
32043 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
32045 const srcOffset = order[ i ] * stride;
32047 for ( let j = 0; j !== stride; ++ j ) {
32049 result[ dstOffset ++ ] = values[ srcOffset + j ];
32059 // function for parsing AOS keyframe formats
32060 flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
32062 let i = 1, key = jsonKeys[ 0 ];
32064 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
32066 key = jsonKeys[ i ++ ];
32070 if ( key === undefined ) return; // no data
32072 let value = key[ valuePropertyName ];
32073 if ( value === undefined ) return; // no data
32075 if ( Array.isArray( value ) ) {
32079 value = key[ valuePropertyName ];
32081 if ( value !== undefined ) {
32083 times.push( key.time );
32084 values.push.apply( values, value ); // push all elements
32088 key = jsonKeys[ i ++ ];
32090 } while ( key !== undefined );
32092 } else if ( value.toArray !== undefined ) {
32094 // ...assume THREE.Math-ish
32098 value = key[ valuePropertyName ];
32100 if ( value !== undefined ) {
32102 times.push( key.time );
32103 value.toArray( values, values.length );
32107 key = jsonKeys[ i ++ ];
32109 } while ( key !== undefined );
32113 // otherwise push as-is
32117 value = key[ valuePropertyName ];
32119 if ( value !== undefined ) {
32121 times.push( key.time );
32122 values.push( value );
32126 key = jsonKeys[ i ++ ];
32128 } while ( key !== undefined );
32134 subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) {
32136 const clip = sourceClip.clone();
32142 for ( let i = 0; i < clip.tracks.length; ++ i ) {
32144 const track = clip.tracks[ i ];
32145 const valueSize = track.getValueSize();
32150 for ( let j = 0; j < track.times.length; ++ j ) {
32152 const frame = track.times[ j ] * fps;
32154 if ( frame < startFrame || frame >= endFrame ) continue;
32156 times.push( track.times[ j ] );
32158 for ( let k = 0; k < valueSize; ++ k ) {
32160 values.push( track.values[ j * valueSize + k ] );
32166 if ( times.length === 0 ) continue;
32168 track.times = AnimationUtils.convertArray( times, track.times.constructor );
32169 track.values = AnimationUtils.convertArray( values, track.values.constructor );
32171 tracks.push( track );
32175 clip.tracks = tracks;
32177 // find minimum .times value across all tracks in the trimmed clip
32179 let minStartTime = Infinity;
32181 for ( let i = 0; i < clip.tracks.length; ++ i ) {
32183 if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
32185 minStartTime = clip.tracks[ i ].times[ 0 ];
32191 // shift all tracks such that clip begins at t=0
32193 for ( let i = 0; i < clip.tracks.length; ++ i ) {
32195 clip.tracks[ i ].shift( - 1 * minStartTime );
32199 clip.resetDuration();
32205 makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
32207 if ( fps <= 0 ) fps = 30;
32209 const numTracks = referenceClip.tracks.length;
32210 const referenceTime = referenceFrame / fps;
32212 // Make each track's values relative to the values at the reference frame
32213 for ( let i = 0; i < numTracks; ++ i ) {
32215 const referenceTrack = referenceClip.tracks[ i ];
32216 const referenceTrackType = referenceTrack.ValueTypeName;
32218 // Skip this track if it's non-numeric
32219 if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
32221 // Find the track in the target clip whose name and type matches the reference track
32222 const targetTrack = targetClip.tracks.find( function ( track ) {
32224 return track.name === referenceTrack.name
32225 && track.ValueTypeName === referenceTrackType;
32229 if ( targetTrack === undefined ) continue;
32231 let referenceOffset = 0;
32232 const referenceValueSize = referenceTrack.getValueSize();
32234 if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
32236 referenceOffset = referenceValueSize / 3;
32240 let targetOffset = 0;
32241 const targetValueSize = targetTrack.getValueSize();
32243 if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
32245 targetOffset = targetValueSize / 3;
32249 const lastIndex = referenceTrack.times.length - 1;
32250 let referenceValue;
32252 // Find the value to subtract out of the track
32253 if ( referenceTime <= referenceTrack.times[ 0 ] ) {
32255 // Reference frame is earlier than the first keyframe, so just use the first keyframe
32256 const startIndex = referenceOffset;
32257 const endIndex = referenceValueSize - referenceOffset;
32258 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
32260 } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
32262 // Reference frame is after the last keyframe, so just use the last keyframe
32263 const startIndex = lastIndex * referenceValueSize + referenceOffset;
32264 const endIndex = startIndex + referenceValueSize - referenceOffset;
32265 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
32269 // Interpolate to the reference value
32270 const interpolant = referenceTrack.createInterpolant();
32271 const startIndex = referenceOffset;
32272 const endIndex = referenceValueSize - referenceOffset;
32273 interpolant.evaluate( referenceTime );
32274 referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex );
32278 // Conjugate the quaternion
32279 if ( referenceTrackType === 'quaternion' ) {
32281 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
32282 referenceQuat.toArray( referenceValue );
32286 // Subtract the reference value from all of the track values
32288 const numTimes = targetTrack.times.length;
32289 for ( let j = 0; j < numTimes; ++ j ) {
32291 const valueStart = j * targetValueSize + targetOffset;
32293 if ( referenceTrackType === 'quaternion' ) {
32295 // Multiply the conjugate for quaternion track types
32296 Quaternion.multiplyQuaternionsFlat(
32297 targetTrack.values,
32301 targetTrack.values,
32307 const valueEnd = targetValueSize - targetOffset * 2;
32309 // Subtract each value for all other numeric track types
32310 for ( let k = 0; k < valueEnd; ++ k ) {
32312 targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
32322 targetClip.blendMode = AdditiveAnimationBlendMode;
32331 * Abstract base class of interpolants over parametric samples.
32333 * The parameter domain is one dimensional, typically the time or a path
32334 * along a curve defined by the data.
32336 * The sample values can have any dimensionality and derived classes may
32337 * apply special interpretations to the data.
32339 * This class provides the interval seek in a Template Method, deferring
32340 * the actual interpolation to derived classes.
32342 * Time complexity is O(1) for linear access crossing at most two points
32343 * and O(log N) for random access, where N is the number of positions.
32347 * http://www.oodesign.com/template-method-pattern.html
32351 function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
32353 this.parameterPositions = parameterPositions;
32354 this._cachedIndex = 0;
32356 this.resultBuffer = resultBuffer !== undefined ?
32357 resultBuffer : new sampleValues.constructor( sampleSize );
32358 this.sampleValues = sampleValues;
32359 this.valueSize = sampleSize;
32363 Object.assign( Interpolant.prototype, {
32365 evaluate: function ( t ) {
32367 const pp = this.parameterPositions;
32368 let i1 = this._cachedIndex,
32372 validate_interval: {
32380 //- See http://jsperf.com/comparison-to-undefined/3
32383 //- if ( t >= t1 || t1 === undefined ) {
32384 forward_scan: if ( ! ( t < t1 ) ) {
32386 for ( let giveUpAt = i1 + 2; ; ) {
32388 if ( t1 === undefined ) {
32390 if ( t < t0 ) break forward_scan;
32395 this._cachedIndex = i1;
32396 return this.afterEnd_( i1 - 1, t, t0 );
32400 if ( i1 === giveUpAt ) break; // this loop
32407 // we have arrived at the sought interval
32414 // prepare binary search on the right side of the index
32421 //- if ( t < t0 || t0 === undefined ) {
32422 if ( ! ( t >= t0 ) ) {
32426 const t1global = pp[ 1 ];
32428 if ( t < t1global ) {
32430 i1 = 2; // + 1, using the scan for the details
32435 // linear reverse scan
32437 for ( let giveUpAt = i1 - 2; ; ) {
32439 if ( t0 === undefined ) {
32443 this._cachedIndex = 0;
32444 return this.beforeStart_( 0, t, t1 );
32448 if ( i1 === giveUpAt ) break; // this loop
32451 t0 = pp[ -- i1 - 1 ];
32455 // we have arrived at the sought interval
32462 // prepare binary search on the left side of the index
32469 // the interval is valid
32471 break validate_interval;
32477 while ( i1 < right ) {
32479 const mid = ( i1 + right ) >>> 1;
32481 if ( t < pp[ mid ] ) {
32496 // check boundary cases, again
32498 if ( t0 === undefined ) {
32500 this._cachedIndex = 0;
32501 return this.beforeStart_( 0, t, t1 );
32505 if ( t1 === undefined ) {
32508 this._cachedIndex = i1;
32509 return this.afterEnd_( i1 - 1, t0, t );
32515 this._cachedIndex = i1;
32517 this.intervalChanged_( i1, t0, t1 );
32519 } // validate_interval
32521 return this.interpolate_( i1, t0, t, t1 );
32525 settings: null, // optional, subclass-specific settings structure
32526 // Note: The indirection allows central control of many interpolants.
32528 // --- Protected interface
32530 DefaultSettings_: {},
32532 getSettings_: function () {
32534 return this.settings || this.DefaultSettings_;
32538 copySampleValue_: function ( index ) {
32540 // copies a sample value to the result buffer
32542 const result = this.resultBuffer,
32543 values = this.sampleValues,
32544 stride = this.valueSize,
32545 offset = index * stride;
32547 for ( let i = 0; i !== stride; ++ i ) {
32549 result[ i ] = values[ offset + i ];
32557 // Template methods for derived classes:
32559 interpolate_: function ( /* i1, t0, t, t1 */ ) {
32561 throw new Error( 'call to abstract method' );
32562 // implementations shall return this.resultBuffer
32566 intervalChanged_: function ( /* i1, t0, t1 */ ) {
32574 // DECLARE ALIAS AFTER assign prototype
32575 Object.assign( Interpolant.prototype, {
32577 //( 0, t, t0 ), returns this.resultBuffer
32578 beforeStart_: Interpolant.prototype.copySampleValue_,
32580 //( N-1, tN-1, t ), returns this.resultBuffer
32581 afterEnd_: Interpolant.prototype.copySampleValue_,
32586 * Fast and simple cubic spline interpolant.
32588 * It was derived from a Hermitian construction setting the first derivative
32589 * at each sample position to the linear slope between neighboring positions
32590 * over their parameter interval.
32593 function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
32595 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
32597 this._weightPrev = - 0;
32598 this._offsetPrev = - 0;
32599 this._weightNext = - 0;
32600 this._offsetNext = - 0;
32604 CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
32606 constructor: CubicInterpolant,
32608 DefaultSettings_: {
32610 endingStart: ZeroCurvatureEnding,
32611 endingEnd: ZeroCurvatureEnding
32615 intervalChanged_: function ( i1, t0, t1 ) {
32617 const pp = this.parameterPositions;
32618 let iPrev = i1 - 2,
32621 tPrev = pp[ iPrev ],
32622 tNext = pp[ iNext ];
32624 if ( tPrev === undefined ) {
32626 switch ( this.getSettings_().endingStart ) {
32628 case ZeroSlopeEnding:
32632 tPrev = 2 * t0 - t1;
32636 case WrapAroundEnding:
32638 // use the other end of the curve
32639 iPrev = pp.length - 2;
32640 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
32644 default: // ZeroCurvatureEnding
32646 // f''(t0) = 0 a.k.a. Natural Spline
32654 if ( tNext === undefined ) {
32656 switch ( this.getSettings_().endingEnd ) {
32658 case ZeroSlopeEnding:
32662 tNext = 2 * t1 - t0;
32666 case WrapAroundEnding:
32668 // use the other end of the curve
32670 tNext = t1 + pp[ 1 ] - pp[ 0 ];
32674 default: // ZeroCurvatureEnding
32676 // f''(tN) = 0, a.k.a. Natural Spline
32684 const halfDt = ( t1 - t0 ) * 0.5,
32685 stride = this.valueSize;
32687 this._weightPrev = halfDt / ( t0 - tPrev );
32688 this._weightNext = halfDt / ( tNext - t1 );
32689 this._offsetPrev = iPrev * stride;
32690 this._offsetNext = iNext * stride;
32694 interpolate_: function ( i1, t0, t, t1 ) {
32696 const result = this.resultBuffer,
32697 values = this.sampleValues,
32698 stride = this.valueSize,
32700 o1 = i1 * stride, o0 = o1 - stride,
32701 oP = this._offsetPrev, oN = this._offsetNext,
32702 wP = this._weightPrev, wN = this._weightNext,
32704 p = ( t - t0 ) / ( t1 - t0 ),
32708 // evaluate polynomials
32710 const sP = - wP * ppp + 2 * wP * pp - wP * p;
32711 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
32712 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
32713 const sN = wN * ppp - wN * pp;
32715 // combine data linearly
32717 for ( let i = 0; i !== stride; ++ i ) {
32720 sP * values[ oP + i ] +
32721 s0 * values[ o0 + i ] +
32722 s1 * values[ o1 + i ] +
32723 sN * values[ oN + i ];
32733 function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
32735 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
32739 LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
32741 constructor: LinearInterpolant,
32743 interpolate_: function ( i1, t0, t, t1 ) {
32745 const result = this.resultBuffer,
32746 values = this.sampleValues,
32747 stride = this.valueSize,
32749 offset1 = i1 * stride,
32750 offset0 = offset1 - stride,
32752 weight1 = ( t - t0 ) / ( t1 - t0 ),
32753 weight0 = 1 - weight1;
32755 for ( let i = 0; i !== stride; ++ i ) {
32758 values[ offset0 + i ] * weight0 +
32759 values[ offset1 + i ] * weight1;
32771 * Interpolant that evaluates to the sample value at the position preceeding
32775 function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
32777 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
32781 DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
32783 constructor: DiscreteInterpolant,
32785 interpolate_: function ( i1 /*, t0, t, t1 */ ) {
32787 return this.copySampleValue_( i1 - 1 );
32793 function KeyframeTrack( name, times, values, interpolation ) {
32795 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
32796 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
32800 this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
32801 this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
32803 this.setInterpolation( interpolation || this.DefaultInterpolation );
32809 Object.assign( KeyframeTrack, {
32811 // Serialization (in static context, because of constructor invocation
32812 // and automatic invocation of .toJSON):
32814 toJSON: function ( track ) {
32816 const trackType = track.constructor;
32820 // derived classes can define a static toJSON method
32821 if ( trackType.toJSON !== undefined ) {
32823 json = trackType.toJSON( track );
32827 // by default, we assume the data can be serialized as-is
32830 'name': track.name,
32831 'times': AnimationUtils.convertArray( track.times, Array ),
32832 'values': AnimationUtils.convertArray( track.values, Array )
32836 const interpolation = track.getInterpolation();
32838 if ( interpolation !== track.DefaultInterpolation ) {
32840 json.interpolation = interpolation;
32846 json.type = track.ValueTypeName; // mandatory
32854 Object.assign( KeyframeTrack.prototype, {
32856 constructor: KeyframeTrack,
32858 TimeBufferType: Float32Array,
32860 ValueBufferType: Float32Array,
32862 DefaultInterpolation: InterpolateLinear,
32864 InterpolantFactoryMethodDiscrete: function ( result ) {
32866 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
32870 InterpolantFactoryMethodLinear: function ( result ) {
32872 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
32876 InterpolantFactoryMethodSmooth: function ( result ) {
32878 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
32882 setInterpolation: function ( interpolation ) {
32886 switch ( interpolation ) {
32888 case InterpolateDiscrete:
32890 factoryMethod = this.InterpolantFactoryMethodDiscrete;
32894 case InterpolateLinear:
32896 factoryMethod = this.InterpolantFactoryMethodLinear;
32900 case InterpolateSmooth:
32902 factoryMethod = this.InterpolantFactoryMethodSmooth;
32908 if ( factoryMethod === undefined ) {
32910 const message = 'unsupported interpolation for ' +
32911 this.ValueTypeName + ' keyframe track named ' + this.name;
32913 if ( this.createInterpolant === undefined ) {
32915 // fall back to default, unless the default itself is messed up
32916 if ( interpolation !== this.DefaultInterpolation ) {
32918 this.setInterpolation( this.DefaultInterpolation );
32922 throw new Error( message ); // fatal, in this case
32928 console.warn( 'THREE.KeyframeTrack:', message );
32933 this.createInterpolant = factoryMethod;
32939 getInterpolation: function () {
32941 switch ( this.createInterpolant ) {
32943 case this.InterpolantFactoryMethodDiscrete:
32945 return InterpolateDiscrete;
32947 case this.InterpolantFactoryMethodLinear:
32949 return InterpolateLinear;
32951 case this.InterpolantFactoryMethodSmooth:
32953 return InterpolateSmooth;
32959 getValueSize: function () {
32961 return this.values.length / this.times.length;
32965 // move all keyframes either forwards or backwards in time
32966 shift: function ( timeOffset ) {
32968 if ( timeOffset !== 0.0 ) {
32970 const times = this.times;
32972 for ( let i = 0, n = times.length; i !== n; ++ i ) {
32974 times[ i ] += timeOffset;
32984 // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
32985 scale: function ( timeScale ) {
32987 if ( timeScale !== 1.0 ) {
32989 const times = this.times;
32991 for ( let i = 0, n = times.length; i !== n; ++ i ) {
32993 times[ i ] *= timeScale;
33003 // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
33004 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
33005 trim: function ( startTime, endTime ) {
33007 const times = this.times,
33008 nKeys = times.length;
33013 while ( from !== nKeys && times[ from ] < startTime ) {
33019 while ( to !== - 1 && times[ to ] > endTime ) {
33025 ++ to; // inclusive -> exclusive bound
33027 if ( from !== 0 || to !== nKeys ) {
33029 // empty tracks are forbidden, so keep at least one keyframe
33030 if ( from >= to ) {
33032 to = Math.max( to, 1 );
33037 const stride = this.getValueSize();
33038 this.times = AnimationUtils.arraySlice( times, from, to );
33039 this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
33047 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
33048 validate: function () {
33052 const valueSize = this.getValueSize();
33053 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
33055 console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
33060 const times = this.times,
33061 values = this.values,
33063 nKeys = times.length;
33065 if ( nKeys === 0 ) {
33067 console.error( 'THREE.KeyframeTrack: Track is empty.', this );
33072 let prevTime = null;
33074 for ( let i = 0; i !== nKeys; i ++ ) {
33076 const currTime = times[ i ];
33078 if ( typeof currTime === 'number' && isNaN( currTime ) ) {
33080 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
33086 if ( prevTime !== null && prevTime > currTime ) {
33088 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
33094 prevTime = currTime;
33098 if ( values !== undefined ) {
33100 if ( AnimationUtils.isTypedArray( values ) ) {
33102 for ( let i = 0, n = values.length; i !== n; ++ i ) {
33104 const value = values[ i ];
33106 if ( isNaN( value ) ) {
33108 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
33124 // removes equivalent sequential keys as common in morph target sequences
33125 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
33126 optimize: function () {
33128 // times or values may be shared with other tracks, so overwriting is unsafe
33129 const times = AnimationUtils.arraySlice( this.times ),
33130 values = AnimationUtils.arraySlice( this.values ),
33131 stride = this.getValueSize(),
33133 smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
33135 lastIndex = times.length - 1;
33137 let writeIndex = 1;
33139 for ( let i = 1; i < lastIndex; ++ i ) {
33143 const time = times[ i ];
33144 const timeNext = times[ i + 1 ];
33146 // remove adjacent keyframes scheduled at the same time
33148 if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
33150 if ( ! smoothInterpolation ) {
33152 // remove unnecessary keyframes same as their neighbors
33154 const offset = i * stride,
33155 offsetP = offset - stride,
33156 offsetN = offset + stride;
33158 for ( let j = 0; j !== stride; ++ j ) {
33160 const value = values[ offset + j ];
33162 if ( value !== values[ offsetP + j ] ||
33163 value !== values[ offsetN + j ] ) {
33180 // in-place compaction
33184 if ( i !== writeIndex ) {
33186 times[ writeIndex ] = times[ i ];
33188 const readOffset = i * stride,
33189 writeOffset = writeIndex * stride;
33191 for ( let j = 0; j !== stride; ++ j ) {
33193 values[ writeOffset + j ] = values[ readOffset + j ];
33205 // flush last keyframe (compaction looks ahead)
33207 if ( lastIndex > 0 ) {
33209 times[ writeIndex ] = times[ lastIndex ];
33211 for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
33213 values[ writeOffset + j ] = values[ readOffset + j ];
33221 if ( writeIndex !== times.length ) {
33223 this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
33224 this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
33228 this.times = times;
33229 this.values = values;
33237 clone: function () {
33239 const times = AnimationUtils.arraySlice( this.times, 0 );
33240 const values = AnimationUtils.arraySlice( this.values, 0 );
33242 const TypedKeyframeTrack = this.constructor;
33243 const track = new TypedKeyframeTrack( this.name, times, values );
33245 // Interpolant argument to constructor is not saved, so copy the factory method directly.
33246 track.createInterpolant = this.createInterpolant;
33255 * A Track of Boolean keyframe values.
33258 function BooleanKeyframeTrack( name, times, values ) {
33260 KeyframeTrack.call( this, name, times, values );
33264 BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33266 constructor: BooleanKeyframeTrack,
33268 ValueTypeName: 'bool',
33269 ValueBufferType: Array,
33271 DefaultInterpolation: InterpolateDiscrete,
33273 InterpolantFactoryMethodLinear: undefined,
33274 InterpolantFactoryMethodSmooth: undefined
33276 // Note: Actually this track could have a optimized / compressed
33277 // representation of a single value and a custom interpolant that
33278 // computes "firstValue ^ isOdd( index )".
33283 * A Track of keyframe values that represent color.
33286 function ColorKeyframeTrack( name, times, values, interpolation ) {
33288 KeyframeTrack.call( this, name, times, values, interpolation );
33292 ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33294 constructor: ColorKeyframeTrack,
33296 ValueTypeName: 'color'
33298 // ValueBufferType is inherited
33300 // DefaultInterpolation is inherited
33302 // Note: Very basic implementation and nothing special yet.
33303 // However, this is the place for color space parameterization.
33308 * A Track of numeric keyframe values.
33311 function NumberKeyframeTrack( name, times, values, interpolation ) {
33313 KeyframeTrack.call( this, name, times, values, interpolation );
33317 NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33319 constructor: NumberKeyframeTrack,
33321 ValueTypeName: 'number'
33323 // ValueBufferType is inherited
33325 // DefaultInterpolation is inherited
33330 * Spherical linear unit quaternion interpolant.
33333 function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
33335 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
33339 QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
33341 constructor: QuaternionLinearInterpolant,
33343 interpolate_: function ( i1, t0, t, t1 ) {
33345 const result = this.resultBuffer,
33346 values = this.sampleValues,
33347 stride = this.valueSize,
33349 alpha = ( t - t0 ) / ( t1 - t0 );
33351 let offset = i1 * stride;
33353 for ( let end = offset + stride; offset !== end; offset += 4 ) {
33355 Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
33366 * A Track of quaternion keyframe values.
33369 function QuaternionKeyframeTrack( name, times, values, interpolation ) {
33371 KeyframeTrack.call( this, name, times, values, interpolation );
33375 QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33377 constructor: QuaternionKeyframeTrack,
33379 ValueTypeName: 'quaternion',
33381 // ValueBufferType is inherited
33383 DefaultInterpolation: InterpolateLinear,
33385 InterpolantFactoryMethodLinear: function ( result ) {
33387 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
33391 InterpolantFactoryMethodSmooth: undefined // not yet implemented
33396 * A Track that interpolates Strings
33399 function StringKeyframeTrack( name, times, values, interpolation ) {
33401 KeyframeTrack.call( this, name, times, values, interpolation );
33405 StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33407 constructor: StringKeyframeTrack,
33409 ValueTypeName: 'string',
33410 ValueBufferType: Array,
33412 DefaultInterpolation: InterpolateDiscrete,
33414 InterpolantFactoryMethodLinear: undefined,
33416 InterpolantFactoryMethodSmooth: undefined
33421 * A Track of vectored keyframe values.
33424 function VectorKeyframeTrack( name, times, values, interpolation ) {
33426 KeyframeTrack.call( this, name, times, values, interpolation );
33430 VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
33432 constructor: VectorKeyframeTrack,
33434 ValueTypeName: 'vector'
33436 // ValueBufferType is inherited
33438 // DefaultInterpolation is inherited
33442 function AnimationClip( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
33445 this.tracks = tracks;
33446 this.duration = duration;
33447 this.blendMode = blendMode;
33449 this.uuid = MathUtils.generateUUID();
33451 // this means it should figure out its duration by scanning the tracks
33452 if ( this.duration < 0 ) {
33454 this.resetDuration();
33460 function getTrackTypeForValueTypeName( typeName ) {
33462 switch ( typeName.toLowerCase() ) {
33470 return NumberKeyframeTrack;
33477 return VectorKeyframeTrack;
33481 return ColorKeyframeTrack;
33485 return QuaternionKeyframeTrack;
33490 return BooleanKeyframeTrack;
33494 return StringKeyframeTrack;
33498 throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
33502 function parseKeyframeTrack( json ) {
33504 if ( json.type === undefined ) {
33506 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
33510 const trackType = getTrackTypeForValueTypeName( json.type );
33512 if ( json.times === undefined ) {
33514 const times = [], values = [];
33516 AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
33518 json.times = times;
33519 json.values = values;
33523 // derived classes can define a static parse method
33524 if ( trackType.parse !== undefined ) {
33526 return trackType.parse( json );
33530 // by default, we assume a constructor compatible with the base
33531 return new trackType( json.name, json.times, json.values, json.interpolation );
33537 Object.assign( AnimationClip, {
33539 parse: function ( json ) {
33542 jsonTracks = json.tracks,
33543 frameTime = 1.0 / ( json.fps || 1.0 );
33545 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
33547 tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
33551 const clip = new AnimationClip( json.name, json.duration, tracks, json.blendMode );
33552 clip.uuid = json.uuid;
33558 toJSON: function ( clip ) {
33561 clipTracks = clip.tracks;
33566 'duration': clip.duration,
33569 'blendMode': clip.blendMode
33573 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
33575 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
33583 CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
33585 const numMorphTargets = morphTargetSequence.length;
33588 for ( let i = 0; i < numMorphTargets; i ++ ) {
33594 ( i + numMorphTargets - 1 ) % numMorphTargets,
33596 ( i + 1 ) % numMorphTargets );
33598 values.push( 0, 1, 0 );
33600 const order = AnimationUtils.getKeyframeOrder( times );
33601 times = AnimationUtils.sortedArray( times, 1, order );
33602 values = AnimationUtils.sortedArray( values, 1, order );
33604 // if there is a key at the first frame, duplicate it as the
33605 // last frame as well for perfect loop.
33606 if ( ! noLoop && times[ 0 ] === 0 ) {
33608 times.push( numMorphTargets );
33609 values.push( values[ 0 ] );
33614 new NumberKeyframeTrack(
33615 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
33617 ).scale( 1.0 / fps ) );
33621 return new AnimationClip( name, - 1, tracks );
33625 findByName: function ( objectOrClipArray, name ) {
33627 let clipArray = objectOrClipArray;
33629 if ( ! Array.isArray( objectOrClipArray ) ) {
33631 const o = objectOrClipArray;
33632 clipArray = o.geometry && o.geometry.animations || o.animations;
33636 for ( let i = 0; i < clipArray.length; i ++ ) {
33638 if ( clipArray[ i ].name === name ) {
33640 return clipArray[ i ];
33650 CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
33652 const animationToMorphTargets = {};
33654 // tested with https://regex101.com/ on trick sequences
33655 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
33656 const pattern = /^([\w-]*?)([\d]+)$/;
33658 // sort morph target names into animation groups based
33659 // patterns like Walk_001, Walk_002, Run_001, Run_002
33660 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
33662 const morphTarget = morphTargets[ i ];
33663 const parts = morphTarget.name.match( pattern );
33665 if ( parts && parts.length > 1 ) {
33667 const name = parts[ 1 ];
33669 let animationMorphTargets = animationToMorphTargets[ name ];
33671 if ( ! animationMorphTargets ) {
33673 animationToMorphTargets[ name ] = animationMorphTargets = [];
33677 animationMorphTargets.push( morphTarget );
33685 for ( const name in animationToMorphTargets ) {
33687 clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
33695 // parse the animation.hierarchy format
33696 parseAnimation: function ( animation, bones ) {
33698 if ( ! animation ) {
33700 console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
33705 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
33707 // only return track if there are actually keys.
33708 if ( animationKeys.length !== 0 ) {
33713 AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
33715 // empty keys are filtered out, so check again
33716 if ( times.length !== 0 ) {
33718 destTracks.push( new trackType( trackName, times, values ) );
33728 const clipName = animation.name || 'default';
33729 const fps = animation.fps || 30;
33730 const blendMode = animation.blendMode;
33732 // automatic length determination in AnimationClip.
33733 let duration = animation.length || - 1;
33735 const hierarchyTracks = animation.hierarchy || [];
33737 for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
33739 const animationKeys = hierarchyTracks[ h ].keys;
33741 // skip empty tracks
33742 if ( ! animationKeys || animationKeys.length === 0 ) continue;
33744 // process morph targets
33745 if ( animationKeys[ 0 ].morphTargets ) {
33747 // figure out all morph targets used in this track
33748 const morphTargetNames = {};
33752 for ( k = 0; k < animationKeys.length; k ++ ) {
33754 if ( animationKeys[ k ].morphTargets ) {
33756 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
33758 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
33766 // create a track for each morph target with all zero
33767 // morphTargetInfluences except for the keys in which
33768 // the morphTarget is named.
33769 for ( const morphTargetName in morphTargetNames ) {
33774 for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
33776 const animationKey = animationKeys[ k ];
33778 times.push( animationKey.time );
33779 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
33783 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
33787 duration = morphTargetNames.length * ( fps || 1.0 );
33791 // ...assume skeletal animation
33793 const boneName = '.bones[' + bones[ h ].name + ']';
33796 VectorKeyframeTrack, boneName + '.position',
33797 animationKeys, 'pos', tracks );
33800 QuaternionKeyframeTrack, boneName + '.quaternion',
33801 animationKeys, 'rot', tracks );
33804 VectorKeyframeTrack, boneName + '.scale',
33805 animationKeys, 'scl', tracks );
33811 if ( tracks.length === 0 ) {
33817 const clip = new AnimationClip( clipName, duration, tracks, blendMode );
33825 Object.assign( AnimationClip.prototype, {
33827 resetDuration: function () {
33829 const tracks = this.tracks;
33832 for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
33834 const track = this.tracks[ i ];
33836 duration = Math.max( duration, track.times[ track.times.length - 1 ] );
33840 this.duration = duration;
33846 trim: function () {
33848 for ( let i = 0; i < this.tracks.length; i ++ ) {
33850 this.tracks[ i ].trim( 0, this.duration );
33858 validate: function () {
33862 for ( let i = 0; i < this.tracks.length; i ++ ) {
33864 valid = valid && this.tracks[ i ].validate();
33872 optimize: function () {
33874 for ( let i = 0; i < this.tracks.length; i ++ ) {
33876 this.tracks[ i ].optimize();
33884 clone: function () {
33888 for ( let i = 0; i < this.tracks.length; i ++ ) {
33890 tracks.push( this.tracks[ i ].clone() );
33894 return new AnimationClip( this.name, this.duration, tracks, this.blendMode );
33898 toJSON: function () {
33900 return AnimationClip.toJSON( this );
33912 add: function ( key, file ) {
33914 if ( this.enabled === false ) return;
33916 // console.log( 'THREE.Cache', 'Adding key:', key );
33918 this.files[ key ] = file;
33922 get: function ( key ) {
33924 if ( this.enabled === false ) return;
33926 // console.log( 'THREE.Cache', 'Checking key:', key );
33928 return this.files[ key ];
33932 remove: function ( key ) {
33934 delete this.files[ key ];
33938 clear: function () {
33946 function LoadingManager( onLoad, onProgress, onError ) {
33948 const scope = this;
33950 let isLoading = false;
33951 let itemsLoaded = 0;
33952 let itemsTotal = 0;
33953 let urlModifier = undefined;
33954 const handlers = [];
33956 // Refer to #5689 for the reason why we don't set .onStart
33957 // in the constructor
33959 this.onStart = undefined;
33960 this.onLoad = onLoad;
33961 this.onProgress = onProgress;
33962 this.onError = onError;
33964 this.itemStart = function ( url ) {
33968 if ( isLoading === false ) {
33970 if ( scope.onStart !== undefined ) {
33972 scope.onStart( url, itemsLoaded, itemsTotal );
33982 this.itemEnd = function ( url ) {
33986 if ( scope.onProgress !== undefined ) {
33988 scope.onProgress( url, itemsLoaded, itemsTotal );
33992 if ( itemsLoaded === itemsTotal ) {
33996 if ( scope.onLoad !== undefined ) {
34006 this.itemError = function ( url ) {
34008 if ( scope.onError !== undefined ) {
34010 scope.onError( url );
34016 this.resolveURL = function ( url ) {
34018 if ( urlModifier ) {
34020 return urlModifier( url );
34028 this.setURLModifier = function ( transform ) {
34030 urlModifier = transform;
34036 this.addHandler = function ( regex, loader ) {
34038 handlers.push( regex, loader );
34044 this.removeHandler = function ( regex ) {
34046 const index = handlers.indexOf( regex );
34048 if ( index !== - 1 ) {
34050 handlers.splice( index, 2 );
34058 this.getHandler = function ( file ) {
34060 for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
34062 const regex = handlers[ i ];
34063 const loader = handlers[ i + 1 ];
34065 if ( regex.global ) regex.lastIndex = 0; // see #17920
34067 if ( regex.test( file ) ) {
34081 const DefaultLoadingManager = new LoadingManager();
34083 function Loader( manager ) {
34085 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
34087 this.crossOrigin = 'anonymous';
34088 this.withCredentials = false;
34090 this.resourcePath = '';
34091 this.requestHeader = {};
34095 Object.assign( Loader.prototype, {
34097 load: function ( /* url, onLoad, onProgress, onError */ ) {},
34099 loadAsync: function ( url, onProgress ) {
34101 const scope = this;
34103 return new Promise( function ( resolve, reject ) {
34105 scope.load( url, resolve, onProgress, reject );
34111 parse: function ( /* data */ ) {},
34113 setCrossOrigin: function ( crossOrigin ) {
34115 this.crossOrigin = crossOrigin;
34120 setWithCredentials: function ( value ) {
34122 this.withCredentials = value;
34127 setPath: function ( path ) {
34134 setResourcePath: function ( resourcePath ) {
34136 this.resourcePath = resourcePath;
34141 setRequestHeader: function ( requestHeader ) {
34143 this.requestHeader = requestHeader;
34150 const loading = {};
34152 function FileLoader( manager ) {
34154 Loader.call( this, manager );
34158 FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34160 constructor: FileLoader,
34162 load: function ( url, onLoad, onProgress, onError ) {
34164 if ( url === undefined ) url = '';
34166 if ( this.path !== undefined ) url = this.path + url;
34168 url = this.manager.resolveURL( url );
34170 const scope = this;
34172 const cached = Cache.get( url );
34174 if ( cached !== undefined ) {
34176 scope.manager.itemStart( url );
34178 setTimeout( function () {
34180 if ( onLoad ) onLoad( cached );
34182 scope.manager.itemEnd( url );
34190 // Check if request is duplicate
34192 if ( loading[ url ] !== undefined ) {
34194 loading[ url ].push( {
34197 onProgress: onProgress,
34206 // Check for data: URI
34207 const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
34208 const dataUriRegexResult = url.match( dataUriRegex );
34211 // Safari can not handle Data URIs through XMLHttpRequest so process manually
34212 if ( dataUriRegexResult ) {
34214 const mimeType = dataUriRegexResult[ 1 ];
34215 const isBase64 = !! dataUriRegexResult[ 2 ];
34217 let data = dataUriRegexResult[ 3 ];
34218 data = decodeURIComponent( data );
34220 if ( isBase64 ) data = atob( data );
34225 const responseType = ( this.responseType || '' ).toLowerCase();
34227 switch ( responseType ) {
34229 case 'arraybuffer':
34232 const view = new Uint8Array( data.length );
34234 for ( let i = 0; i < data.length; i ++ ) {
34236 view[ i ] = data.charCodeAt( i );
34240 if ( responseType === 'blob' ) {
34242 response = new Blob( [ view.buffer ], { type: mimeType } );
34246 response = view.buffer;
34254 const parser = new DOMParser();
34255 response = parser.parseFromString( data, mimeType );
34261 response = JSON.parse( data );
34265 default: // 'text' or other
34273 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
34274 setTimeout( function () {
34276 if ( onLoad ) onLoad( response );
34278 scope.manager.itemEnd( url );
34282 } catch ( error ) {
34284 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
34285 setTimeout( function () {
34287 if ( onError ) onError( error );
34289 scope.manager.itemError( url );
34290 scope.manager.itemEnd( url );
34298 // Initialise array for duplicate requests
34300 loading[ url ] = [];
34302 loading[ url ].push( {
34305 onProgress: onProgress,
34310 request = new XMLHttpRequest();
34312 request.open( 'GET', url, true );
34314 request.addEventListener( 'load', function ( event ) {
34316 const response = this.response;
34318 const callbacks = loading[ url ];
34320 delete loading[ url ];
34322 if ( this.status === 200 || this.status === 0 ) {
34324 // Some browsers return HTTP Status 0 when using non-http protocol
34325 // e.g. 'file://' or 'data://'. Handle as success.
34327 if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
34329 // Add to cache only on HTTP success, so that we do not cache
34330 // error response bodies as proper responses to requests.
34331 Cache.add( url, response );
34333 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
34335 const callback = callbacks[ i ];
34336 if ( callback.onLoad ) callback.onLoad( response );
34340 scope.manager.itemEnd( url );
34344 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
34346 const callback = callbacks[ i ];
34347 if ( callback.onError ) callback.onError( event );
34351 scope.manager.itemError( url );
34352 scope.manager.itemEnd( url );
34358 request.addEventListener( 'progress', function ( event ) {
34360 const callbacks = loading[ url ];
34362 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
34364 const callback = callbacks[ i ];
34365 if ( callback.onProgress ) callback.onProgress( event );
34371 request.addEventListener( 'error', function ( event ) {
34373 const callbacks = loading[ url ];
34375 delete loading[ url ];
34377 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
34379 const callback = callbacks[ i ];
34380 if ( callback.onError ) callback.onError( event );
34384 scope.manager.itemError( url );
34385 scope.manager.itemEnd( url );
34389 request.addEventListener( 'abort', function ( event ) {
34391 const callbacks = loading[ url ];
34393 delete loading[ url ];
34395 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
34397 const callback = callbacks[ i ];
34398 if ( callback.onError ) callback.onError( event );
34402 scope.manager.itemError( url );
34403 scope.manager.itemEnd( url );
34407 if ( this.responseType !== undefined ) request.responseType = this.responseType;
34408 if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
34410 if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
34412 for ( const header in this.requestHeader ) {
34414 request.setRequestHeader( header, this.requestHeader[ header ] );
34418 request.send( null );
34422 scope.manager.itemStart( url );
34428 setResponseType: function ( value ) {
34430 this.responseType = value;
34435 setMimeType: function ( value ) {
34437 this.mimeType = value;
34444 function AnimationLoader( manager ) {
34446 Loader.call( this, manager );
34450 AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34452 constructor: AnimationLoader,
34454 load: function ( url, onLoad, onProgress, onError ) {
34456 const scope = this;
34458 const loader = new FileLoader( scope.manager );
34459 loader.setPath( scope.path );
34460 loader.setRequestHeader( scope.requestHeader );
34461 loader.setWithCredentials( scope.withCredentials );
34462 loader.load( url, function ( text ) {
34466 onLoad( scope.parse( JSON.parse( text ) ) );
34476 console.error( e );
34480 scope.manager.itemError( url );
34484 }, onProgress, onError );
34488 parse: function ( json ) {
34490 const animations = [];
34492 for ( let i = 0; i < json.length; i ++ ) {
34494 const clip = AnimationClip.parse( json[ i ] );
34496 animations.push( clip );
34507 * Abstract Base class to block based textures loader (dds, pvr, ...)
34509 * Sub classes have to implement the parse() method which will be used in load().
34512 function CompressedTextureLoader( manager ) {
34514 Loader.call( this, manager );
34518 CompressedTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34520 constructor: CompressedTextureLoader,
34522 load: function ( url, onLoad, onProgress, onError ) {
34524 const scope = this;
34528 const texture = new CompressedTexture();
34530 const loader = new FileLoader( this.manager );
34531 loader.setPath( this.path );
34532 loader.setResponseType( 'arraybuffer' );
34533 loader.setRequestHeader( this.requestHeader );
34534 loader.setWithCredentials( scope.withCredentials );
34538 function loadTexture( i ) {
34540 loader.load( url[ i ], function ( buffer ) {
34542 const texDatas = scope.parse( buffer, true );
34545 width: texDatas.width,
34546 height: texDatas.height,
34547 format: texDatas.format,
34548 mipmaps: texDatas.mipmaps
34553 if ( loaded === 6 ) {
34555 if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
34557 texture.image = images;
34558 texture.format = texDatas.format;
34559 texture.needsUpdate = true;
34561 if ( onLoad ) onLoad( texture );
34565 }, onProgress, onError );
34569 if ( Array.isArray( url ) ) {
34571 for ( let i = 0, il = url.length; i < il; ++ i ) {
34579 // compressed cubemap texture stored in a single DDS file
34581 loader.load( url, function ( buffer ) {
34583 const texDatas = scope.parse( buffer, true );
34585 if ( texDatas.isCubemap ) {
34587 const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
34589 for ( let f = 0; f < faces; f ++ ) {
34591 images[ f ] = { mipmaps: [] };
34593 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
34595 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
34596 images[ f ].format = texDatas.format;
34597 images[ f ].width = texDatas.width;
34598 images[ f ].height = texDatas.height;
34604 texture.image = images;
34608 texture.image.width = texDatas.width;
34609 texture.image.height = texDatas.height;
34610 texture.mipmaps = texDatas.mipmaps;
34614 if ( texDatas.mipmapCount === 1 ) {
34616 texture.minFilter = LinearFilter;
34620 texture.format = texDatas.format;
34621 texture.needsUpdate = true;
34623 if ( onLoad ) onLoad( texture );
34625 }, onProgress, onError );
34635 function ImageLoader( manager ) {
34637 Loader.call( this, manager );
34641 ImageLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34643 constructor: ImageLoader,
34645 load: function ( url, onLoad, onProgress, onError ) {
34647 if ( this.path !== undefined ) url = this.path + url;
34649 url = this.manager.resolveURL( url );
34651 const scope = this;
34653 const cached = Cache.get( url );
34655 if ( cached !== undefined ) {
34657 scope.manager.itemStart( url );
34659 setTimeout( function () {
34661 if ( onLoad ) onLoad( cached );
34663 scope.manager.itemEnd( url );
34671 const image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
34673 function onImageLoad() {
34675 image.removeEventListener( 'load', onImageLoad, false );
34676 image.removeEventListener( 'error', onImageError, false );
34678 Cache.add( url, this );
34680 if ( onLoad ) onLoad( this );
34682 scope.manager.itemEnd( url );
34686 function onImageError( event ) {
34688 image.removeEventListener( 'load', onImageLoad, false );
34689 image.removeEventListener( 'error', onImageError, false );
34691 if ( onError ) onError( event );
34693 scope.manager.itemError( url );
34694 scope.manager.itemEnd( url );
34698 image.addEventListener( 'load', onImageLoad, false );
34699 image.addEventListener( 'error', onImageError, false );
34701 if ( url.substr( 0, 5 ) !== 'data:' ) {
34703 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
34707 scope.manager.itemStart( url );
34717 function CubeTextureLoader( manager ) {
34719 Loader.call( this, manager );
34723 CubeTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34725 constructor: CubeTextureLoader,
34727 load: function ( urls, onLoad, onProgress, onError ) {
34729 const texture = new CubeTexture();
34731 const loader = new ImageLoader( this.manager );
34732 loader.setCrossOrigin( this.crossOrigin );
34733 loader.setPath( this.path );
34737 function loadTexture( i ) {
34739 loader.load( urls[ i ], function ( image ) {
34741 texture.images[ i ] = image;
34745 if ( loaded === 6 ) {
34747 texture.needsUpdate = true;
34749 if ( onLoad ) onLoad( texture );
34753 }, undefined, onError );
34757 for ( let i = 0; i < urls.length; ++ i ) {
34770 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
34772 * Sub classes have to implement the parse() method which will be used in load().
34775 function DataTextureLoader( manager ) {
34777 Loader.call( this, manager );
34781 DataTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34783 constructor: DataTextureLoader,
34785 load: function ( url, onLoad, onProgress, onError ) {
34787 const scope = this;
34789 const texture = new DataTexture();
34791 const loader = new FileLoader( this.manager );
34792 loader.setResponseType( 'arraybuffer' );
34793 loader.setRequestHeader( this.requestHeader );
34794 loader.setPath( this.path );
34795 loader.setWithCredentials( scope.withCredentials );
34796 loader.load( url, function ( buffer ) {
34798 const texData = scope.parse( buffer );
34800 if ( ! texData ) return;
34802 if ( texData.image !== undefined ) {
34804 texture.image = texData.image;
34806 } else if ( texData.data !== undefined ) {
34808 texture.image.width = texData.width;
34809 texture.image.height = texData.height;
34810 texture.image.data = texData.data;
34814 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
34815 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
34817 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
34818 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
34820 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
34822 if ( texData.encoding !== undefined ) {
34824 texture.encoding = texData.encoding;
34828 if ( texData.flipY !== undefined ) {
34830 texture.flipY = texData.flipY;
34834 if ( texData.format !== undefined ) {
34836 texture.format = texData.format;
34840 if ( texData.type !== undefined ) {
34842 texture.type = texData.type;
34846 if ( texData.mipmaps !== undefined ) {
34848 texture.mipmaps = texData.mipmaps;
34849 texture.minFilter = LinearMipmapLinearFilter; // presumably...
34853 if ( texData.mipmapCount === 1 ) {
34855 texture.minFilter = LinearFilter;
34859 texture.needsUpdate = true;
34861 if ( onLoad ) onLoad( texture, texData );
34863 }, onProgress, onError );
34872 function TextureLoader( manager ) {
34874 Loader.call( this, manager );
34878 TextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
34880 constructor: TextureLoader,
34882 load: function ( url, onLoad, onProgress, onError ) {
34884 const texture = new Texture();
34886 const loader = new ImageLoader( this.manager );
34887 loader.setCrossOrigin( this.crossOrigin );
34888 loader.setPath( this.path );
34890 loader.load( url, function ( image ) {
34892 texture.image = image;
34894 // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
34895 const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
34897 texture.format = isJPEG ? RGBFormat : RGBAFormat;
34898 texture.needsUpdate = true;
34900 if ( onLoad !== undefined ) {
34906 }, onProgress, onError );
34915 * Extensible curve object.
34917 * Some common of curve methods:
34918 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
34919 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
34920 * .getPoints(), .getSpacedPoints()
34922 * .updateArcLengths()
34924 * This following curves inherit from THREE.Curve:
34928 * THREE.CubicBezierCurve
34929 * THREE.EllipseCurve
34931 * THREE.QuadraticBezierCurve
34932 * THREE.SplineCurve
34935 * THREE.CatmullRomCurve3
34936 * THREE.CubicBezierCurve3
34938 * THREE.QuadraticBezierCurve3
34940 * A series of curves can be represented as a THREE.CurvePath.
34946 this.type = 'Curve';
34948 this.arcLengthDivisions = 200;
34952 Object.assign( Curve.prototype, {
34954 // Virtual base class method to overwrite and implement in subclasses
34957 getPoint: function ( /* t, optionalTarget */ ) {
34959 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
34964 // Get point at relative position in curve according to arc length
34967 getPointAt: function ( u, optionalTarget ) {
34969 const t = this.getUtoTmapping( u );
34970 return this.getPoint( t, optionalTarget );
34974 // Get sequence of points using getPoint( t )
34976 getPoints: function ( divisions = 5 ) {
34980 for ( let d = 0; d <= divisions; d ++ ) {
34982 points.push( this.getPoint( d / divisions ) );
34990 // Get sequence of points using getPointAt( u )
34992 getSpacedPoints: function ( divisions = 5 ) {
34996 for ( let d = 0; d <= divisions; d ++ ) {
34998 points.push( this.getPointAt( d / divisions ) );
35006 // Get total curve arc length
35008 getLength: function () {
35010 const lengths = this.getLengths();
35011 return lengths[ lengths.length - 1 ];
35015 // Get list of cumulative segment lengths
35017 getLengths: function ( divisions ) {
35019 if ( divisions === undefined ) divisions = this.arcLengthDivisions;
35021 if ( this.cacheArcLengths &&
35022 ( this.cacheArcLengths.length === divisions + 1 ) &&
35023 ! this.needsUpdate ) {
35025 return this.cacheArcLengths;
35029 this.needsUpdate = false;
35032 let current, last = this.getPoint( 0 );
35037 for ( let p = 1; p <= divisions; p ++ ) {
35039 current = this.getPoint( p / divisions );
35040 sum += current.distanceTo( last );
35046 this.cacheArcLengths = cache;
35048 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
35052 updateArcLengths: function () {
35054 this.needsUpdate = true;
35059 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
35061 getUtoTmapping: function ( u, distance ) {
35063 const arcLengths = this.getLengths();
35066 const il = arcLengths.length;
35068 let targetArcLength; // The targeted u distance value to get
35072 targetArcLength = distance;
35076 targetArcLength = u * arcLengths[ il - 1 ];
35080 // binary search for the index with largest value smaller than target u distance
35082 let low = 0, high = il - 1, comparison;
35084 while ( low <= high ) {
35086 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
35088 comparison = arcLengths[ i ] - targetArcLength;
35090 if ( comparison < 0 ) {
35094 } else if ( comparison > 0 ) {
35111 if ( arcLengths[ i ] === targetArcLength ) {
35113 return i / ( il - 1 );
35117 // we could get finer grain at lengths, or use simple interpolation between two points
35119 const lengthBefore = arcLengths[ i ];
35120 const lengthAfter = arcLengths[ i + 1 ];
35122 const segmentLength = lengthAfter - lengthBefore;
35124 // determine where we are between the 'before' and 'after' points
35126 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
35128 // add that fractional amount to t
35130 const t = ( i + segmentFraction ) / ( il - 1 );
35136 // Returns a unit vector tangent at t
35137 // In case any sub curve does not implement its tangent derivation,
35138 // 2 points a small delta apart will be used to find its gradient
35139 // which seems to give a reasonable approximation
35141 getTangent: function ( t, optionalTarget ) {
35143 const delta = 0.0001;
35144 let t1 = t - delta;
35145 let t2 = t + delta;
35147 // Capping in case of danger
35149 if ( t1 < 0 ) t1 = 0;
35150 if ( t2 > 1 ) t2 = 1;
35152 const pt1 = this.getPoint( t1 );
35153 const pt2 = this.getPoint( t2 );
35155 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
35157 tangent.copy( pt2 ).sub( pt1 ).normalize();
35163 getTangentAt: function ( u, optionalTarget ) {
35165 const t = this.getUtoTmapping( u );
35166 return this.getTangent( t, optionalTarget );
35170 computeFrenetFrames: function ( segments, closed ) {
35172 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
35174 const normal = new Vector3();
35176 const tangents = [];
35177 const normals = [];
35178 const binormals = [];
35180 const vec = new Vector3();
35181 const mat = new Matrix4();
35183 // compute the tangent vectors for each segment on the curve
35185 for ( let i = 0; i <= segments; i ++ ) {
35187 const u = i / segments;
35189 tangents[ i ] = this.getTangentAt( u, new Vector3() );
35190 tangents[ i ].normalize();
35194 // select an initial normal vector perpendicular to the first tangent vector,
35195 // and in the direction of the minimum tangent xyz component
35197 normals[ 0 ] = new Vector3();
35198 binormals[ 0 ] = new Vector3();
35199 let min = Number.MAX_VALUE;
35200 const tx = Math.abs( tangents[ 0 ].x );
35201 const ty = Math.abs( tangents[ 0 ].y );
35202 const tz = Math.abs( tangents[ 0 ].z );
35207 normal.set( 1, 0, 0 );
35214 normal.set( 0, 1, 0 );
35220 normal.set( 0, 0, 1 );
35224 vec.crossVectors( tangents[ 0 ], normal ).normalize();
35226 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
35227 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
35230 // compute the slowly-varying normal and binormal vectors for each segment on the curve
35232 for ( let i = 1; i <= segments; i ++ ) {
35234 normals[ i ] = normals[ i - 1 ].clone();
35236 binormals[ i ] = binormals[ i - 1 ].clone();
35238 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
35240 if ( vec.length() > Number.EPSILON ) {
35244 const theta = Math.acos( MathUtils.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
35246 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
35250 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35254 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
35256 if ( closed === true ) {
35258 let theta = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
35261 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
35267 for ( let i = 1; i <= segments; i ++ ) {
35269 // twist a little...
35270 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
35271 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35278 tangents: tangents,
35280 binormals: binormals
35285 clone: function () {
35287 return new this.constructor().copy( this );
35291 copy: function ( source ) {
35293 this.arcLengthDivisions = source.arcLengthDivisions;
35299 toJSON: function () {
35305 generator: 'Curve.toJSON'
35309 data.arcLengthDivisions = this.arcLengthDivisions;
35310 data.type = this.type;
35316 fromJSON: function ( json ) {
35318 this.arcLengthDivisions = json.arcLengthDivisions;
35326 function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
35328 Curve.call( this );
35330 this.type = 'EllipseCurve';
35335 this.xRadius = xRadius || 1;
35336 this.yRadius = yRadius || 1;
35338 this.aStartAngle = aStartAngle || 0;
35339 this.aEndAngle = aEndAngle || 2 * Math.PI;
35341 this.aClockwise = aClockwise || false;
35343 this.aRotation = aRotation || 0;
35347 EllipseCurve.prototype = Object.create( Curve.prototype );
35348 EllipseCurve.prototype.constructor = EllipseCurve;
35350 EllipseCurve.prototype.isEllipseCurve = true;
35352 EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) {
35354 const point = optionalTarget || new Vector2();
35356 const twoPi = Math.PI * 2;
35357 let deltaAngle = this.aEndAngle - this.aStartAngle;
35358 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
35360 // ensures that deltaAngle is 0 .. 2 PI
35361 while ( deltaAngle < 0 ) deltaAngle += twoPi;
35362 while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
35364 if ( deltaAngle < Number.EPSILON ) {
35366 if ( samePoints ) {
35372 deltaAngle = twoPi;
35378 if ( this.aClockwise === true && ! samePoints ) {
35380 if ( deltaAngle === twoPi ) {
35382 deltaAngle = - twoPi;
35386 deltaAngle = deltaAngle - twoPi;
35392 const angle = this.aStartAngle + t * deltaAngle;
35393 let x = this.aX + this.xRadius * Math.cos( angle );
35394 let y = this.aY + this.yRadius * Math.sin( angle );
35396 if ( this.aRotation !== 0 ) {
35398 const cos = Math.cos( this.aRotation );
35399 const sin = Math.sin( this.aRotation );
35401 const tx = x - this.aX;
35402 const ty = y - this.aY;
35404 // Rotate the point about the center of the ellipse.
35405 x = tx * cos - ty * sin + this.aX;
35406 y = tx * sin + ty * cos + this.aY;
35410 return point.set( x, y );
35414 EllipseCurve.prototype.copy = function ( source ) {
35416 Curve.prototype.copy.call( this, source );
35418 this.aX = source.aX;
35419 this.aY = source.aY;
35421 this.xRadius = source.xRadius;
35422 this.yRadius = source.yRadius;
35424 this.aStartAngle = source.aStartAngle;
35425 this.aEndAngle = source.aEndAngle;
35427 this.aClockwise = source.aClockwise;
35429 this.aRotation = source.aRotation;
35436 EllipseCurve.prototype.toJSON = function () {
35438 const data = Curve.prototype.toJSON.call( this );
35443 data.xRadius = this.xRadius;
35444 data.yRadius = this.yRadius;
35446 data.aStartAngle = this.aStartAngle;
35447 data.aEndAngle = this.aEndAngle;
35449 data.aClockwise = this.aClockwise;
35451 data.aRotation = this.aRotation;
35457 EllipseCurve.prototype.fromJSON = function ( json ) {
35459 Curve.prototype.fromJSON.call( this, json );
35464 this.xRadius = json.xRadius;
35465 this.yRadius = json.yRadius;
35467 this.aStartAngle = json.aStartAngle;
35468 this.aEndAngle = json.aEndAngle;
35470 this.aClockwise = json.aClockwise;
35472 this.aRotation = json.aRotation;
35478 function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35480 EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
35482 this.type = 'ArcCurve';
35486 ArcCurve.prototype = Object.create( EllipseCurve.prototype );
35487 ArcCurve.prototype.constructor = ArcCurve;
35489 ArcCurve.prototype.isArcCurve = true;
35492 * Centripetal CatmullRom Curve - which is useful for avoiding
35493 * cusps and self-intersections in non-uniform catmull rom curves.
35494 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
35496 * curve.type accepts centripetal(default), chordal and catmullrom
35497 * curve.tension is used for catmullrom which defaults to 0.5
35502 Based on an optimized c++ solution in
35503 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
35504 - http://ideone.com/NoEbVM
35506 This CubicPoly class could be used for reusing some variables and calculations,
35507 but for three.js curve use, it could be possible inlined and flatten into a single function call
35508 which can be placed in CurveUtils.
35511 function CubicPoly() {
35513 let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
35516 * Compute coefficients for a cubic polynomial
35517 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
35519 * p(0) = x0, p(1) = x1
35521 * p'(0) = t0, p'(1) = t1.
35523 function init( x0, x1, t0, t1 ) {
35527 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
35528 c3 = 2 * x0 - 2 * x1 + t0 + t1;
35534 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
35536 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
35540 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
35542 // compute tangents when parameterized in [t1,t2]
35543 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
35544 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
35546 // rescale tangents for parametrization in [0,1]
35550 init( x1, x2, t1, t2 );
35554 calc: function ( t ) {
35558 return c0 + c1 * t + c2 * t2 + c3 * t3;
35568 const tmp = new Vector3();
35569 const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
35571 function CatmullRomCurve3( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
35573 Curve.call( this );
35575 this.type = 'CatmullRomCurve3';
35577 this.points = points;
35578 this.closed = closed;
35579 this.curveType = curveType;
35580 this.tension = tension;
35584 CatmullRomCurve3.prototype = Object.create( Curve.prototype );
35585 CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
35587 CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
35589 CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
35591 const point = optionalTarget;
35593 const points = this.points;
35594 const l = points.length;
35596 const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
35597 let intPoint = Math.floor( p );
35598 let weight = p - intPoint;
35600 if ( this.closed ) {
35602 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
35604 } else if ( weight === 0 && intPoint === l - 1 ) {
35611 let p0, p3; // 4 points (p1 & p2 defined below)
35613 if ( this.closed || intPoint > 0 ) {
35615 p0 = points[ ( intPoint - 1 ) % l ];
35619 // extrapolate first point
35620 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
35625 const p1 = points[ intPoint % l ];
35626 const p2 = points[ ( intPoint + 1 ) % l ];
35628 if ( this.closed || intPoint + 2 < l ) {
35630 p3 = points[ ( intPoint + 2 ) % l ];
35634 // extrapolate last point
35635 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
35640 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
35642 // init Centripetal / Chordal Catmull-Rom
35643 const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
35644 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
35645 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
35646 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
35648 // safety check for repeated points
35649 if ( dt1 < 1e-4 ) dt1 = 1.0;
35650 if ( dt0 < 1e-4 ) dt0 = dt1;
35651 if ( dt2 < 1e-4 ) dt2 = dt1;
35653 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
35654 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
35655 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
35657 } else if ( this.curveType === 'catmullrom' ) {
35659 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
35660 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
35661 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
35675 CatmullRomCurve3.prototype.copy = function ( source ) {
35677 Curve.prototype.copy.call( this, source );
35681 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35683 const point = source.points[ i ];
35685 this.points.push( point.clone() );
35689 this.closed = source.closed;
35690 this.curveType = source.curveType;
35691 this.tension = source.tension;
35697 CatmullRomCurve3.prototype.toJSON = function () {
35699 const data = Curve.prototype.toJSON.call( this );
35703 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35705 const point = this.points[ i ];
35706 data.points.push( point.toArray() );
35710 data.closed = this.closed;
35711 data.curveType = this.curveType;
35712 data.tension = this.tension;
35718 CatmullRomCurve3.prototype.fromJSON = function ( json ) {
35720 Curve.prototype.fromJSON.call( this, json );
35724 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35726 const point = json.points[ i ];
35727 this.points.push( new Vector3().fromArray( point ) );
35731 this.closed = json.closed;
35732 this.curveType = json.curveType;
35733 this.tension = json.tension;
35740 * Bezier Curves formulas obtained from
35741 * http://en.wikipedia.org/wiki/Bézier_curve
35744 function CatmullRom( t, p0, p1, p2, p3 ) {
35746 const v0 = ( p2 - p0 ) * 0.5;
35747 const v1 = ( p3 - p1 ) * 0.5;
35750 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
35756 function QuadraticBezierP0( t, p ) {
35763 function QuadraticBezierP1( t, p ) {
35765 return 2 * ( 1 - t ) * t * p;
35769 function QuadraticBezierP2( t, p ) {
35775 function QuadraticBezier( t, p0, p1, p2 ) {
35777 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
35778 QuadraticBezierP2( t, p2 );
35784 function CubicBezierP0( t, p ) {
35787 return k * k * k * p;
35791 function CubicBezierP1( t, p ) {
35794 return 3 * k * k * t * p;
35798 function CubicBezierP2( t, p ) {
35800 return 3 * ( 1 - t ) * t * t * p;
35804 function CubicBezierP3( t, p ) {
35806 return t * t * t * p;
35810 function CubicBezier( t, p0, p1, p2, p3 ) {
35812 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
35813 CubicBezierP3( t, p3 );
35817 function CubicBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
35819 Curve.call( this );
35821 this.type = 'CubicBezierCurve';
35830 CubicBezierCurve.prototype = Object.create( Curve.prototype );
35831 CubicBezierCurve.prototype.constructor = CubicBezierCurve;
35833 CubicBezierCurve.prototype.isCubicBezierCurve = true;
35835 CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
35837 const point = optionalTarget;
35839 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35842 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35843 CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
35850 CubicBezierCurve.prototype.copy = function ( source ) {
35852 Curve.prototype.copy.call( this, source );
35854 this.v0.copy( source.v0 );
35855 this.v1.copy( source.v1 );
35856 this.v2.copy( source.v2 );
35857 this.v3.copy( source.v3 );
35863 CubicBezierCurve.prototype.toJSON = function () {
35865 const data = Curve.prototype.toJSON.call( this );
35867 data.v0 = this.v0.toArray();
35868 data.v1 = this.v1.toArray();
35869 data.v2 = this.v2.toArray();
35870 data.v3 = this.v3.toArray();
35876 CubicBezierCurve.prototype.fromJSON = function ( json ) {
35878 Curve.prototype.fromJSON.call( this, json );
35880 this.v0.fromArray( json.v0 );
35881 this.v1.fromArray( json.v1 );
35882 this.v2.fromArray( json.v2 );
35883 this.v3.fromArray( json.v3 );
35889 function CubicBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
35891 Curve.call( this );
35893 this.type = 'CubicBezierCurve3';
35902 CubicBezierCurve3.prototype = Object.create( Curve.prototype );
35903 CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
35905 CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
35907 CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
35909 const point = optionalTarget;
35911 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35914 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35915 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
35916 CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
35923 CubicBezierCurve3.prototype.copy = function ( source ) {
35925 Curve.prototype.copy.call( this, source );
35927 this.v0.copy( source.v0 );
35928 this.v1.copy( source.v1 );
35929 this.v2.copy( source.v2 );
35930 this.v3.copy( source.v3 );
35936 CubicBezierCurve3.prototype.toJSON = function () {
35938 const data = Curve.prototype.toJSON.call( this );
35940 data.v0 = this.v0.toArray();
35941 data.v1 = this.v1.toArray();
35942 data.v2 = this.v2.toArray();
35943 data.v3 = this.v3.toArray();
35949 CubicBezierCurve3.prototype.fromJSON = function ( json ) {
35951 Curve.prototype.fromJSON.call( this, json );
35953 this.v0.fromArray( json.v0 );
35954 this.v1.fromArray( json.v1 );
35955 this.v2.fromArray( json.v2 );
35956 this.v3.fromArray( json.v3 );
35962 function LineCurve( v1 = new Vector2(), v2 = new Vector2() ) {
35964 Curve.call( this );
35966 this.type = 'LineCurve';
35973 LineCurve.prototype = Object.create( Curve.prototype );
35974 LineCurve.prototype.constructor = LineCurve;
35976 LineCurve.prototype.isLineCurve = true;
35978 LineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
35980 const point = optionalTarget;
35984 point.copy( this.v2 );
35988 point.copy( this.v2 ).sub( this.v1 );
35989 point.multiplyScalar( t ).add( this.v1 );
35997 // Line curve is linear, so we can overwrite default getPointAt
35999 LineCurve.prototype.getPointAt = function ( u, optionalTarget ) {
36001 return this.getPoint( u, optionalTarget );
36005 LineCurve.prototype.getTangent = function ( t, optionalTarget ) {
36007 const tangent = optionalTarget || new Vector2();
36009 tangent.copy( this.v2 ).sub( this.v1 ).normalize();
36015 LineCurve.prototype.copy = function ( source ) {
36017 Curve.prototype.copy.call( this, source );
36019 this.v1.copy( source.v1 );
36020 this.v2.copy( source.v2 );
36026 LineCurve.prototype.toJSON = function () {
36028 const data = Curve.prototype.toJSON.call( this );
36030 data.v1 = this.v1.toArray();
36031 data.v2 = this.v2.toArray();
36037 LineCurve.prototype.fromJSON = function ( json ) {
36039 Curve.prototype.fromJSON.call( this, json );
36041 this.v1.fromArray( json.v1 );
36042 this.v2.fromArray( json.v2 );
36048 function LineCurve3( v1 = new Vector3(), v2 = new Vector3() ) {
36050 Curve.call( this );
36052 this.type = 'LineCurve3';
36059 LineCurve3.prototype = Object.create( Curve.prototype );
36060 LineCurve3.prototype.constructor = LineCurve3;
36062 LineCurve3.prototype.isLineCurve3 = true;
36064 LineCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
36066 const point = optionalTarget;
36070 point.copy( this.v2 );
36074 point.copy( this.v2 ).sub( this.v1 );
36075 point.multiplyScalar( t ).add( this.v1 );
36083 // Line curve is linear, so we can overwrite default getPointAt
36085 LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) {
36087 return this.getPoint( u, optionalTarget );
36091 LineCurve3.prototype.copy = function ( source ) {
36093 Curve.prototype.copy.call( this, source );
36095 this.v1.copy( source.v1 );
36096 this.v2.copy( source.v2 );
36102 LineCurve3.prototype.toJSON = function () {
36104 const data = Curve.prototype.toJSON.call( this );
36106 data.v1 = this.v1.toArray();
36107 data.v2 = this.v2.toArray();
36113 LineCurve3.prototype.fromJSON = function ( json ) {
36115 Curve.prototype.fromJSON.call( this, json );
36117 this.v1.fromArray( json.v1 );
36118 this.v2.fromArray( json.v2 );
36124 function QuadraticBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
36126 Curve.call( this );
36128 this.type = 'QuadraticBezierCurve';
36136 QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
36137 QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
36139 QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
36141 QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
36143 const point = optionalTarget;
36145 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
36148 QuadraticBezier( t, v0.x, v1.x, v2.x ),
36149 QuadraticBezier( t, v0.y, v1.y, v2.y )
36156 QuadraticBezierCurve.prototype.copy = function ( source ) {
36158 Curve.prototype.copy.call( this, source );
36160 this.v0.copy( source.v0 );
36161 this.v1.copy( source.v1 );
36162 this.v2.copy( source.v2 );
36168 QuadraticBezierCurve.prototype.toJSON = function () {
36170 const data = Curve.prototype.toJSON.call( this );
36172 data.v0 = this.v0.toArray();
36173 data.v1 = this.v1.toArray();
36174 data.v2 = this.v2.toArray();
36180 QuadraticBezierCurve.prototype.fromJSON = function ( json ) {
36182 Curve.prototype.fromJSON.call( this, json );
36184 this.v0.fromArray( json.v0 );
36185 this.v1.fromArray( json.v1 );
36186 this.v2.fromArray( json.v2 );
36192 function QuadraticBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
36194 Curve.call( this );
36196 this.type = 'QuadraticBezierCurve3';
36204 QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
36205 QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
36207 QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
36209 QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
36211 const point = optionalTarget;
36213 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
36216 QuadraticBezier( t, v0.x, v1.x, v2.x ),
36217 QuadraticBezier( t, v0.y, v1.y, v2.y ),
36218 QuadraticBezier( t, v0.z, v1.z, v2.z )
36225 QuadraticBezierCurve3.prototype.copy = function ( source ) {
36227 Curve.prototype.copy.call( this, source );
36229 this.v0.copy( source.v0 );
36230 this.v1.copy( source.v1 );
36231 this.v2.copy( source.v2 );
36237 QuadraticBezierCurve3.prototype.toJSON = function () {
36239 const data = Curve.prototype.toJSON.call( this );
36241 data.v0 = this.v0.toArray();
36242 data.v1 = this.v1.toArray();
36243 data.v2 = this.v2.toArray();
36249 QuadraticBezierCurve3.prototype.fromJSON = function ( json ) {
36251 Curve.prototype.fromJSON.call( this, json );
36253 this.v0.fromArray( json.v0 );
36254 this.v1.fromArray( json.v1 );
36255 this.v2.fromArray( json.v2 );
36261 function SplineCurve( points = [] ) {
36263 Curve.call( this );
36265 this.type = 'SplineCurve';
36267 this.points = points;
36271 SplineCurve.prototype = Object.create( Curve.prototype );
36272 SplineCurve.prototype.constructor = SplineCurve;
36274 SplineCurve.prototype.isSplineCurve = true;
36276 SplineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
36278 const point = optionalTarget;
36280 const points = this.points;
36281 const p = ( points.length - 1 ) * t;
36283 const intPoint = Math.floor( p );
36284 const weight = p - intPoint;
36286 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
36287 const p1 = points[ intPoint ];
36288 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
36289 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
36292 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
36293 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
36300 SplineCurve.prototype.copy = function ( source ) {
36302 Curve.prototype.copy.call( this, source );
36306 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
36308 const point = source.points[ i ];
36310 this.points.push( point.clone() );
36318 SplineCurve.prototype.toJSON = function () {
36320 const data = Curve.prototype.toJSON.call( this );
36324 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
36326 const point = this.points[ i ];
36327 data.points.push( point.toArray() );
36335 SplineCurve.prototype.fromJSON = function ( json ) {
36337 Curve.prototype.fromJSON.call( this, json );
36341 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
36343 const point = json.points[ i ];
36344 this.points.push( new Vector2().fromArray( point ) );
36352 var Curves = /*#__PURE__*/Object.freeze({
36354 ArcCurve: ArcCurve,
36355 CatmullRomCurve3: CatmullRomCurve3,
36356 CubicBezierCurve: CubicBezierCurve,
36357 CubicBezierCurve3: CubicBezierCurve3,
36358 EllipseCurve: EllipseCurve,
36359 LineCurve: LineCurve,
36360 LineCurve3: LineCurve3,
36361 QuadraticBezierCurve: QuadraticBezierCurve,
36362 QuadraticBezierCurve3: QuadraticBezierCurve3,
36363 SplineCurve: SplineCurve
36366 /**************************************************************
36367 * Curved Path - a curve path is simply a array of connected
36368 * curves, but retains the api of a curve
36369 **************************************************************/
36371 function CurvePath() {
36373 Curve.call( this );
36375 this.type = 'CurvePath';
36378 this.autoClose = false; // Automatically closes the path
36382 CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
36384 constructor: CurvePath,
36386 add: function ( curve ) {
36388 this.curves.push( curve );
36392 closePath: function () {
36394 // Add a line curve if start and end of lines are not connected
36395 const startPoint = this.curves[ 0 ].getPoint( 0 );
36396 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
36398 if ( ! startPoint.equals( endPoint ) ) {
36400 this.curves.push( new LineCurve( endPoint, startPoint ) );
36406 // To get accurate point with reference to
36407 // entire path distance at time t,
36408 // following has to be done:
36410 // 1. Length of each sub path have to be known
36411 // 2. Locate and identify type of curve
36412 // 3. Get t for the curve
36413 // 4. Return curve.getPointAt(t')
36415 getPoint: function ( t ) {
36417 const d = t * this.getLength();
36418 const curveLengths = this.getCurveLengths();
36421 // To think about boundaries points.
36423 while ( i < curveLengths.length ) {
36425 if ( curveLengths[ i ] >= d ) {
36427 const diff = curveLengths[ i ] - d;
36428 const curve = this.curves[ i ];
36430 const segmentLength = curve.getLength();
36431 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
36433 return curve.getPointAt( u );
36443 // loop where sum != 0, sum > d , sum+1 <d
36447 // We cannot use the default THREE.Curve getPoint() with getLength() because in
36448 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
36449 // getPoint() depends on getLength
36451 getLength: function () {
36453 const lens = this.getCurveLengths();
36454 return lens[ lens.length - 1 ];
36458 // cacheLengths must be recalculated.
36459 updateArcLengths: function () {
36461 this.needsUpdate = true;
36462 this.cacheLengths = null;
36463 this.getCurveLengths();
36467 // Compute lengths and cache them
36468 // We cannot overwrite getLengths() because UtoT mapping uses it.
36470 getCurveLengths: function () {
36472 // We use cache values if curves and cache array are same length
36474 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
36476 return this.cacheLengths;
36480 // Get length of sub-curve
36481 // Push sums into cached array
36483 const lengths = [];
36486 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36488 sums += this.curves[ i ].getLength();
36489 lengths.push( sums );
36493 this.cacheLengths = lengths;
36499 getSpacedPoints: function ( divisions = 40 ) {
36503 for ( let i = 0; i <= divisions; i ++ ) {
36505 points.push( this.getPoint( i / divisions ) );
36509 if ( this.autoClose ) {
36511 points.push( points[ 0 ] );
36519 getPoints: function ( divisions = 12 ) {
36524 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
36526 const curve = curves[ i ];
36527 const resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
36528 : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1
36529 : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
36532 const pts = curve.getPoints( resolution );
36534 for ( let j = 0; j < pts.length; j ++ ) {
36536 const point = pts[ j ];
36538 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
36540 points.push( point );
36547 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
36549 points.push( points[ 0 ] );
36557 copy: function ( source ) {
36559 Curve.prototype.copy.call( this, source );
36563 for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
36565 const curve = source.curves[ i ];
36567 this.curves.push( curve.clone() );
36571 this.autoClose = source.autoClose;
36577 toJSON: function () {
36579 const data = Curve.prototype.toJSON.call( this );
36581 data.autoClose = this.autoClose;
36584 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36586 const curve = this.curves[ i ];
36587 data.curves.push( curve.toJSON() );
36595 fromJSON: function ( json ) {
36597 Curve.prototype.fromJSON.call( this, json );
36599 this.autoClose = json.autoClose;
36602 for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
36604 const curve = json.curves[ i ];
36605 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
36615 function Path( points ) {
36617 CurvePath.call( this );
36619 this.type = 'Path';
36621 this.currentPoint = new Vector2();
36625 this.setFromPoints( points );
36631 Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
36635 setFromPoints: function ( points ) {
36637 this.moveTo( points[ 0 ].x, points[ 0 ].y );
36639 for ( let i = 1, l = points.length; i < l; i ++ ) {
36641 this.lineTo( points[ i ].x, points[ i ].y );
36649 moveTo: function ( x, y ) {
36651 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
36657 lineTo: function ( x, y ) {
36659 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
36660 this.curves.push( curve );
36662 this.currentPoint.set( x, y );
36668 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
36670 const curve = new QuadraticBezierCurve(
36671 this.currentPoint.clone(),
36672 new Vector2( aCPx, aCPy ),
36673 new Vector2( aX, aY )
36676 this.curves.push( curve );
36678 this.currentPoint.set( aX, aY );
36684 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
36686 const curve = new CubicBezierCurve(
36687 this.currentPoint.clone(),
36688 new Vector2( aCP1x, aCP1y ),
36689 new Vector2( aCP2x, aCP2y ),
36690 new Vector2( aX, aY )
36693 this.curves.push( curve );
36695 this.currentPoint.set( aX, aY );
36701 splineThru: function ( pts /*Array of Vector*/ ) {
36703 const npts = [ this.currentPoint.clone() ].concat( pts );
36705 const curve = new SplineCurve( npts );
36706 this.curves.push( curve );
36708 this.currentPoint.copy( pts[ pts.length - 1 ] );
36714 arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36716 const x0 = this.currentPoint.x;
36717 const y0 = this.currentPoint.y;
36719 this.absarc( aX + x0, aY + y0, aRadius,
36720 aStartAngle, aEndAngle, aClockwise );
36726 absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36728 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
36734 ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36736 const x0 = this.currentPoint.x;
36737 const y0 = this.currentPoint.y;
36739 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36745 absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
36747 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
36749 if ( this.curves.length > 0 ) {
36751 // if a previous curve is present, attempt to join
36752 const firstPoint = curve.getPoint( 0 );
36754 if ( ! firstPoint.equals( this.currentPoint ) ) {
36756 this.lineTo( firstPoint.x, firstPoint.y );
36762 this.curves.push( curve );
36764 const lastPoint = curve.getPoint( 1 );
36765 this.currentPoint.copy( lastPoint );
36771 copy: function ( source ) {
36773 CurvePath.prototype.copy.call( this, source );
36775 this.currentPoint.copy( source.currentPoint );
36781 toJSON: function () {
36783 const data = CurvePath.prototype.toJSON.call( this );
36785 data.currentPoint = this.currentPoint.toArray();
36791 fromJSON: function ( json ) {
36793 CurvePath.prototype.fromJSON.call( this, json );
36795 this.currentPoint.fromArray( json.currentPoint );
36803 function Shape( points ) {
36805 Path.call( this, points );
36807 this.uuid = MathUtils.generateUUID();
36809 this.type = 'Shape';
36815 Shape.prototype = Object.assign( Object.create( Path.prototype ), {
36817 constructor: Shape,
36819 getPointsHoles: function ( divisions ) {
36821 const holesPts = [];
36823 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
36825 holesPts[ i ] = this.holes[ i ].getPoints( divisions );
36833 // get points of shape and holes (keypoints based on segments parameter)
36835 extractPoints: function ( divisions ) {
36839 shape: this.getPoints( divisions ),
36840 holes: this.getPointsHoles( divisions )
36846 copy: function ( source ) {
36848 Path.prototype.copy.call( this, source );
36852 for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
36854 const hole = source.holes[ i ];
36856 this.holes.push( hole.clone() );
36864 toJSON: function () {
36866 const data = Path.prototype.toJSON.call( this );
36868 data.uuid = this.uuid;
36871 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
36873 const hole = this.holes[ i ];
36874 data.holes.push( hole.toJSON() );
36882 fromJSON: function ( json ) {
36884 Path.prototype.fromJSON.call( this, json );
36886 this.uuid = json.uuid;
36889 for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
36891 const hole = json.holes[ i ];
36892 this.holes.push( new Path().fromJSON( hole ) );
36902 function Light( color, intensity = 1 ) {
36904 Object3D.call( this );
36906 this.type = 'Light';
36908 this.color = new Color( color );
36909 this.intensity = intensity;
36913 Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
36915 constructor: Light,
36919 copy: function ( source ) {
36921 Object3D.prototype.copy.call( this, source );
36923 this.color.copy( source.color );
36924 this.intensity = source.intensity;
36930 toJSON: function ( meta ) {
36932 const data = Object3D.prototype.toJSON.call( this, meta );
36934 data.object.color = this.color.getHex();
36935 data.object.intensity = this.intensity;
36937 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
36939 if ( this.distance !== undefined ) data.object.distance = this.distance;
36940 if ( this.angle !== undefined ) data.object.angle = this.angle;
36941 if ( this.decay !== undefined ) data.object.decay = this.decay;
36942 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
36944 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
36952 function HemisphereLight( skyColor, groundColor, intensity ) {
36954 Light.call( this, skyColor, intensity );
36956 this.type = 'HemisphereLight';
36958 this.position.copy( Object3D.DefaultUp );
36959 this.updateMatrix();
36961 this.groundColor = new Color( groundColor );
36965 HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
36967 constructor: HemisphereLight,
36969 isHemisphereLight: true,
36971 copy: function ( source ) {
36973 Light.prototype.copy.call( this, source );
36975 this.groundColor.copy( source.groundColor );
36983 function LightShadow( camera ) {
36985 this.camera = camera;
36988 this.normalBias = 0;
36991 this.mapSize = new Vector2( 512, 512 );
36994 this.mapPass = null;
36995 this.matrix = new Matrix4();
36997 this.autoUpdate = true;
36998 this.needsUpdate = false;
37000 this._frustum = new Frustum();
37001 this._frameExtents = new Vector2( 1, 1 );
37003 this._viewportCount = 1;
37005 this._viewports = [
37007 new Vector4( 0, 0, 1, 1 )
37013 Object.assign( LightShadow.prototype, {
37015 _projScreenMatrix: new Matrix4(),
37017 _lightPositionWorld: new Vector3(),
37019 _lookTarget: new Vector3(),
37021 getViewportCount: function () {
37023 return this._viewportCount;
37027 getFrustum: function () {
37029 return this._frustum;
37033 updateMatrices: function ( light ) {
37035 const shadowCamera = this.camera,
37036 shadowMatrix = this.matrix,
37037 projScreenMatrix = this._projScreenMatrix,
37038 lookTarget = this._lookTarget,
37039 lightPositionWorld = this._lightPositionWorld;
37041 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
37042 shadowCamera.position.copy( lightPositionWorld );
37044 lookTarget.setFromMatrixPosition( light.target.matrixWorld );
37045 shadowCamera.lookAt( lookTarget );
37046 shadowCamera.updateMatrixWorld();
37048 projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
37049 this._frustum.setFromProjectionMatrix( projScreenMatrix );
37052 0.5, 0.0, 0.0, 0.5,
37053 0.0, 0.5, 0.0, 0.5,
37054 0.0, 0.0, 0.5, 0.5,
37058 shadowMatrix.multiply( shadowCamera.projectionMatrix );
37059 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
37063 getViewport: function ( viewportIndex ) {
37065 return this._viewports[ viewportIndex ];
37069 getFrameExtents: function () {
37071 return this._frameExtents;
37075 copy: function ( source ) {
37077 this.camera = source.camera.clone();
37079 this.bias = source.bias;
37080 this.radius = source.radius;
37082 this.mapSize.copy( source.mapSize );
37088 clone: function () {
37090 return new this.constructor().copy( this );
37094 toJSON: function () {
37098 if ( this.bias !== 0 ) object.bias = this.bias;
37099 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
37100 if ( this.radius !== 1 ) object.radius = this.radius;
37101 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
37103 object.camera = this.camera.toJSON( false ).object;
37104 delete object.camera.matrix;
37112 function SpotLightShadow() {
37114 LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
37120 SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
37122 constructor: SpotLightShadow,
37124 isSpotLightShadow: true,
37126 updateMatrices: function ( light ) {
37128 const camera = this.camera;
37130 const fov = MathUtils.RAD2DEG * 2 * light.angle * this.focus;
37131 const aspect = this.mapSize.width / this.mapSize.height;
37132 const far = light.distance || camera.far;
37134 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
37137 camera.aspect = aspect;
37139 camera.updateProjectionMatrix();
37143 LightShadow.prototype.updateMatrices.call( this, light );
37149 function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
37151 Light.call( this, color, intensity );
37153 this.type = 'SpotLight';
37155 this.position.copy( Object3D.DefaultUp );
37156 this.updateMatrix();
37158 this.target = new Object3D();
37160 Object.defineProperty( this, 'power', {
37163 // intensity = power per solid angle.
37164 // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37165 return this.intensity * Math.PI;
37168 set: function ( power ) {
37170 // intensity = power per solid angle.
37171 // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37172 this.intensity = power / Math.PI;
37177 this.distance = ( distance !== undefined ) ? distance : 0;
37178 this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
37179 this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
37180 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
37182 this.shadow = new SpotLightShadow();
37186 SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
37188 constructor: SpotLight,
37192 copy: function ( source ) {
37194 Light.prototype.copy.call( this, source );
37196 this.distance = source.distance;
37197 this.angle = source.angle;
37198 this.penumbra = source.penumbra;
37199 this.decay = source.decay;
37201 this.target = source.target.clone();
37203 this.shadow = source.shadow.clone();
37211 function PointLightShadow() {
37213 LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) );
37215 this._frameExtents = new Vector2( 4, 2 );
37217 this._viewportCount = 6;
37219 this._viewports = [
37220 // These viewports map a cube-map onto a 2D texture with the
37221 // following orientation:
37226 // X - Positive x direction
37227 // x - Negative x direction
37228 // Y - Positive y direction
37229 // y - Negative y direction
37230 // Z - Positive z direction
37231 // z - Negative z direction
37234 new Vector4( 2, 1, 1, 1 ),
37236 new Vector4( 0, 1, 1, 1 ),
37238 new Vector4( 3, 1, 1, 1 ),
37240 new Vector4( 1, 1, 1, 1 ),
37242 new Vector4( 3, 0, 1, 1 ),
37244 new Vector4( 1, 0, 1, 1 )
37247 this._cubeDirections = [
37248 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
37249 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
37253 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
37254 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
37259 PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
37261 constructor: PointLightShadow,
37263 isPointLightShadow: true,
37265 updateMatrices: function ( light, viewportIndex = 0 ) {
37267 const camera = this.camera,
37268 shadowMatrix = this.matrix,
37269 lightPositionWorld = this._lightPositionWorld,
37270 lookTarget = this._lookTarget,
37271 projScreenMatrix = this._projScreenMatrix;
37273 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
37274 camera.position.copy( lightPositionWorld );
37276 lookTarget.copy( camera.position );
37277 lookTarget.add( this._cubeDirections[ viewportIndex ] );
37278 camera.up.copy( this._cubeUps[ viewportIndex ] );
37279 camera.lookAt( lookTarget );
37280 camera.updateMatrixWorld();
37282 shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z );
37284 projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
37285 this._frustum.setFromProjectionMatrix( projScreenMatrix );
37291 function PointLight( color, intensity, distance, decay ) {
37293 Light.call( this, color, intensity );
37295 this.type = 'PointLight';
37297 Object.defineProperty( this, 'power', {
37300 // intensity = power per solid angle.
37301 // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37302 return this.intensity * 4 * Math.PI;
37305 set: function ( power ) {
37307 // intensity = power per solid angle.
37308 // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37309 this.intensity = power / ( 4 * Math.PI );
37314 this.distance = ( distance !== undefined ) ? distance : 0;
37315 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
37317 this.shadow = new PointLightShadow();
37321 PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
37323 constructor: PointLight,
37325 isPointLight: true,
37327 copy: function ( source ) {
37329 Light.prototype.copy.call( this, source );
37331 this.distance = source.distance;
37332 this.decay = source.decay;
37334 this.shadow = source.shadow.clone();
37342 function OrthographicCamera( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
37344 Camera.call( this );
37346 this.type = 'OrthographicCamera';
37352 this.right = right;
37354 this.bottom = bottom;
37359 this.updateProjectionMatrix();
37363 OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
37365 constructor: OrthographicCamera,
37367 isOrthographicCamera: true,
37369 copy: function ( source, recursive ) {
37371 Camera.prototype.copy.call( this, source, recursive );
37373 this.left = source.left;
37374 this.right = source.right;
37375 this.top = source.top;
37376 this.bottom = source.bottom;
37377 this.near = source.near;
37378 this.far = source.far;
37380 this.zoom = source.zoom;
37381 this.view = source.view === null ? null : Object.assign( {}, source.view );
37387 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
37389 if ( this.view === null ) {
37403 this.view.enabled = true;
37404 this.view.fullWidth = fullWidth;
37405 this.view.fullHeight = fullHeight;
37406 this.view.offsetX = x;
37407 this.view.offsetY = y;
37408 this.view.width = width;
37409 this.view.height = height;
37411 this.updateProjectionMatrix();
37415 clearViewOffset: function () {
37417 if ( this.view !== null ) {
37419 this.view.enabled = false;
37423 this.updateProjectionMatrix();
37427 updateProjectionMatrix: function () {
37429 const dx = ( this.right - this.left ) / ( 2 * this.zoom );
37430 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
37431 const cx = ( this.right + this.left ) / 2;
37432 const cy = ( this.top + this.bottom ) / 2;
37434 let left = cx - dx;
37435 let right = cx + dx;
37437 let bottom = cy - dy;
37439 if ( this.view !== null && this.view.enabled ) {
37441 const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
37442 const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
37444 left += scaleW * this.view.offsetX;
37445 right = left + scaleW * this.view.width;
37446 top -= scaleH * this.view.offsetY;
37447 bottom = top - scaleH * this.view.height;
37451 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
37453 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
37457 toJSON: function ( meta ) {
37459 const data = Object3D.prototype.toJSON.call( this, meta );
37461 data.object.zoom = this.zoom;
37462 data.object.left = this.left;
37463 data.object.right = this.right;
37464 data.object.top = this.top;
37465 data.object.bottom = this.bottom;
37466 data.object.near = this.near;
37467 data.object.far = this.far;
37469 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
37477 function DirectionalLightShadow() {
37479 LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
37483 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
37485 constructor: DirectionalLightShadow,
37487 isDirectionalLightShadow: true,
37489 updateMatrices: function ( light ) {
37491 LightShadow.prototype.updateMatrices.call( this, light );
37497 function DirectionalLight( color, intensity ) {
37499 Light.call( this, color, intensity );
37501 this.type = 'DirectionalLight';
37503 this.position.copy( Object3D.DefaultUp );
37504 this.updateMatrix();
37506 this.target = new Object3D();
37508 this.shadow = new DirectionalLightShadow();
37512 DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
37514 constructor: DirectionalLight,
37516 isDirectionalLight: true,
37518 copy: function ( source ) {
37520 Light.prototype.copy.call( this, source );
37522 this.target = source.target.clone();
37524 this.shadow = source.shadow.clone();
37532 function AmbientLight( color, intensity ) {
37534 Light.call( this, color, intensity );
37536 this.type = 'AmbientLight';
37540 AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
37542 constructor: AmbientLight,
37544 isAmbientLight: true
37548 function RectAreaLight( color, intensity, width, height ) {
37550 Light.call( this, color, intensity );
37552 this.type = 'RectAreaLight';
37554 this.width = ( width !== undefined ) ? width : 10;
37555 this.height = ( height !== undefined ) ? height : 10;
37559 RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
37561 constructor: RectAreaLight,
37563 isRectAreaLight: true,
37565 copy: function ( source ) {
37567 Light.prototype.copy.call( this, source );
37569 this.width = source.width;
37570 this.height = source.height;
37576 toJSON: function ( meta ) {
37578 const data = Light.prototype.toJSON.call( this, meta );
37580 data.object.width = this.width;
37581 data.object.height = this.height;
37590 * Primary reference:
37591 * https://graphics.stanford.edu/papers/envmap/envmap.pdf
37593 * Secondary reference:
37594 * https://www.ppsloan.org/publications/StupidSH36.pdf
37597 // 3-band SH defined by 9 coefficients
37599 class SphericalHarmonics3 {
37603 Object.defineProperty( this, 'isSphericalHarmonics3', { value: true } );
37605 this.coefficients = [];
37607 for ( let i = 0; i < 9; i ++ ) {
37609 this.coefficients.push( new Vector3() );
37615 set( coefficients ) {
37617 for ( let i = 0; i < 9; i ++ ) {
37619 this.coefficients[ i ].copy( coefficients[ i ] );
37629 for ( let i = 0; i < 9; i ++ ) {
37631 this.coefficients[ i ].set( 0, 0, 0 );
37639 // get the radiance in the direction of the normal
37640 // target is a Vector3
37641 getAt( normal, target ) {
37643 // normal is assumed to be unit length
37645 const x = normal.x, y = normal.y, z = normal.z;
37647 const coeff = this.coefficients;
37650 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
37653 target.addScaledVector( coeff[ 1 ], 0.488603 * y );
37654 target.addScaledVector( coeff[ 2 ], 0.488603 * z );
37655 target.addScaledVector( coeff[ 3 ], 0.488603 * x );
37658 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
37659 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
37660 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
37661 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
37662 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
37668 // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
37669 // target is a Vector3
37670 // https://graphics.stanford.edu/papers/envmap/envmap.pdf
37671 getIrradianceAt( normal, target ) {
37673 // normal is assumed to be unit length
37675 const x = normal.x, y = normal.y, z = normal.z;
37677 const coeff = this.coefficients;
37680 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
37683 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
37684 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
37685 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
37688 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
37689 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
37690 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
37691 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
37692 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
37700 for ( let i = 0; i < 9; i ++ ) {
37702 this.coefficients[ i ].add( sh.coefficients[ i ] );
37710 addScaledSH( sh, s ) {
37712 for ( let i = 0; i < 9; i ++ ) {
37714 this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
37724 for ( let i = 0; i < 9; i ++ ) {
37726 this.coefficients[ i ].multiplyScalar( s );
37734 lerp( sh, alpha ) {
37736 for ( let i = 0; i < 9; i ++ ) {
37738 this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
37748 for ( let i = 0; i < 9; i ++ ) {
37750 if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
37764 return this.set( sh.coefficients );
37770 return new this.constructor().copy( this );
37774 fromArray( array, offset = 0 ) {
37776 const coefficients = this.coefficients;
37778 for ( let i = 0; i < 9; i ++ ) {
37780 coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
37788 toArray( array = [], offset = 0 ) {
37790 const coefficients = this.coefficients;
37792 for ( let i = 0; i < 9; i ++ ) {
37794 coefficients[ i ].toArray( array, offset + ( i * 3 ) );
37802 // evaluate the basis functions
37803 // shBasis is an Array[ 9 ]
37804 static getBasisAt( normal, shBasis ) {
37806 // normal is assumed to be unit length
37808 const x = normal.x, y = normal.y, z = normal.z;
37811 shBasis[ 0 ] = 0.282095;
37814 shBasis[ 1 ] = 0.488603 * y;
37815 shBasis[ 2 ] = 0.488603 * z;
37816 shBasis[ 3 ] = 0.488603 * x;
37819 shBasis[ 4 ] = 1.092548 * x * y;
37820 shBasis[ 5 ] = 1.092548 * y * z;
37821 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
37822 shBasis[ 7 ] = 1.092548 * x * z;
37823 shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
37829 function LightProbe( sh, intensity ) {
37831 Light.call( this, undefined, intensity );
37833 this.type = 'LightProbe';
37835 this.sh = ( sh !== undefined ) ? sh : new SphericalHarmonics3();
37839 LightProbe.prototype = Object.assign( Object.create( Light.prototype ), {
37841 constructor: LightProbe,
37843 isLightProbe: true,
37845 copy: function ( source ) {
37847 Light.prototype.copy.call( this, source );
37849 this.sh.copy( source.sh );
37855 fromJSON: function ( json ) {
37857 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
37858 this.sh.fromArray( json.sh );
37864 toJSON: function ( meta ) {
37866 const data = Light.prototype.toJSON.call( this, meta );
37868 data.object.sh = this.sh.toArray();
37876 function MaterialLoader( manager ) {
37878 Loader.call( this, manager );
37880 this.textures = {};
37884 MaterialLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37886 constructor: MaterialLoader,
37888 load: function ( url, onLoad, onProgress, onError ) {
37890 const scope = this;
37892 const loader = new FileLoader( scope.manager );
37893 loader.setPath( scope.path );
37894 loader.setRequestHeader( scope.requestHeader );
37895 loader.setWithCredentials( scope.withCredentials );
37896 loader.load( url, function ( text ) {
37900 onLoad( scope.parse( JSON.parse( text ) ) );
37910 console.error( e );
37914 scope.manager.itemError( url );
37918 }, onProgress, onError );
37922 parse: function ( json ) {
37924 const textures = this.textures;
37926 function getTexture( name ) {
37928 if ( textures[ name ] === undefined ) {
37930 console.warn( 'THREE.MaterialLoader: Undefined texture', name );
37934 return textures[ name ];
37938 const material = new Materials[ json.type ]();
37940 if ( json.uuid !== undefined ) material.uuid = json.uuid;
37941 if ( json.name !== undefined ) material.name = json.name;
37942 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
37943 if ( json.roughness !== undefined ) material.roughness = json.roughness;
37944 if ( json.metalness !== undefined ) material.metalness = json.metalness;
37945 if ( json.sheen !== undefined ) material.sheen = new Color().setHex( json.sheen );
37946 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
37947 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
37948 if ( json.shininess !== undefined ) material.shininess = json.shininess;
37949 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
37950 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
37951 if ( json.fog !== undefined ) material.fog = json.fog;
37952 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
37953 if ( json.blending !== undefined ) material.blending = json.blending;
37954 if ( json.combine !== undefined ) material.combine = json.combine;
37955 if ( json.side !== undefined ) material.side = json.side;
37956 if ( json.opacity !== undefined ) material.opacity = json.opacity;
37957 if ( json.transparent !== undefined ) material.transparent = json.transparent;
37958 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
37959 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
37960 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
37961 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
37963 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
37964 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
37965 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
37966 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
37967 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
37968 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
37969 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
37970 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
37972 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
37973 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
37974 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
37975 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
37977 if ( json.rotation !== undefined ) material.rotation = json.rotation;
37979 if ( json.linewidth !== 1 ) material.linewidth = json.linewidth;
37980 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
37981 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
37982 if ( json.scale !== undefined ) material.scale = json.scale;
37984 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
37985 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
37986 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
37988 if ( json.skinning !== undefined ) material.skinning = json.skinning;
37989 if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
37990 if ( json.morphNormals !== undefined ) material.morphNormals = json.morphNormals;
37991 if ( json.dithering !== undefined ) material.dithering = json.dithering;
37993 if ( json.vertexTangents !== undefined ) material.vertexTangents = json.vertexTangents;
37995 if ( json.visible !== undefined ) material.visible = json.visible;
37997 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
37999 if ( json.userData !== undefined ) material.userData = json.userData;
38001 if ( json.vertexColors !== undefined ) {
38003 if ( typeof json.vertexColors === 'number' ) {
38005 material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
38009 material.vertexColors = json.vertexColors;
38017 if ( json.uniforms !== undefined ) {
38019 for ( const name in json.uniforms ) {
38021 const uniform = json.uniforms[ name ];
38023 material.uniforms[ name ] = {};
38025 switch ( uniform.type ) {
38028 material.uniforms[ name ].value = getTexture( uniform.value );
38032 material.uniforms[ name ].value = new Color().setHex( uniform.value );
38036 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
38040 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
38044 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
38048 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
38052 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
38056 material.uniforms[ name ].value = uniform.value;
38064 if ( json.defines !== undefined ) material.defines = json.defines;
38065 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
38066 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
38068 if ( json.extensions !== undefined ) {
38070 for ( const key in json.extensions ) {
38072 material.extensions[ key ] = json.extensions[ key ];
38080 if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
38082 // for PointsMaterial
38084 if ( json.size !== undefined ) material.size = json.size;
38085 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
38089 if ( json.map !== undefined ) material.map = getTexture( json.map );
38090 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
38092 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
38094 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
38095 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
38097 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
38098 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
38099 if ( json.normalScale !== undefined ) {
38101 let normalScale = json.normalScale;
38103 if ( Array.isArray( normalScale ) === false ) {
38105 // Blender exporter used to export a scalar. See #7459
38107 normalScale = [ normalScale, normalScale ];
38111 material.normalScale = new Vector2().fromArray( normalScale );
38115 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
38116 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
38117 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
38119 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
38120 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
38122 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
38123 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
38125 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
38127 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
38128 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
38130 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
38131 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
38133 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
38134 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
38136 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
38137 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
38139 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
38141 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
38142 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
38143 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
38144 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
38146 if ( json.transmission !== undefined ) material.transmission = json.transmission;
38147 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
38153 setTextures: function ( value ) {
38155 this.textures = value;
38162 const LoaderUtils = {
38164 decodeText: function ( array ) {
38166 if ( typeof TextDecoder !== 'undefined' ) {
38168 return new TextDecoder().decode( array );
38172 // Avoid the String.fromCharCode.apply(null, array) shortcut, which
38173 // throws a "maximum call stack size exceeded" error for large arrays.
38177 for ( let i = 0, il = array.length; i < il; i ++ ) {
38179 // Implicitly assumes little-endian.
38180 s += String.fromCharCode( array[ i ] );
38186 // merges multi-byte utf-8 characters.
38188 return decodeURIComponent( escape( s ) );
38190 } catch ( e ) { // see #16358
38198 extractUrlBase: function ( url ) {
38200 const index = url.lastIndexOf( '/' );
38202 if ( index === - 1 ) return './';
38204 return url.substr( 0, index + 1 );
38210 function InstancedBufferGeometry() {
38212 BufferGeometry.call( this );
38214 this.type = 'InstancedBufferGeometry';
38215 this.instanceCount = Infinity;
38219 InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
38221 constructor: InstancedBufferGeometry,
38223 isInstancedBufferGeometry: true,
38225 copy: function ( source ) {
38227 BufferGeometry.prototype.copy.call( this, source );
38229 this.instanceCount = source.instanceCount;
38235 clone: function () {
38237 return new this.constructor().copy( this );
38241 toJSON: function () {
38243 const data = BufferGeometry.prototype.toJSON.call( this );
38245 data.instanceCount = this.instanceCount;
38247 data.isInstancedBufferGeometry = true;
38255 function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) {
38257 if ( typeof ( normalized ) === 'number' ) {
38259 meshPerAttribute = normalized;
38261 normalized = false;
38263 console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' );
38267 BufferAttribute.call( this, array, itemSize, normalized );
38269 this.meshPerAttribute = meshPerAttribute || 1;
38273 InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
38275 constructor: InstancedBufferAttribute,
38277 isInstancedBufferAttribute: true,
38279 copy: function ( source ) {
38281 BufferAttribute.prototype.copy.call( this, source );
38283 this.meshPerAttribute = source.meshPerAttribute;
38289 toJSON: function () {
38291 const data = BufferAttribute.prototype.toJSON.call( this );
38293 data.meshPerAttribute = this.meshPerAttribute;
38295 data.isInstancedBufferAttribute = true;
38303 function BufferGeometryLoader( manager ) {
38305 Loader.call( this, manager );
38309 BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
38311 constructor: BufferGeometryLoader,
38313 load: function ( url, onLoad, onProgress, onError ) {
38315 const scope = this;
38317 const loader = new FileLoader( scope.manager );
38318 loader.setPath( scope.path );
38319 loader.setRequestHeader( scope.requestHeader );
38320 loader.setWithCredentials( scope.withCredentials );
38321 loader.load( url, function ( text ) {
38325 onLoad( scope.parse( JSON.parse( text ) ) );
38335 console.error( e );
38339 scope.manager.itemError( url );
38343 }, onProgress, onError );
38347 parse: function ( json ) {
38349 const interleavedBufferMap = {};
38350 const arrayBufferMap = {};
38352 function getInterleavedBuffer( json, uuid ) {
38354 if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
38356 const interleavedBuffers = json.interleavedBuffers;
38357 const interleavedBuffer = interleavedBuffers[ uuid ];
38359 const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
38361 const array = getTypedArray( interleavedBuffer.type, buffer );
38362 const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
38363 ib.uuid = interleavedBuffer.uuid;
38365 interleavedBufferMap[ uuid ] = ib;
38371 function getArrayBuffer( json, uuid ) {
38373 if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
38375 const arrayBuffers = json.arrayBuffers;
38376 const arrayBuffer = arrayBuffers[ uuid ];
38378 const ab = new Uint32Array( arrayBuffer ).buffer;
38380 arrayBufferMap[ uuid ] = ab;
38386 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
38388 const index = json.data.index;
38390 if ( index !== undefined ) {
38392 const typedArray = getTypedArray( index.type, index.array );
38393 geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
38397 const attributes = json.data.attributes;
38399 for ( const key in attributes ) {
38401 const attribute = attributes[ key ];
38402 let bufferAttribute;
38404 if ( attribute.isInterleavedBufferAttribute ) {
38406 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
38407 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
38411 const typedArray = getTypedArray( attribute.type, attribute.array );
38412 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
38413 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
38417 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
38418 geometry.setAttribute( key, bufferAttribute );
38422 const morphAttributes = json.data.morphAttributes;
38424 if ( morphAttributes ) {
38426 for ( const key in morphAttributes ) {
38428 const attributeArray = morphAttributes[ key ];
38432 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
38434 const attribute = attributeArray[ i ];
38435 let bufferAttribute;
38437 if ( attribute.isInterleavedBufferAttribute ) {
38439 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
38440 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
38444 const typedArray = getTypedArray( attribute.type, attribute.array );
38445 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
38449 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
38450 array.push( bufferAttribute );
38454 geometry.morphAttributes[ key ] = array;
38460 const morphTargetsRelative = json.data.morphTargetsRelative;
38462 if ( morphTargetsRelative ) {
38464 geometry.morphTargetsRelative = true;
38468 const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
38470 if ( groups !== undefined ) {
38472 for ( let i = 0, n = groups.length; i !== n; ++ i ) {
38474 const group = groups[ i ];
38476 geometry.addGroup( group.start, group.count, group.materialIndex );
38482 const boundingSphere = json.data.boundingSphere;
38484 if ( boundingSphere !== undefined ) {
38486 const center = new Vector3();
38488 if ( boundingSphere.center !== undefined ) {
38490 center.fromArray( boundingSphere.center );
38494 geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
38498 if ( json.name ) geometry.name = json.name;
38499 if ( json.userData ) geometry.userData = json.userData;
38507 class ObjectLoader extends Loader {
38509 constructor( manager ) {
38515 load( url, onLoad, onProgress, onError ) {
38517 const scope = this;
38519 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
38520 this.resourcePath = this.resourcePath || path;
38522 const loader = new FileLoader( this.manager );
38523 loader.setPath( this.path );
38524 loader.setRequestHeader( this.requestHeader );
38525 loader.setWithCredentials( this.withCredentials );
38526 loader.load( url, function ( text ) {
38532 json = JSON.parse( text );
38534 } catch ( error ) {
38536 if ( onError !== undefined ) onError( error );
38538 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
38544 const metadata = json.metadata;
38546 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
38548 console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
38553 scope.parse( json, onLoad );
38555 }, onProgress, onError );
38559 parse( json, onLoad ) {
38561 const animations = this.parseAnimations( json.animations );
38562 const shapes = this.parseShapes( json.shapes );
38563 const geometries = this.parseGeometries( json.geometries, shapes );
38565 const images = this.parseImages( json.images, function () {
38567 if ( onLoad !== undefined ) onLoad( object );
38571 const textures = this.parseTextures( json.textures, images );
38572 const materials = this.parseMaterials( json.materials, textures );
38574 const object = this.parseObject( json.object, geometries, materials, animations );
38575 const skeletons = this.parseSkeletons( json.skeletons, object );
38577 this.bindSkeletons( object, skeletons );
38581 if ( onLoad !== undefined ) {
38583 let hasImages = false;
38585 for ( const uuid in images ) {
38587 if ( images[ uuid ] instanceof HTMLImageElement ) {
38596 if ( hasImages === false ) onLoad( object );
38604 parseShapes( json ) {
38608 if ( json !== undefined ) {
38610 for ( let i = 0, l = json.length; i < l; i ++ ) {
38612 const shape = new Shape().fromJSON( json[ i ] );
38614 shapes[ shape.uuid ] = shape;
38624 parseSkeletons( json, object ) {
38626 const skeletons = {};
38629 // generate bone lookup table
38631 object.traverse( function ( child ) {
38633 if ( child.isBone ) bones[ child.uuid ] = child;
38637 // create skeletons
38639 if ( json !== undefined ) {
38641 for ( let i = 0, l = json.length; i < l; i ++ ) {
38643 const skeleton = new Skeleton().fromJSON( json[ i ], bones );
38645 skeletons[ skeleton.uuid ] = skeleton;
38655 parseGeometries( json, shapes ) {
38657 const geometries = {};
38658 let geometryShapes;
38660 if ( json !== undefined ) {
38662 const bufferGeometryLoader = new BufferGeometryLoader();
38664 for ( let i = 0, l = json.length; i < l; i ++ ) {
38667 const data = json[ i ];
38669 switch ( data.type ) {
38671 case 'PlaneGeometry':
38672 case 'PlaneBufferGeometry':
38674 geometry = new Geometries[ data.type ](
38677 data.widthSegments,
38678 data.heightSegments
38683 case 'BoxGeometry':
38684 case 'BoxBufferGeometry':
38686 geometry = new Geometries[ data.type ](
38690 data.widthSegments,
38691 data.heightSegments,
38697 case 'CircleGeometry':
38698 case 'CircleBufferGeometry':
38700 geometry = new Geometries[ data.type ](
38709 case 'CylinderGeometry':
38710 case 'CylinderBufferGeometry':
38712 geometry = new Geometries[ data.type ](
38716 data.radialSegments,
38717 data.heightSegments,
38725 case 'ConeGeometry':
38726 case 'ConeBufferGeometry':
38728 geometry = new Geometries[ data.type ](
38731 data.radialSegments,
38732 data.heightSegments,
38740 case 'SphereGeometry':
38741 case 'SphereBufferGeometry':
38743 geometry = new Geometries[ data.type ](
38745 data.widthSegments,
38746 data.heightSegments,
38755 case 'DodecahedronGeometry':
38756 case 'DodecahedronBufferGeometry':
38757 case 'IcosahedronGeometry':
38758 case 'IcosahedronBufferGeometry':
38759 case 'OctahedronGeometry':
38760 case 'OctahedronBufferGeometry':
38761 case 'TetrahedronGeometry':
38762 case 'TetrahedronBufferGeometry':
38764 geometry = new Geometries[ data.type ](
38771 case 'RingGeometry':
38772 case 'RingBufferGeometry':
38774 geometry = new Geometries[ data.type ](
38777 data.thetaSegments,
38785 case 'TorusGeometry':
38786 case 'TorusBufferGeometry':
38788 geometry = new Geometries[ data.type ](
38791 data.radialSegments,
38792 data.tubularSegments,
38798 case 'TorusKnotGeometry':
38799 case 'TorusKnotBufferGeometry':
38801 geometry = new Geometries[ data.type ](
38804 data.tubularSegments,
38805 data.radialSegments,
38812 case 'TubeGeometry':
38813 case 'TubeBufferGeometry':
38815 // This only works for built-in curves (e.g. CatmullRomCurve3).
38816 // User defined curves or instances of CurvePath will not be deserialized.
38817 geometry = new Geometries[ data.type ](
38818 new Curves[ data.path.type ]().fromJSON( data.path ),
38819 data.tubularSegments,
38821 data.radialSegments,
38827 case 'LatheGeometry':
38828 case 'LatheBufferGeometry':
38830 geometry = new Geometries[ data.type ](
38839 case 'PolyhedronGeometry':
38840 case 'PolyhedronBufferGeometry':
38842 geometry = new Geometries[ data.type ](
38851 case 'ShapeGeometry':
38852 case 'ShapeBufferGeometry':
38854 geometryShapes = [];
38856 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
38858 const shape = shapes[ data.shapes[ j ] ];
38860 geometryShapes.push( shape );
38864 geometry = new Geometries[ data.type ](
38872 case 'ExtrudeGeometry':
38873 case 'ExtrudeBufferGeometry':
38875 geometryShapes = [];
38877 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
38879 const shape = shapes[ data.shapes[ j ] ];
38881 geometryShapes.push( shape );
38885 const extrudePath = data.options.extrudePath;
38887 if ( extrudePath !== undefined ) {
38889 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
38893 geometry = new Geometries[ data.type ](
38900 case 'BufferGeometry':
38901 case 'InstancedBufferGeometry':
38903 geometry = bufferGeometryLoader.parse( data );
38909 console.error( 'THREE.ObjectLoader: Loading "Geometry" is not supported anymore.' );
38915 console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
38921 geometry.uuid = data.uuid;
38923 if ( data.name !== undefined ) geometry.name = data.name;
38924 if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData;
38926 geometries[ data.uuid ] = geometry;
38936 parseMaterials( json, textures ) {
38938 const cache = {}; // MultiMaterial
38939 const materials = {};
38941 if ( json !== undefined ) {
38943 const loader = new MaterialLoader();
38944 loader.setTextures( textures );
38946 for ( let i = 0, l = json.length; i < l; i ++ ) {
38948 const data = json[ i ];
38950 if ( data.type === 'MultiMaterial' ) {
38956 for ( let j = 0; j < data.materials.length; j ++ ) {
38958 const material = data.materials[ j ];
38960 if ( cache[ material.uuid ] === undefined ) {
38962 cache[ material.uuid ] = loader.parse( material );
38966 array.push( cache[ material.uuid ] );
38970 materials[ data.uuid ] = array;
38974 if ( cache[ data.uuid ] === undefined ) {
38976 cache[ data.uuid ] = loader.parse( data );
38980 materials[ data.uuid ] = cache[ data.uuid ];
38992 parseAnimations( json ) {
38994 const animations = {};
38996 if ( json !== undefined ) {
38998 for ( let i = 0; i < json.length; i ++ ) {
39000 const data = json[ i ];
39002 const clip = AnimationClip.parse( data );
39004 animations[ clip.uuid ] = clip;
39014 parseImages( json, onLoad ) {
39016 const scope = this;
39021 function loadImage( url ) {
39023 scope.manager.itemStart( url );
39025 return loader.load( url, function () {
39027 scope.manager.itemEnd( url );
39029 }, undefined, function () {
39031 scope.manager.itemError( url );
39032 scope.manager.itemEnd( url );
39038 function deserializeImage( image ) {
39040 if ( typeof image === 'string' ) {
39044 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
39046 return loadImage( path );
39050 if ( image.data ) {
39053 data: getTypedArray( image.type, image.data ),
39054 width: image.width,
39055 height: image.height
39068 if ( json !== undefined && json.length > 0 ) {
39070 const manager = new LoadingManager( onLoad );
39072 loader = new ImageLoader( manager );
39073 loader.setCrossOrigin( this.crossOrigin );
39075 for ( let i = 0, il = json.length; i < il; i ++ ) {
39077 const image = json[ i ];
39078 const url = image.url;
39080 if ( Array.isArray( url ) ) {
39082 // load array of images e.g CubeTexture
39084 images[ image.uuid ] = [];
39086 for ( let j = 0, jl = url.length; j < jl; j ++ ) {
39088 const currentUrl = url[ j ];
39090 const deserializedImage = deserializeImage( currentUrl );
39092 if ( deserializedImage !== null ) {
39094 if ( deserializedImage instanceof HTMLImageElement ) {
39096 images[ image.uuid ].push( deserializedImage );
39100 // special case: handle array of data textures for cube textures
39102 images[ image.uuid ].push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
39112 // load single image
39114 const deserializedImage = deserializeImage( image.url );
39116 if ( deserializedImage !== null ) {
39118 images[ image.uuid ] = deserializedImage;
39132 parseTextures( json, images ) {
39134 function parseConstant( value, type ) {
39136 if ( typeof value === 'number' ) return value;
39138 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
39140 return type[ value ];
39144 const textures = {};
39146 if ( json !== undefined ) {
39148 for ( let i = 0, l = json.length; i < l; i ++ ) {
39150 const data = json[ i ];
39152 if ( data.image === undefined ) {
39154 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
39158 if ( images[ data.image ] === undefined ) {
39160 console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
39165 const image = images[ data.image ];
39167 if ( Array.isArray( image ) ) {
39169 texture = new CubeTexture( image );
39171 if ( image.length === 6 ) texture.needsUpdate = true;
39175 if ( image && image.data ) {
39177 texture = new DataTexture( image.data, image.width, image.height );
39181 texture = new Texture( image );
39185 if ( image ) texture.needsUpdate = true; // textures can have undefined image data
39189 texture.uuid = data.uuid;
39191 if ( data.name !== undefined ) texture.name = data.name;
39193 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
39195 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
39196 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
39197 if ( data.center !== undefined ) texture.center.fromArray( data.center );
39198 if ( data.rotation !== undefined ) texture.rotation = data.rotation;
39200 if ( data.wrap !== undefined ) {
39202 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
39203 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
39207 if ( data.format !== undefined ) texture.format = data.format;
39208 if ( data.type !== undefined ) texture.type = data.type;
39209 if ( data.encoding !== undefined ) texture.encoding = data.encoding;
39211 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
39212 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
39213 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
39215 if ( data.flipY !== undefined ) texture.flipY = data.flipY;
39217 if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
39218 if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
39220 textures[ data.uuid ] = texture;
39230 parseObject( data, geometries, materials, animations ) {
39234 function getGeometry( name ) {
39236 if ( geometries[ name ] === undefined ) {
39238 console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
39242 return geometries[ name ];
39246 function getMaterial( name ) {
39248 if ( name === undefined ) return undefined;
39250 if ( Array.isArray( name ) ) {
39254 for ( let i = 0, l = name.length; i < l; i ++ ) {
39256 const uuid = name[ i ];
39258 if ( materials[ uuid ] === undefined ) {
39260 console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
39264 array.push( materials[ uuid ] );
39272 if ( materials[ name ] === undefined ) {
39274 console.warn( 'THREE.ObjectLoader: Undefined material', name );
39278 return materials[ name ];
39282 let geometry, material;
39284 switch ( data.type ) {
39288 object = new Scene();
39290 if ( data.background !== undefined ) {
39292 if ( Number.isInteger( data.background ) ) {
39294 object.background = new Color( data.background );
39300 if ( data.fog !== undefined ) {
39302 if ( data.fog.type === 'Fog' ) {
39304 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
39306 } else if ( data.fog.type === 'FogExp2' ) {
39308 object.fog = new FogExp2( data.fog.color, data.fog.density );
39316 case 'PerspectiveCamera':
39318 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
39320 if ( data.focus !== undefined ) object.focus = data.focus;
39321 if ( data.zoom !== undefined ) object.zoom = data.zoom;
39322 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
39323 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
39324 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
39328 case 'OrthographicCamera':
39330 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
39332 if ( data.zoom !== undefined ) object.zoom = data.zoom;
39333 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
39337 case 'AmbientLight':
39339 object = new AmbientLight( data.color, data.intensity );
39343 case 'DirectionalLight':
39345 object = new DirectionalLight( data.color, data.intensity );
39351 object = new PointLight( data.color, data.intensity, data.distance, data.decay );
39355 case 'RectAreaLight':
39357 object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
39363 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
39367 case 'HemisphereLight':
39369 object = new HemisphereLight( data.color, data.groundColor, data.intensity );
39375 object = new LightProbe().fromJSON( data );
39379 case 'SkinnedMesh':
39381 geometry = getGeometry( data.geometry );
39382 material = getMaterial( data.material );
39384 object = new SkinnedMesh( geometry, material );
39386 if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
39387 if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
39388 if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
39394 geometry = getGeometry( data.geometry );
39395 material = getMaterial( data.material );
39397 object = new Mesh( geometry, material );
39401 case 'InstancedMesh':
39403 geometry = getGeometry( data.geometry );
39404 material = getMaterial( data.material );
39405 const count = data.count;
39406 const instanceMatrix = data.instanceMatrix;
39408 object = new InstancedMesh( geometry, material, count );
39409 object.instanceMatrix = new BufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
39415 object = new LOD();
39421 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );
39427 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
39431 case 'LineSegments':
39433 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
39440 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
39446 object = new Sprite( getMaterial( data.material ) );
39452 object = new Group();
39458 object = new Bone();
39464 object = new Object3D();
39468 object.uuid = data.uuid;
39470 if ( data.name !== undefined ) object.name = data.name;
39472 if ( data.matrix !== undefined ) {
39474 object.matrix.fromArray( data.matrix );
39476 if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
39477 if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
39481 if ( data.position !== undefined ) object.position.fromArray( data.position );
39482 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
39483 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
39484 if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
39488 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
39489 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
39491 if ( data.shadow ) {
39493 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
39494 if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
39495 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
39496 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
39497 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
39501 if ( data.visible !== undefined ) object.visible = data.visible;
39502 if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
39503 if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
39504 if ( data.userData !== undefined ) object.userData = data.userData;
39505 if ( data.layers !== undefined ) object.layers.mask = data.layers;
39507 if ( data.children !== undefined ) {
39509 const children = data.children;
39511 for ( let i = 0; i < children.length; i ++ ) {
39513 object.add( this.parseObject( children[ i ], geometries, materials, animations ) );
39519 if ( data.animations !== undefined ) {
39521 const objectAnimations = data.animations;
39523 for ( let i = 0; i < objectAnimations.length; i ++ ) {
39525 const uuid = objectAnimations[ i ];
39527 object.animations.push( animations[ uuid ] );
39533 if ( data.type === 'LOD' ) {
39535 if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
39537 const levels = data.levels;
39539 for ( let l = 0; l < levels.length; l ++ ) {
39541 const level = levels[ l ];
39542 const child = object.getObjectByProperty( 'uuid', level.object );
39544 if ( child !== undefined ) {
39546 object.addLevel( child, level.distance );
39558 bindSkeletons( object, skeletons ) {
39560 if ( Object.keys( skeletons ).length === 0 ) return;
39562 object.traverse( function ( child ) {
39564 if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
39566 const skeleton = skeletons[ child.skeleton ];
39568 if ( skeleton === undefined ) {
39570 console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
39574 child.bind( skeleton, child.bindMatrix );
39586 setTexturePath( value ) {
39588 console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' );
39589 return this.setResourcePath( value );
39595 const TEXTURE_MAPPING = {
39596 UVMapping: UVMapping,
39597 CubeReflectionMapping: CubeReflectionMapping,
39598 CubeRefractionMapping: CubeRefractionMapping,
39599 EquirectangularReflectionMapping: EquirectangularReflectionMapping,
39600 EquirectangularRefractionMapping: EquirectangularRefractionMapping,
39601 CubeUVReflectionMapping: CubeUVReflectionMapping,
39602 CubeUVRefractionMapping: CubeUVRefractionMapping
39605 const TEXTURE_WRAPPING = {
39606 RepeatWrapping: RepeatWrapping,
39607 ClampToEdgeWrapping: ClampToEdgeWrapping,
39608 MirroredRepeatWrapping: MirroredRepeatWrapping
39611 const TEXTURE_FILTER = {
39612 NearestFilter: NearestFilter,
39613 NearestMipmapNearestFilter: NearestMipmapNearestFilter,
39614 NearestMipmapLinearFilter: NearestMipmapLinearFilter,
39615 LinearFilter: LinearFilter,
39616 LinearMipmapNearestFilter: LinearMipmapNearestFilter,
39617 LinearMipmapLinearFilter: LinearMipmapLinearFilter
39620 function ImageBitmapLoader( manager ) {
39622 if ( typeof createImageBitmap === 'undefined' ) {
39624 console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
39628 if ( typeof fetch === 'undefined' ) {
39630 console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
39634 Loader.call( this, manager );
39636 this.options = { premultiplyAlpha: 'none' };
39640 ImageBitmapLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
39642 constructor: ImageBitmapLoader,
39644 isImageBitmapLoader: true,
39646 setOptions: function setOptions( options ) {
39648 this.options = options;
39654 load: function ( url, onLoad, onProgress, onError ) {
39656 if ( url === undefined ) url = '';
39658 if ( this.path !== undefined ) url = this.path + url;
39660 url = this.manager.resolveURL( url );
39662 const scope = this;
39664 const cached = Cache.get( url );
39666 if ( cached !== undefined ) {
39668 scope.manager.itemStart( url );
39670 setTimeout( function () {
39672 if ( onLoad ) onLoad( cached );
39674 scope.manager.itemEnd( url );
39682 const fetchOptions = {};
39683 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
39685 fetch( url, fetchOptions ).then( function ( res ) {
39689 } ).then( function ( blob ) {
39691 return createImageBitmap( blob, scope.options );
39693 } ).then( function ( imageBitmap ) {
39695 Cache.add( url, imageBitmap );
39697 if ( onLoad ) onLoad( imageBitmap );
39699 scope.manager.itemEnd( url );
39701 } ).catch( function ( e ) {
39703 if ( onError ) onError( e );
39705 scope.manager.itemError( url );
39706 scope.manager.itemEnd( url );
39710 scope.manager.itemStart( url );
39716 function ShapePath() {
39718 this.type = 'ShapePath';
39720 this.color = new Color();
39722 this.subPaths = [];
39723 this.currentPath = null;
39727 Object.assign( ShapePath.prototype, {
39729 moveTo: function ( x, y ) {
39731 this.currentPath = new Path();
39732 this.subPaths.push( this.currentPath );
39733 this.currentPath.moveTo( x, y );
39739 lineTo: function ( x, y ) {
39741 this.currentPath.lineTo( x, y );
39747 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
39749 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
39755 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
39757 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
39763 splineThru: function ( pts ) {
39765 this.currentPath.splineThru( pts );
39771 toShapes: function ( isCCW, noHoles ) {
39773 function toShapesNoHoles( inSubpaths ) {
39777 for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
39779 const tmpPath = inSubpaths[ i ];
39781 const tmpShape = new Shape();
39782 tmpShape.curves = tmpPath.curves;
39784 shapes.push( tmpShape );
39792 function isPointInsidePolygon( inPt, inPolygon ) {
39794 const polyLen = inPolygon.length;
39796 // inPt on polygon contour => immediate success or
39797 // toggling of inside/outside at every single! intersection point of an edge
39798 // with the horizontal line through inPt, left of inPt
39799 // not counting lowerY endpoints of edges and whole edges on that line
39800 let inside = false;
39801 for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
39803 let edgeLowPt = inPolygon[ p ];
39804 let edgeHighPt = inPolygon[ q ];
39806 let edgeDx = edgeHighPt.x - edgeLowPt.x;
39807 let edgeDy = edgeHighPt.y - edgeLowPt.y;
39809 if ( Math.abs( edgeDy ) > Number.EPSILON ) {
39812 if ( edgeDy < 0 ) {
39814 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
39815 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
39819 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
39821 if ( inPt.y === edgeLowPt.y ) {
39823 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
39824 // continue; // no intersection or edgeLowPt => doesn't count !!!
39828 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
39829 if ( perpEdge === 0 ) return true; // inPt is on contour ?
39830 if ( perpEdge < 0 ) continue;
39831 inside = ! inside; // true intersection left of inPt
39837 // parallel or collinear
39838 if ( inPt.y !== edgeLowPt.y ) continue; // parallel
39839 // edge lies on the same horizontal line as inPt
39840 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
39841 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
39852 const isClockWise = ShapeUtils.isClockWise;
39854 const subPaths = this.subPaths;
39855 if ( subPaths.length === 0 ) return [];
39857 if ( noHoles === true ) return toShapesNoHoles( subPaths );
39860 let solid, tmpPath, tmpShape;
39863 if ( subPaths.length === 1 ) {
39865 tmpPath = subPaths[ 0 ];
39866 tmpShape = new Shape();
39867 tmpShape.curves = tmpPath.curves;
39868 shapes.push( tmpShape );
39873 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
39874 holesFirst = isCCW ? ! holesFirst : holesFirst;
39876 // console.log("Holes first", holesFirst);
39878 const betterShapeHoles = [];
39879 const newShapes = [];
39880 let newShapeHoles = [];
39884 newShapes[ mainIdx ] = undefined;
39885 newShapeHoles[ mainIdx ] = [];
39887 for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
39889 tmpPath = subPaths[ i ];
39890 tmpPoints = tmpPath.getPoints();
39891 solid = isClockWise( tmpPoints );
39892 solid = isCCW ? ! solid : solid;
39896 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
39898 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
39899 newShapes[ mainIdx ].s.curves = tmpPath.curves;
39901 if ( holesFirst ) mainIdx ++;
39902 newShapeHoles[ mainIdx ] = [];
39904 //console.log('cw', i);
39908 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
39910 //console.log('ccw', i);
39916 // only Holes? -> probably all Shapes with wrong orientation
39917 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
39920 if ( newShapes.length > 1 ) {
39922 let ambiguous = false;
39923 const toChange = [];
39925 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
39927 betterShapeHoles[ sIdx ] = [];
39931 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
39933 const sho = newShapeHoles[ sIdx ];
39935 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
39937 const ho = sho[ hIdx ];
39938 let hole_unassigned = true;
39940 for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
39942 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
39944 if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
39945 if ( hole_unassigned ) {
39947 hole_unassigned = false;
39948 betterShapeHoles[ s2Idx ].push( ho );
39960 if ( hole_unassigned ) {
39962 betterShapeHoles[ sIdx ].push( ho );
39969 // console.log("ambiguous: ", ambiguous);
39971 if ( toChange.length > 0 ) {
39973 // console.log("to change: ", toChange);
39974 if ( ! ambiguous ) newShapeHoles = betterShapeHoles;
39982 for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
39984 tmpShape = newShapes[ i ].s;
39985 shapes.push( tmpShape );
39986 tmpHoles = newShapeHoles[ i ];
39988 for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
39990 tmpShape.holes.push( tmpHoles[ j ].h );
39996 //console.log("shape", shapes);
40006 constructor( data ) {
40008 Object.defineProperty( this, 'isFont', { value: true } );
40010 this.type = 'Font';
40016 generateShapes( text, size = 100 ) {
40019 const paths = createPaths( text, size, this.data );
40021 for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
40023 Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
40033 function createPaths( text, size, data ) {
40035 const chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988
40036 const scale = size / data.resolution;
40037 const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
40041 let offsetX = 0, offsetY = 0;
40043 for ( let i = 0; i < chars.length; i ++ ) {
40045 const char = chars[ i ];
40047 if ( char === '\n' ) {
40050 offsetY -= line_height;
40054 const ret = createPath( char, scale, offsetX, offsetY, data );
40055 offsetX += ret.offsetX;
40056 paths.push( ret.path );
40066 function createPath( char, scale, offsetX, offsetY, data ) {
40068 const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
40072 console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
40078 const path = new ShapePath();
40080 let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
40084 const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
40086 for ( let i = 0, l = outline.length; i < l; ) {
40088 const action = outline[ i ++ ];
40090 switch ( action ) {
40092 case 'm': // moveTo
40094 x = outline[ i ++ ] * scale + offsetX;
40095 y = outline[ i ++ ] * scale + offsetY;
40097 path.moveTo( x, y );
40101 case 'l': // lineTo
40103 x = outline[ i ++ ] * scale + offsetX;
40104 y = outline[ i ++ ] * scale + offsetY;
40106 path.lineTo( x, y );
40110 case 'q': // quadraticCurveTo
40112 cpx = outline[ i ++ ] * scale + offsetX;
40113 cpy = outline[ i ++ ] * scale + offsetY;
40114 cpx1 = outline[ i ++ ] * scale + offsetX;
40115 cpy1 = outline[ i ++ ] * scale + offsetY;
40117 path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
40121 case 'b': // bezierCurveTo
40123 cpx = outline[ i ++ ] * scale + offsetX;
40124 cpy = outline[ i ++ ] * scale + offsetY;
40125 cpx1 = outline[ i ++ ] * scale + offsetX;
40126 cpy1 = outline[ i ++ ] * scale + offsetY;
40127 cpx2 = outline[ i ++ ] * scale + offsetX;
40128 cpy2 = outline[ i ++ ] * scale + offsetY;
40130 path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
40140 return { offsetX: glyph.ha * scale, path: path };
40144 function FontLoader( manager ) {
40146 Loader.call( this, manager );
40150 FontLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40152 constructor: FontLoader,
40154 load: function ( url, onLoad, onProgress, onError ) {
40156 const scope = this;
40158 const loader = new FileLoader( this.manager );
40159 loader.setPath( this.path );
40160 loader.setRequestHeader( this.requestHeader );
40161 loader.setWithCredentials( scope.withCredentials );
40162 loader.load( url, function ( text ) {
40168 json = JSON.parse( text );
40172 console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
40173 json = JSON.parse( text.substring( 65, text.length - 2 ) );
40177 const font = scope.parse( json );
40179 if ( onLoad ) onLoad( font );
40181 }, onProgress, onError );
40185 parse: function ( json ) {
40187 return new Font( json );
40195 const AudioContext = {
40197 getContext: function () {
40199 if ( _context === undefined ) {
40201 _context = new ( window.AudioContext || window.webkitAudioContext )();
40209 setContext: function ( value ) {
40217 function AudioLoader( manager ) {
40219 Loader.call( this, manager );
40223 AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40225 constructor: AudioLoader,
40227 load: function ( url, onLoad, onProgress, onError ) {
40229 const scope = this;
40231 const loader = new FileLoader( scope.manager );
40232 loader.setResponseType( 'arraybuffer' );
40233 loader.setPath( scope.path );
40234 loader.setRequestHeader( scope.requestHeader );
40235 loader.setWithCredentials( scope.withCredentials );
40236 loader.load( url, function ( buffer ) {
40240 // Create a copy of the buffer. The `decodeAudioData` method
40241 // detaches the buffer when complete, preventing reuse.
40242 const bufferCopy = buffer.slice( 0 );
40244 const context = AudioContext.getContext();
40245 context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
40247 onLoad( audioBuffer );
40259 console.error( e );
40263 scope.manager.itemError( url );
40267 }, onProgress, onError );
40273 function HemisphereLightProbe( skyColor, groundColor, intensity ) {
40275 LightProbe.call( this, undefined, intensity );
40277 const color1 = new Color().set( skyColor );
40278 const color2 = new Color().set( groundColor );
40280 const sky = new Vector3( color1.r, color1.g, color1.b );
40281 const ground = new Vector3( color2.r, color2.g, color2.b );
40283 // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI );
40284 const c0 = Math.sqrt( Math.PI );
40285 const c1 = c0 * Math.sqrt( 0.75 );
40287 this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 );
40288 this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 );
40292 HemisphereLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
40294 constructor: HemisphereLightProbe,
40296 isHemisphereLightProbe: true,
40298 copy: function ( source ) { // modifying colors not currently supported
40300 LightProbe.prototype.copy.call( this, source );
40306 toJSON: function ( meta ) {
40308 const data = LightProbe.prototype.toJSON.call( this, meta );
40310 // data.sh = this.sh.toArray(); // todo
40318 function AmbientLightProbe( color, intensity ) {
40320 LightProbe.call( this, undefined, intensity );
40322 const color1 = new Color().set( color );
40324 // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI );
40325 this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) );
40329 AmbientLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
40331 constructor: AmbientLightProbe,
40333 isAmbientLightProbe: true,
40335 copy: function ( source ) { // modifying color not currently supported
40337 LightProbe.prototype.copy.call( this, source );
40343 toJSON: function ( meta ) {
40345 const data = LightProbe.prototype.toJSON.call( this, meta );
40347 // data.sh = this.sh.toArray(); // todo
40355 const _eyeRight = new Matrix4();
40356 const _eyeLeft = new Matrix4();
40358 function StereoCamera() {
40360 this.type = 'StereoCamera';
40364 this.eyeSep = 0.064;
40366 this.cameraL = new PerspectiveCamera();
40367 this.cameraL.layers.enable( 1 );
40368 this.cameraL.matrixAutoUpdate = false;
40370 this.cameraR = new PerspectiveCamera();
40371 this.cameraR.layers.enable( 2 );
40372 this.cameraR.matrixAutoUpdate = false;
40386 Object.assign( StereoCamera.prototype, {
40388 update: function ( camera ) {
40390 const cache = this._cache;
40392 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
40393 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
40394 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
40396 if ( needsUpdate ) {
40398 cache.focus = camera.focus;
40399 cache.fov = camera.fov;
40400 cache.aspect = camera.aspect * this.aspect;
40401 cache.near = camera.near;
40402 cache.far = camera.far;
40403 cache.zoom = camera.zoom;
40404 cache.eyeSep = this.eyeSep;
40406 // Off-axis stereoscopic effect based on
40407 // http://paulbourke.net/stereographics/stereorender/
40409 const projectionMatrix = camera.projectionMatrix.clone();
40410 const eyeSepHalf = cache.eyeSep / 2;
40411 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
40412 const ymax = ( cache.near * Math.tan( MathUtils.DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
40415 // translate xOffset
40417 _eyeLeft.elements[ 12 ] = - eyeSepHalf;
40418 _eyeRight.elements[ 12 ] = eyeSepHalf;
40422 xmin = - ymax * cache.aspect + eyeSepOnProjection;
40423 xmax = ymax * cache.aspect + eyeSepOnProjection;
40425 projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
40426 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
40428 this.cameraL.projectionMatrix.copy( projectionMatrix );
40432 xmin = - ymax * cache.aspect - eyeSepOnProjection;
40433 xmax = ymax * cache.aspect - eyeSepOnProjection;
40435 projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
40436 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
40438 this.cameraR.projectionMatrix.copy( projectionMatrix );
40442 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
40443 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
40451 constructor( autoStart ) {
40453 this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
40455 this.startTime = 0;
40457 this.elapsedTime = 0;
40459 this.running = false;
40465 this.startTime = now();
40467 this.oldTime = this.startTime;
40468 this.elapsedTime = 0;
40469 this.running = true;
40475 this.getElapsedTime();
40476 this.running = false;
40477 this.autoStart = false;
40484 return this.elapsedTime;
40492 if ( this.autoStart && ! this.running ) {
40499 if ( this.running ) {
40501 const newTime = now();
40503 diff = ( newTime - this.oldTime ) / 1000;
40504 this.oldTime = newTime;
40506 this.elapsedTime += diff;
40518 return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
40522 const _position$2 = /*@__PURE__*/ new Vector3();
40523 const _quaternion$3 = /*@__PURE__*/ new Quaternion();
40524 const _scale$1 = /*@__PURE__*/ new Vector3();
40525 const _orientation = /*@__PURE__*/ new Vector3();
40527 class AudioListener extends Object3D {
40533 this.type = 'AudioListener';
40535 this.context = AudioContext.getContext();
40537 this.gain = this.context.createGain();
40538 this.gain.connect( this.context.destination );
40540 this.filter = null;
40542 this.timeDelta = 0;
40546 this._clock = new Clock();
40558 if ( this.filter !== null ) {
40560 this.gain.disconnect( this.filter );
40561 this.filter.disconnect( this.context.destination );
40562 this.gain.connect( this.context.destination );
40563 this.filter = null;
40573 return this.filter;
40577 setFilter( value ) {
40579 if ( this.filter !== null ) {
40581 this.gain.disconnect( this.filter );
40582 this.filter.disconnect( this.context.destination );
40586 this.gain.disconnect( this.context.destination );
40590 this.filter = value;
40591 this.gain.connect( this.filter );
40592 this.filter.connect( this.context.destination );
40598 getMasterVolume() {
40600 return this.gain.gain.value;
40604 setMasterVolume( value ) {
40606 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
40612 updateMatrixWorld( force ) {
40614 super.updateMatrixWorld( force );
40616 const listener = this.context.listener;
40617 const up = this.up;
40619 this.timeDelta = this._clock.getDelta();
40621 this.matrixWorld.decompose( _position$2, _quaternion$3, _scale$1 );
40623 _orientation.set( 0, 0, - 1 ).applyQuaternion( _quaternion$3 );
40625 if ( listener.positionX ) {
40627 // code path for Chrome (see #14393)
40629 const endTime = this.context.currentTime + this.timeDelta;
40631 listener.positionX.linearRampToValueAtTime( _position$2.x, endTime );
40632 listener.positionY.linearRampToValueAtTime( _position$2.y, endTime );
40633 listener.positionZ.linearRampToValueAtTime( _position$2.z, endTime );
40634 listener.forwardX.linearRampToValueAtTime( _orientation.x, endTime );
40635 listener.forwardY.linearRampToValueAtTime( _orientation.y, endTime );
40636 listener.forwardZ.linearRampToValueAtTime( _orientation.z, endTime );
40637 listener.upX.linearRampToValueAtTime( up.x, endTime );
40638 listener.upY.linearRampToValueAtTime( up.y, endTime );
40639 listener.upZ.linearRampToValueAtTime( up.z, endTime );
40643 listener.setPosition( _position$2.x, _position$2.y, _position$2.z );
40644 listener.setOrientation( _orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z );
40652 class Audio extends Object3D {
40654 constructor( listener ) {
40658 this.type = 'Audio';
40660 this.listener = listener;
40661 this.context = listener.context;
40663 this.gain = this.context.createGain();
40664 this.gain.connect( listener.getInput() );
40666 this.autoplay = false;
40668 this.buffer = null;
40671 this.loopStart = 0;
40674 this.duration = undefined;
40675 this.playbackRate = 1;
40676 this.isPlaying = false;
40677 this.hasPlaybackControl = true;
40678 this.source = null;
40679 this.sourceType = 'empty';
40681 this._startedAt = 0;
40682 this._progress = 0;
40683 this._connected = false;
40695 setNodeSource( audioNode ) {
40697 this.hasPlaybackControl = false;
40698 this.sourceType = 'audioNode';
40699 this.source = audioNode;
40706 setMediaElementSource( mediaElement ) {
40708 this.hasPlaybackControl = false;
40709 this.sourceType = 'mediaNode';
40710 this.source = this.context.createMediaElementSource( mediaElement );
40717 setMediaStreamSource( mediaStream ) {
40719 this.hasPlaybackControl = false;
40720 this.sourceType = 'mediaStreamNode';
40721 this.source = this.context.createMediaStreamSource( mediaStream );
40728 setBuffer( audioBuffer ) {
40730 this.buffer = audioBuffer;
40731 this.sourceType = 'buffer';
40733 if ( this.autoplay ) this.play();
40739 play( delay = 0 ) {
40741 if ( this.isPlaying === true ) {
40743 console.warn( 'THREE.Audio: Audio is already playing.' );
40748 if ( this.hasPlaybackControl === false ) {
40750 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40755 this._startedAt = this.context.currentTime + delay;
40757 const source = this.context.createBufferSource();
40758 source.buffer = this.buffer;
40759 source.loop = this.loop;
40760 source.loopStart = this.loopStart;
40761 source.loopEnd = this.loopEnd;
40762 source.onended = this.onEnded.bind( this );
40763 source.start( this._startedAt, this._progress + this.offset, this.duration );
40765 this.isPlaying = true;
40767 this.source = source;
40769 this.setDetune( this.detune );
40770 this.setPlaybackRate( this.playbackRate );
40772 return this.connect();
40778 if ( this.hasPlaybackControl === false ) {
40780 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40785 if ( this.isPlaying === true ) {
40787 // update current progress
40789 this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
40791 if ( this.loop === true ) {
40793 // ensure _progress does not exceed duration with looped audios
40795 this._progress = this._progress % ( this.duration || this.buffer.duration );
40799 this.source.stop();
40800 this.source.onended = null;
40802 this.isPlaying = false;
40812 if ( this.hasPlaybackControl === false ) {
40814 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40819 this._progress = 0;
40821 this.source.stop();
40822 this.source.onended = null;
40823 this.isPlaying = false;
40831 if ( this.filters.length > 0 ) {
40833 this.source.connect( this.filters[ 0 ] );
40835 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
40837 this.filters[ i - 1 ].connect( this.filters[ i ] );
40841 this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
40845 this.source.connect( this.getOutput() );
40849 this._connected = true;
40857 if ( this.filters.length > 0 ) {
40859 this.source.disconnect( this.filters[ 0 ] );
40861 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
40863 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
40867 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
40871 this.source.disconnect( this.getOutput() );
40875 this._connected = false;
40883 return this.filters;
40887 setFilters( value ) {
40889 if ( ! value ) value = [];
40891 if ( this._connected === true ) {
40894 this.filters = value.slice();
40899 this.filters = value.slice();
40907 setDetune( value ) {
40909 this.detune = value;
40911 if ( this.source.detune === undefined ) return; // only set detune when available
40913 if ( this.isPlaying === true ) {
40915 this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
40925 return this.detune;
40931 return this.getFilters()[ 0 ];
40935 setFilter( filter ) {
40937 return this.setFilters( filter ? [ filter ] : [] );
40941 setPlaybackRate( value ) {
40943 if ( this.hasPlaybackControl === false ) {
40945 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40950 this.playbackRate = value;
40952 if ( this.isPlaying === true ) {
40954 this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
40962 getPlaybackRate() {
40964 return this.playbackRate;
40970 this.isPlaying = false;
40976 if ( this.hasPlaybackControl === false ) {
40978 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40989 if ( this.hasPlaybackControl === false ) {
40991 console.warn( 'THREE.Audio: this Audio has no playback control.' );
40998 if ( this.isPlaying === true ) {
41000 this.source.loop = this.loop;
41008 setLoopStart( value ) {
41010 this.loopStart = value;
41016 setLoopEnd( value ) {
41018 this.loopEnd = value;
41026 return this.gain.gain.value;
41030 setVolume( value ) {
41032 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
41040 const _position$3 = /*@__PURE__*/ new Vector3();
41041 const _quaternion$4 = /*@__PURE__*/ new Quaternion();
41042 const _scale$2 = /*@__PURE__*/ new Vector3();
41043 const _orientation$1 = /*@__PURE__*/ new Vector3();
41045 class PositionalAudio extends Audio {
41047 constructor( listener ) {
41051 this.panner = this.context.createPanner();
41052 this.panner.panningModel = 'HRTF';
41053 this.panner.connect( this.gain );
41059 return this.panner;
41065 return this.panner.refDistance;
41069 setRefDistance( value ) {
41071 this.panner.refDistance = value;
41077 getRolloffFactor() {
41079 return this.panner.rolloffFactor;
41083 setRolloffFactor( value ) {
41085 this.panner.rolloffFactor = value;
41091 getDistanceModel() {
41093 return this.panner.distanceModel;
41097 setDistanceModel( value ) {
41099 this.panner.distanceModel = value;
41107 return this.panner.maxDistance;
41111 setMaxDistance( value ) {
41113 this.panner.maxDistance = value;
41119 setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
41121 this.panner.coneInnerAngle = coneInnerAngle;
41122 this.panner.coneOuterAngle = coneOuterAngle;
41123 this.panner.coneOuterGain = coneOuterGain;
41129 updateMatrixWorld( force ) {
41131 super.updateMatrixWorld( force );
41133 if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
41135 this.matrixWorld.decompose( _position$3, _quaternion$4, _scale$2 );
41137 _orientation$1.set( 0, 0, 1 ).applyQuaternion( _quaternion$4 );
41139 const panner = this.panner;
41141 if ( panner.positionX ) {
41143 // code path for Chrome and Firefox (see #14393)
41145 const endTime = this.context.currentTime + this.listener.timeDelta;
41147 panner.positionX.linearRampToValueAtTime( _position$3.x, endTime );
41148 panner.positionY.linearRampToValueAtTime( _position$3.y, endTime );
41149 panner.positionZ.linearRampToValueAtTime( _position$3.z, endTime );
41150 panner.orientationX.linearRampToValueAtTime( _orientation$1.x, endTime );
41151 panner.orientationY.linearRampToValueAtTime( _orientation$1.y, endTime );
41152 panner.orientationZ.linearRampToValueAtTime( _orientation$1.z, endTime );
41156 panner.setPosition( _position$3.x, _position$3.y, _position$3.z );
41157 panner.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z );
41165 class AudioAnalyser {
41167 constructor( audio, fftSize = 2048 ) {
41169 this.analyser = audio.context.createAnalyser();
41170 this.analyser.fftSize = fftSize;
41172 this.data = new Uint8Array( this.analyser.frequencyBinCount );
41174 audio.getOutput().connect( this.analyser );
41179 getFrequencyData() {
41181 this.analyser.getByteFrequencyData( this.data );
41187 getAverageFrequency() {
41190 const data = this.getFrequencyData();
41192 for ( let i = 0; i < data.length; i ++ ) {
41194 value += data[ i ];
41198 return value / data.length;
41204 function PropertyMixer( binding, typeName, valueSize ) {
41206 this.binding = binding;
41207 this.valueSize = valueSize;
41210 mixFunctionAdditive,
41213 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
41215 // interpolators can use .buffer as their .result
41216 // the data then goes to 'incoming'
41218 // 'accu0' and 'accu1' are used frame-interleaved for
41219 // the cumulative result and are compared to detect
41222 // 'orig' stores the original state of the property
41224 // 'add' is used for additive cumulative results
41226 // 'work' is optional and is only present for quaternion types. It is used
41227 // to store intermediate quaternion multiplication results
41229 switch ( typeName ) {
41232 mixFunction = this._slerp;
41233 mixFunctionAdditive = this._slerpAdditive;
41234 setIdentity = this._setAdditiveIdentityQuaternion;
41236 this.buffer = new Float64Array( valueSize * 6 );
41237 this._workIndex = 5;
41242 mixFunction = this._select;
41244 // Use the regular mix function and for additive on these types,
41245 // additive is not relevant for non-numeric types
41246 mixFunctionAdditive = this._select;
41248 setIdentity = this._setAdditiveIdentityOther;
41250 this.buffer = new Array( valueSize * 5 );
41254 mixFunction = this._lerp;
41255 mixFunctionAdditive = this._lerpAdditive;
41256 setIdentity = this._setAdditiveIdentityNumeric;
41258 this.buffer = new Float64Array( valueSize * 5 );
41262 this._mixBufferRegion = mixFunction;
41263 this._mixBufferRegionAdditive = mixFunctionAdditive;
41264 this._setIdentity = setIdentity;
41265 this._origIndex = 3;
41266 this._addIndex = 4;
41268 this.cumulativeWeight = 0;
41269 this.cumulativeWeightAdditive = 0;
41272 this.referenceCount = 0;
41276 Object.assign( PropertyMixer.prototype, {
41278 // accumulate data in the 'incoming' region into 'accu<i>'
41279 accumulate: function ( accuIndex, weight ) {
41281 // note: happily accumulating nothing when weight = 0, the caller knows
41282 // the weight and shouldn't have made the call in the first place
41284 const buffer = this.buffer,
41285 stride = this.valueSize,
41286 offset = accuIndex * stride + stride;
41288 let currentWeight = this.cumulativeWeight;
41290 if ( currentWeight === 0 ) {
41292 // accuN := incoming * weight
41294 for ( let i = 0; i !== stride; ++ i ) {
41296 buffer[ offset + i ] = buffer[ i ];
41300 currentWeight = weight;
41304 // accuN := accuN + incoming * weight
41306 currentWeight += weight;
41307 const mix = weight / currentWeight;
41308 this._mixBufferRegion( buffer, offset, 0, mix, stride );
41312 this.cumulativeWeight = currentWeight;
41316 // accumulate data in the 'incoming' region into 'add'
41317 accumulateAdditive: function ( weight ) {
41319 const buffer = this.buffer,
41320 stride = this.valueSize,
41321 offset = stride * this._addIndex;
41323 if ( this.cumulativeWeightAdditive === 0 ) {
41327 this._setIdentity();
41331 // add := add + incoming * weight
41333 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
41334 this.cumulativeWeightAdditive += weight;
41338 // apply the state of 'accu<i>' to the binding when accus differ
41339 apply: function ( accuIndex ) {
41341 const stride = this.valueSize,
41342 buffer = this.buffer,
41343 offset = accuIndex * stride + stride,
41345 weight = this.cumulativeWeight,
41346 weightAdditive = this.cumulativeWeightAdditive,
41348 binding = this.binding;
41350 this.cumulativeWeight = 0;
41351 this.cumulativeWeightAdditive = 0;
41353 if ( weight < 1 ) {
41355 // accuN := accuN + original * ( 1 - cumulativeWeight )
41357 const originalValueOffset = stride * this._origIndex;
41359 this._mixBufferRegion(
41360 buffer, offset, originalValueOffset, 1 - weight, stride );
41364 if ( weightAdditive > 0 ) {
41366 // accuN := accuN + additive accuN
41368 this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
41372 for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
41374 if ( buffer[ i ] !== buffer[ i + stride ] ) {
41376 // value has changed -> update scene graph
41378 binding.setValue( buffer, offset );
41387 // remember the state of the bound property and copy it to both accus
41388 saveOriginalState: function () {
41390 const binding = this.binding;
41392 const buffer = this.buffer,
41393 stride = this.valueSize,
41395 originalValueOffset = stride * this._origIndex;
41397 binding.getValue( buffer, originalValueOffset );
41399 // accu[0..1] := orig -- initially detect changes against the original
41400 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
41402 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
41406 // Add to identity for additive
41407 this._setIdentity();
41409 this.cumulativeWeight = 0;
41410 this.cumulativeWeightAdditive = 0;
41414 // apply the state previously taken via 'saveOriginalState' to the binding
41415 restoreOriginalState: function () {
41417 const originalValueOffset = this.valueSize * 3;
41418 this.binding.setValue( this.buffer, originalValueOffset );
41422 _setAdditiveIdentityNumeric: function () {
41424 const startIndex = this._addIndex * this.valueSize;
41425 const endIndex = startIndex + this.valueSize;
41427 for ( let i = startIndex; i < endIndex; i ++ ) {
41429 this.buffer[ i ] = 0;
41435 _setAdditiveIdentityQuaternion: function () {
41437 this._setAdditiveIdentityNumeric();
41438 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
41442 _setAdditiveIdentityOther: function () {
41444 const startIndex = this._origIndex * this.valueSize;
41445 const targetIndex = this._addIndex * this.valueSize;
41447 for ( let i = 0; i < this.valueSize; i ++ ) {
41449 this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
41458 _select: function ( buffer, dstOffset, srcOffset, t, stride ) {
41462 for ( let i = 0; i !== stride; ++ i ) {
41464 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
41472 _slerp: function ( buffer, dstOffset, srcOffset, t ) {
41474 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
41478 _slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
41480 const workOffset = this._workIndex * stride;
41482 // Store result in intermediate buffer offset
41483 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
41485 // Slerp to the intermediate result
41486 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
41490 _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
41494 for ( let i = 0; i !== stride; ++ i ) {
41496 const j = dstOffset + i;
41498 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
41504 _lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
41506 for ( let i = 0; i !== stride; ++ i ) {
41508 const j = dstOffset + i;
41510 buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
41518 // Characters [].:/ are reserved for track binding syntax.
41519 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
41520 const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
41522 // Attempts to allow node names from any language. ES5's `\w` regexp matches
41523 // only latin characters, and the unicode \p{L} is not yet supported. So
41524 // instead, we exclude reserved characters and match everything else.
41525 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
41526 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
41528 // Parent directories, delimited by '/' or ':'. Currently unused, but must
41529 // be matched to parse the rest of the track name.
41530 const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
41532 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
41533 const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
41535 // Object on target node, and accessor. May not contain reserved
41536 // characters. Accessor may contain any character except closing bracket.
41537 const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
41539 // Property and accessor. May not contain reserved characters. Accessor may
41540 // contain any non-bracket characters.
41541 const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
41543 const _trackRe = new RegExp( ''
41552 const _supportedObjectNames = [ 'material', 'materials', 'bones' ];
41554 function Composite( targetGroup, path, optionalParsedPath ) {
41556 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
41558 this._targetGroup = targetGroup;
41559 this._bindings = targetGroup.subscribe_( path, parsedPath );
41563 Object.assign( Composite.prototype, {
41565 getValue: function ( array, offset ) {
41567 this.bind(); // bind all binding
41569 const firstValidIndex = this._targetGroup.nCachedObjects_,
41570 binding = this._bindings[ firstValidIndex ];
41572 // and only call .getValue on the first
41573 if ( binding !== undefined ) binding.getValue( array, offset );
41577 setValue: function ( array, offset ) {
41579 const bindings = this._bindings;
41581 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41583 bindings[ i ].setValue( array, offset );
41589 bind: function () {
41591 const bindings = this._bindings;
41593 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41595 bindings[ i ].bind();
41601 unbind: function () {
41603 const bindings = this._bindings;
41605 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41607 bindings[ i ].unbind();
41616 function PropertyBinding( rootNode, path, parsedPath ) {
41619 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
41621 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
41623 this.rootNode = rootNode;
41627 Object.assign( PropertyBinding, {
41629 Composite: Composite,
41631 create: function ( root, path, parsedPath ) {
41633 if ( ! ( root && root.isAnimationObjectGroup ) ) {
41635 return new PropertyBinding( root, path, parsedPath );
41639 return new PropertyBinding.Composite( root, path, parsedPath );
41646 * Replaces spaces with underscores and removes unsupported characters from
41647 * node names, to ensure compatibility with parseTrackName().
41649 * @param {string} name Node name to be sanitized.
41652 sanitizeNodeName: function ( name ) {
41654 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
41658 parseTrackName: function ( trackName ) {
41660 const matches = _trackRe.exec( trackName );
41664 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
41669 // directoryName: matches[ 1 ], // (tschw) currently unused
41670 nodeName: matches[ 2 ],
41671 objectName: matches[ 3 ],
41672 objectIndex: matches[ 4 ],
41673 propertyName: matches[ 5 ], // required
41674 propertyIndex: matches[ 6 ]
41677 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
41679 if ( lastDot !== undefined && lastDot !== - 1 ) {
41681 const objectName = results.nodeName.substring( lastDot + 1 );
41683 // Object names must be checked against an allowlist. Otherwise, there
41684 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
41685 // 'bar' could be the objectName, or part of a nodeName (which can
41686 // include '.' characters).
41687 if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
41689 results.nodeName = results.nodeName.substring( 0, lastDot );
41690 results.objectName = objectName;
41696 if ( results.propertyName === null || results.propertyName.length === 0 ) {
41698 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
41706 findNode: function ( root, nodeName ) {
41708 if ( ! nodeName || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
41714 // search into skeleton bones.
41715 if ( root.skeleton ) {
41717 const bone = root.skeleton.getBoneByName( nodeName );
41719 if ( bone !== undefined ) {
41727 // search into node subtree.
41728 if ( root.children ) {
41730 const searchNodeSubtree = function ( children ) {
41732 for ( let i = 0; i < children.length; i ++ ) {
41734 const childNode = children[ i ];
41736 if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
41742 const result = searchNodeSubtree( childNode.children );
41744 if ( result ) return result;
41752 const subTreeNode = searchNodeSubtree( root.children );
41754 if ( subTreeNode ) {
41756 return subTreeNode;
41768 Object.assign( PropertyBinding.prototype, { // prototype, continued
41770 // these are used to "bind" a nonexistent property
41771 _getValue_unavailable: function () {},
41772 _setValue_unavailable: function () {},
41784 MatrixWorldNeedsUpdate: 2
41787 GetterByBindingType: [
41789 function getValue_direct( buffer, offset ) {
41791 buffer[ offset ] = this.node[ this.propertyName ];
41795 function getValue_array( buffer, offset ) {
41797 const source = this.resolvedProperty;
41799 for ( let i = 0, n = source.length; i !== n; ++ i ) {
41801 buffer[ offset ++ ] = source[ i ];
41807 function getValue_arrayElement( buffer, offset ) {
41809 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
41813 function getValue_toArray( buffer, offset ) {
41815 this.resolvedProperty.toArray( buffer, offset );
41821 SetterByBindingTypeAndVersioning: [
41826 function setValue_direct( buffer, offset ) {
41828 this.targetObject[ this.propertyName ] = buffer[ offset ];
41832 function setValue_direct_setNeedsUpdate( buffer, offset ) {
41834 this.targetObject[ this.propertyName ] = buffer[ offset ];
41835 this.targetObject.needsUpdate = true;
41839 function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
41841 this.targetObject[ this.propertyName ] = buffer[ offset ];
41842 this.targetObject.matrixWorldNeedsUpdate = true;
41850 function setValue_array( buffer, offset ) {
41852 const dest = this.resolvedProperty;
41854 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41856 dest[ i ] = buffer[ offset ++ ];
41862 function setValue_array_setNeedsUpdate( buffer, offset ) {
41864 const dest = this.resolvedProperty;
41866 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41868 dest[ i ] = buffer[ offset ++ ];
41872 this.targetObject.needsUpdate = true;
41876 function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
41878 const dest = this.resolvedProperty;
41880 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41882 dest[ i ] = buffer[ offset ++ ];
41886 this.targetObject.matrixWorldNeedsUpdate = true;
41894 function setValue_arrayElement( buffer, offset ) {
41896 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41900 function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
41902 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41903 this.targetObject.needsUpdate = true;
41907 function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
41909 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41910 this.targetObject.matrixWorldNeedsUpdate = true;
41918 function setValue_fromArray( buffer, offset ) {
41920 this.resolvedProperty.fromArray( buffer, offset );
41924 function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
41926 this.resolvedProperty.fromArray( buffer, offset );
41927 this.targetObject.needsUpdate = true;
41931 function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
41933 this.resolvedProperty.fromArray( buffer, offset );
41934 this.targetObject.matrixWorldNeedsUpdate = true;
41942 getValue: function getValue_unbound( targetArray, offset ) {
41945 this.getValue( targetArray, offset );
41947 // Note: This class uses a State pattern on a per-method basis:
41948 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
41949 // prototype version of these methods with one that represents
41950 // the bound state. When the property is not found, the methods
41955 setValue: function getValue_unbound( sourceArray, offset ) {
41958 this.setValue( sourceArray, offset );
41962 // create getter / setter pair for a property in the scene graph
41963 bind: function () {
41965 let targetObject = this.node;
41966 const parsedPath = this.parsedPath;
41968 const objectName = parsedPath.objectName;
41969 const propertyName = parsedPath.propertyName;
41970 let propertyIndex = parsedPath.propertyIndex;
41972 if ( ! targetObject ) {
41974 targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
41976 this.node = targetObject;
41980 // set fail state so we can just 'return' on error
41981 this.getValue = this._getValue_unavailable;
41982 this.setValue = this._setValue_unavailable;
41984 // ensure there is a value node
41985 if ( ! targetObject ) {
41987 console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
41992 if ( objectName ) {
41994 let objectIndex = parsedPath.objectIndex;
41996 // special cases were we need to reach deeper into the hierarchy to get the face materials....
41997 switch ( objectName ) {
42001 if ( ! targetObject.material ) {
42003 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
42008 if ( ! targetObject.material.materials ) {
42010 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
42015 targetObject = targetObject.material.materials;
42021 if ( ! targetObject.skeleton ) {
42023 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
42028 // potential future optimization: skip this if propertyIndex is already an integer
42029 // and convert the integer string to a true integer.
42031 targetObject = targetObject.skeleton.bones;
42033 // support resolving morphTarget names into indices.
42034 for ( let i = 0; i < targetObject.length; i ++ ) {
42036 if ( targetObject[ i ].name === objectIndex ) {
42049 if ( targetObject[ objectName ] === undefined ) {
42051 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
42056 targetObject = targetObject[ objectName ];
42061 if ( objectIndex !== undefined ) {
42063 if ( targetObject[ objectIndex ] === undefined ) {
42065 console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
42070 targetObject = targetObject[ objectIndex ];
42076 // resolve property
42077 const nodeProperty = targetObject[ propertyName ];
42079 if ( nodeProperty === undefined ) {
42081 const nodeName = parsedPath.nodeName;
42083 console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
42084 '.' + propertyName + ' but it wasn\'t found.', targetObject );
42089 // determine versioning scheme
42090 let versioning = this.Versioning.None;
42092 this.targetObject = targetObject;
42094 if ( targetObject.needsUpdate !== undefined ) { // material
42096 versioning = this.Versioning.NeedsUpdate;
42098 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
42100 versioning = this.Versioning.MatrixWorldNeedsUpdate;
42104 // determine how the property gets bound
42105 let bindingType = this.BindingType.Direct;
42107 if ( propertyIndex !== undefined ) {
42109 // access a sub element of the property array (only primitives are supported right now)
42111 if ( propertyName === 'morphTargetInfluences' ) {
42113 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
42115 // support resolving morphTarget names into indices.
42116 if ( ! targetObject.geometry ) {
42118 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
42123 if ( targetObject.geometry.isBufferGeometry ) {
42125 if ( ! targetObject.geometry.morphAttributes ) {
42127 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
42132 if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
42134 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
42141 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this );
42148 bindingType = this.BindingType.ArrayElement;
42150 this.resolvedProperty = nodeProperty;
42151 this.propertyIndex = propertyIndex;
42153 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
42155 // must use copy for Object3D.Euler/Quaternion
42157 bindingType = this.BindingType.HasFromToArray;
42159 this.resolvedProperty = nodeProperty;
42161 } else if ( Array.isArray( nodeProperty ) ) {
42163 bindingType = this.BindingType.EntireArray;
42165 this.resolvedProperty = nodeProperty;
42169 this.propertyName = propertyName;
42173 // select getter / setter
42174 this.getValue = this.GetterByBindingType[ bindingType ];
42175 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
42179 unbind: function () {
42183 // back to the prototype version of getValue / setValue
42184 // note: avoiding to mutate the shape of 'this' via 'delete'
42185 this.getValue = this._getValue_unbound;
42186 this.setValue = this._setValue_unbound;
42192 // DECLARE ALIAS AFTER assign prototype
42193 Object.assign( PropertyBinding.prototype, {
42195 // initial state of these methods that calls 'bind'
42196 _getValue_unbound: PropertyBinding.prototype.getValue,
42197 _setValue_unbound: PropertyBinding.prototype.setValue,
42203 * A group of objects that receives a shared animation state.
42207 * - Add objects you would otherwise pass as 'root' to the
42208 * constructor or the .clipAction method of AnimationMixer.
42210 * - Instead pass this object as 'root'.
42212 * - You can also add and remove objects later when the mixer
42217 * Objects of this class appear as one object to the mixer,
42218 * so cache control of the individual objects must be done
42223 * - The animated properties must be compatible among the
42224 * all objects in the group.
42226 * - A single property can either be controlled through a
42227 * target group or directly, but not both.
42230 function AnimationObjectGroup() {
42232 this.uuid = MathUtils.generateUUID();
42234 // cached objects followed by the active ones
42235 this._objects = Array.prototype.slice.call( arguments );
42237 this.nCachedObjects_ = 0; // threshold
42238 // note: read by PropertyBinding.Composite
42240 const indices = {};
42241 this._indicesByUUID = indices; // for bookkeeping
42243 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
42245 indices[ arguments[ i ].uuid ] = i;
42249 this._paths = []; // inside: string
42250 this._parsedPaths = []; // inside: { we don't care, here }
42251 this._bindings = []; // inside: Array< PropertyBinding >
42252 this._bindingsIndicesByPath = {}; // inside: indices in these arrays
42254 const scope = this;
42261 return scope._objects.length;
42266 return this.total - scope.nCachedObjects_;
42270 get bindingsPerObject() {
42272 return scope._bindings.length;
42280 Object.assign( AnimationObjectGroup.prototype, {
42282 isAnimationObjectGroup: true,
42286 const objects = this._objects,
42287 indicesByUUID = this._indicesByUUID,
42288 paths = this._paths,
42289 parsedPaths = this._parsedPaths,
42290 bindings = this._bindings,
42291 nBindings = bindings.length;
42293 let knownObject = undefined,
42294 nObjects = objects.length,
42295 nCachedObjects = this.nCachedObjects_;
42297 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
42299 const object = arguments[ i ],
42300 uuid = object.uuid;
42301 let index = indicesByUUID[ uuid ];
42303 if ( index === undefined ) {
42305 // unknown object -> add it to the ACTIVE region
42307 index = nObjects ++;
42308 indicesByUUID[ uuid ] = index;
42309 objects.push( object );
42311 // accounting is done, now do the same for all bindings
42313 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
42315 bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
42319 } else if ( index < nCachedObjects ) {
42321 knownObject = objects[ index ];
42323 // move existing object to the ACTIVE region
42325 const firstActiveIndex = -- nCachedObjects,
42326 lastCachedObject = objects[ firstActiveIndex ];
42328 indicesByUUID[ lastCachedObject.uuid ] = index;
42329 objects[ index ] = lastCachedObject;
42331 indicesByUUID[ uuid ] = firstActiveIndex;
42332 objects[ firstActiveIndex ] = object;
42334 // accounting is done, now do the same for all bindings
42336 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
42338 const bindingsForPath = bindings[ j ],
42339 lastCached = bindingsForPath[ firstActiveIndex ];
42341 let binding = bindingsForPath[ index ];
42343 bindingsForPath[ index ] = lastCached;
42345 if ( binding === undefined ) {
42347 // since we do not bother to create new bindings
42348 // for objects that are cached, the binding may
42349 // or may not exist
42351 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
42355 bindingsForPath[ firstActiveIndex ] = binding;
42359 } else if ( objects[ index ] !== knownObject ) {
42361 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
42362 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
42364 } // else the object is already where we want it to be
42368 this.nCachedObjects_ = nCachedObjects;
42372 remove: function () {
42374 const objects = this._objects,
42375 indicesByUUID = this._indicesByUUID,
42376 bindings = this._bindings,
42377 nBindings = bindings.length;
42379 let nCachedObjects = this.nCachedObjects_;
42381 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
42383 const object = arguments[ i ],
42384 uuid = object.uuid,
42385 index = indicesByUUID[ uuid ];
42387 if ( index !== undefined && index >= nCachedObjects ) {
42389 // move existing object into the CACHED region
42391 const lastCachedIndex = nCachedObjects ++,
42392 firstActiveObject = objects[ lastCachedIndex ];
42394 indicesByUUID[ firstActiveObject.uuid ] = index;
42395 objects[ index ] = firstActiveObject;
42397 indicesByUUID[ uuid ] = lastCachedIndex;
42398 objects[ lastCachedIndex ] = object;
42400 // accounting is done, now do the same for all bindings
42402 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
42404 const bindingsForPath = bindings[ j ],
42405 firstActive = bindingsForPath[ lastCachedIndex ],
42406 binding = bindingsForPath[ index ];
42408 bindingsForPath[ index ] = firstActive;
42409 bindingsForPath[ lastCachedIndex ] = binding;
42417 this.nCachedObjects_ = nCachedObjects;
42422 uncache: function () {
42424 const objects = this._objects,
42425 indicesByUUID = this._indicesByUUID,
42426 bindings = this._bindings,
42427 nBindings = bindings.length;
42429 let nCachedObjects = this.nCachedObjects_,
42430 nObjects = objects.length;
42432 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
42434 const object = arguments[ i ],
42435 uuid = object.uuid,
42436 index = indicesByUUID[ uuid ];
42438 if ( index !== undefined ) {
42440 delete indicesByUUID[ uuid ];
42442 if ( index < nCachedObjects ) {
42444 // object is cached, shrink the CACHED region
42446 const firstActiveIndex = -- nCachedObjects,
42447 lastCachedObject = objects[ firstActiveIndex ],
42448 lastIndex = -- nObjects,
42449 lastObject = objects[ lastIndex ];
42451 // last cached object takes this object's place
42452 indicesByUUID[ lastCachedObject.uuid ] = index;
42453 objects[ index ] = lastCachedObject;
42455 // last object goes to the activated slot and pop
42456 indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
42457 objects[ firstActiveIndex ] = lastObject;
42460 // accounting is done, now do the same for all bindings
42462 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
42464 const bindingsForPath = bindings[ j ],
42465 lastCached = bindingsForPath[ firstActiveIndex ],
42466 last = bindingsForPath[ lastIndex ];
42468 bindingsForPath[ index ] = lastCached;
42469 bindingsForPath[ firstActiveIndex ] = last;
42470 bindingsForPath.pop();
42476 // object is active, just swap with the last and pop
42478 const lastIndex = -- nObjects,
42479 lastObject = objects[ lastIndex ];
42481 if ( lastIndex > 0 ) {
42483 indicesByUUID[ lastObject.uuid ] = index;
42487 objects[ index ] = lastObject;
42490 // accounting is done, now do the same for all bindings
42492 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
42494 const bindingsForPath = bindings[ j ];
42496 bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
42497 bindingsForPath.pop();
42501 } // cached or active
42503 } // if object is known
42507 this.nCachedObjects_ = nCachedObjects;
42511 // Internal interface used by befriended PropertyBinding.Composite:
42513 subscribe_: function ( path, parsedPath ) {
42515 // returns an array of bindings for the given path that is changed
42516 // according to the contained objects in the group
42518 const indicesByPath = this._bindingsIndicesByPath;
42519 let index = indicesByPath[ path ];
42520 const bindings = this._bindings;
42522 if ( index !== undefined ) return bindings[ index ];
42524 const paths = this._paths,
42525 parsedPaths = this._parsedPaths,
42526 objects = this._objects,
42527 nObjects = objects.length,
42528 nCachedObjects = this.nCachedObjects_,
42529 bindingsForPath = new Array( nObjects );
42531 index = bindings.length;
42533 indicesByPath[ path ] = index;
42535 paths.push( path );
42536 parsedPaths.push( parsedPath );
42537 bindings.push( bindingsForPath );
42539 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
42541 const object = objects[ i ];
42542 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
42546 return bindingsForPath;
42550 unsubscribe_: function ( path ) {
42552 // tells the group to forget about a property path and no longer
42553 // update the array previously obtained with 'subscribe_'
42555 const indicesByPath = this._bindingsIndicesByPath,
42556 index = indicesByPath[ path ];
42558 if ( index !== undefined ) {
42560 const paths = this._paths,
42561 parsedPaths = this._parsedPaths,
42562 bindings = this._bindings,
42563 lastBindingsIndex = bindings.length - 1,
42564 lastBindings = bindings[ lastBindingsIndex ],
42565 lastBindingsPath = path[ lastBindingsIndex ];
42567 indicesByPath[ lastBindingsPath ] = index;
42569 bindings[ index ] = lastBindings;
42572 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
42575 paths[ index ] = paths[ lastBindingsIndex ];
42584 class AnimationAction {
42586 constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
42588 this._mixer = mixer;
42590 this._localRoot = localRoot;
42591 this.blendMode = blendMode;
42593 const tracks = clip.tracks,
42594 nTracks = tracks.length,
42595 interpolants = new Array( nTracks );
42597 const interpolantSettings = {
42598 endingStart: ZeroCurvatureEnding,
42599 endingEnd: ZeroCurvatureEnding
42602 for ( let i = 0; i !== nTracks; ++ i ) {
42604 const interpolant = tracks[ i ].createInterpolant( null );
42605 interpolants[ i ] = interpolant;
42606 interpolant.settings = interpolantSettings;
42610 this._interpolantSettings = interpolantSettings;
42612 this._interpolants = interpolants; // bound by the mixer
42614 // inside: PropertyMixer (managed by the mixer)
42615 this._propertyBindings = new Array( nTracks );
42617 this._cacheIndex = null; // for the memory manager
42618 this._byClipCacheIndex = null; // for the memory manager
42620 this._timeScaleInterpolant = null;
42621 this._weightInterpolant = null;
42623 this.loop = LoopRepeat;
42624 this._loopCount = - 1;
42626 // global mixer time when the action is to be started
42627 // it's set back to 'null' upon start of the action
42628 this._startTime = null;
42630 // scaled local time of the action
42631 // gets clamped or wrapped to 0..clip.duration according to loop
42634 this.timeScale = 1;
42635 this._effectiveTimeScale = 1;
42638 this._effectiveWeight = 1;
42640 this.repetitions = Infinity; // no. of repetitions when looping
42642 this.paused = false; // true -> zero effective time scale
42643 this.enabled = true; // false -> zero effective weight
42645 this.clampWhenFinished = false;// keep feeding the last frame?
42647 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
42648 this.zeroSlopeAtEnd = true;// clips for start, loop and end
42652 // State & Scheduling
42656 this._mixer._activateAction( this );
42664 this._mixer._deactivateAction( this );
42666 return this.reset();
42672 this.paused = false;
42673 this.enabled = true;
42675 this.time = 0; // restart clip
42676 this._loopCount = - 1;// forget previous loops
42677 this._startTime = null;// forget scheduling
42679 return this.stopFading().stopWarping();
42685 return this.enabled && ! this.paused && this.timeScale !== 0 &&
42686 this._startTime === null && this._mixer._isActiveAction( this );
42690 // return true when play has been called
42693 return this._mixer._isActiveAction( this );
42699 this._startTime = time;
42705 setLoop( mode, repetitions ) {
42708 this.repetitions = repetitions;
42716 // set the weight stopping any scheduled fading
42717 // although .enabled = false yields an effective weight of zero, this
42718 // method does *not* change .enabled, because it would be confusing
42719 setEffectiveWeight( weight ) {
42721 this.weight = weight;
42723 // note: same logic as when updated at runtime
42724 this._effectiveWeight = this.enabled ? weight : 0;
42726 return this.stopFading();
42730 // return the weight considering fading and .enabled
42731 getEffectiveWeight() {
42733 return this._effectiveWeight;
42737 fadeIn( duration ) {
42739 return this._scheduleFading( duration, 0, 1 );
42743 fadeOut( duration ) {
42745 return this._scheduleFading( duration, 1, 0 );
42749 crossFadeFrom( fadeOutAction, duration, warp ) {
42751 fadeOutAction.fadeOut( duration );
42752 this.fadeIn( duration );
42756 const fadeInDuration = this._clip.duration,
42757 fadeOutDuration = fadeOutAction._clip.duration,
42759 startEndRatio = fadeOutDuration / fadeInDuration,
42760 endStartRatio = fadeInDuration / fadeOutDuration;
42762 fadeOutAction.warp( 1.0, startEndRatio, duration );
42763 this.warp( endStartRatio, 1.0, duration );
42771 crossFadeTo( fadeInAction, duration, warp ) {
42773 return fadeInAction.crossFadeFrom( this, duration, warp );
42779 const weightInterpolant = this._weightInterpolant;
42781 if ( weightInterpolant !== null ) {
42783 this._weightInterpolant = null;
42784 this._mixer._takeBackControlInterpolant( weightInterpolant );
42792 // Time Scale Control
42794 // set the time scale stopping any scheduled warping
42795 // although .paused = true yields an effective time scale of zero, this
42796 // method does *not* change .paused, because it would be confusing
42797 setEffectiveTimeScale( timeScale ) {
42799 this.timeScale = timeScale;
42800 this._effectiveTimeScale = this.paused ? 0 : timeScale;
42802 return this.stopWarping();
42806 // return the time scale considering warping and .paused
42807 getEffectiveTimeScale() {
42809 return this._effectiveTimeScale;
42813 setDuration( duration ) {
42815 this.timeScale = this._clip.duration / duration;
42817 return this.stopWarping();
42821 syncWith( action ) {
42823 this.time = action.time;
42824 this.timeScale = action.timeScale;
42826 return this.stopWarping();
42832 return this.warp( this._effectiveTimeScale, 0, duration );
42836 warp( startTimeScale, endTimeScale, duration ) {
42838 const mixer = this._mixer,
42840 timeScale = this.timeScale;
42842 let interpolant = this._timeScaleInterpolant;
42844 if ( interpolant === null ) {
42846 interpolant = mixer._lendControlInterpolant();
42847 this._timeScaleInterpolant = interpolant;
42851 const times = interpolant.parameterPositions,
42852 values = interpolant.sampleValues;
42855 times[ 1 ] = now + duration;
42857 values[ 0 ] = startTimeScale / timeScale;
42858 values[ 1 ] = endTimeScale / timeScale;
42866 const timeScaleInterpolant = this._timeScaleInterpolant;
42868 if ( timeScaleInterpolant !== null ) {
42870 this._timeScaleInterpolant = null;
42871 this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
42879 // Object Accessors
42883 return this._mixer;
42895 return this._localRoot || this._mixer._root;
42901 _update( time, deltaTime, timeDirection, accuIndex ) {
42903 // called by the mixer
42905 if ( ! this.enabled ) {
42907 // call ._updateWeight() to update ._effectiveWeight
42909 this._updateWeight( time );
42914 const startTime = this._startTime;
42916 if ( startTime !== null ) {
42918 // check for scheduled start of action
42920 const timeRunning = ( time - startTime ) * timeDirection;
42921 if ( timeRunning < 0 || timeDirection === 0 ) {
42923 return; // yet to come / don't decide when delta = 0
42929 this._startTime = null; // unschedule
42930 deltaTime = timeDirection * timeRunning;
42934 // apply time scale and advance time
42936 deltaTime *= this._updateTimeScale( time );
42937 const clipTime = this._updateTime( deltaTime );
42939 // note: _updateTime may disable the action resulting in
42940 // an effective weight of 0
42942 const weight = this._updateWeight( time );
42944 if ( weight > 0 ) {
42946 const interpolants = this._interpolants;
42947 const propertyMixers = this._propertyBindings;
42949 switch ( this.blendMode ) {
42951 case AdditiveAnimationBlendMode:
42953 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
42955 interpolants[ j ].evaluate( clipTime );
42956 propertyMixers[ j ].accumulateAdditive( weight );
42962 case NormalAnimationBlendMode:
42965 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
42967 interpolants[ j ].evaluate( clipTime );
42968 propertyMixers[ j ].accumulate( accuIndex, weight );
42978 _updateWeight( time ) {
42982 if ( this.enabled ) {
42984 weight = this.weight;
42985 const interpolant = this._weightInterpolant;
42987 if ( interpolant !== null ) {
42989 const interpolantValue = interpolant.evaluate( time )[ 0 ];
42991 weight *= interpolantValue;
42993 if ( time > interpolant.parameterPositions[ 1 ] ) {
42997 if ( interpolantValue === 0 ) {
42999 // faded out, disable
43000 this.enabled = false;
43010 this._effectiveWeight = weight;
43015 _updateTimeScale( time ) {
43019 if ( ! this.paused ) {
43021 timeScale = this.timeScale;
43023 const interpolant = this._timeScaleInterpolant;
43025 if ( interpolant !== null ) {
43027 const interpolantValue = interpolant.evaluate( time )[ 0 ];
43029 timeScale *= interpolantValue;
43031 if ( time > interpolant.parameterPositions[ 1 ] ) {
43033 this.stopWarping();
43035 if ( timeScale === 0 ) {
43037 // motion has halted, pause
43038 this.paused = true;
43042 // warp done - apply final time scale
43043 this.timeScale = timeScale;
43053 this._effectiveTimeScale = timeScale;
43058 _updateTime( deltaTime ) {
43060 const duration = this._clip.duration;
43061 const loop = this.loop;
43063 let time = this.time + deltaTime;
43064 let loopCount = this._loopCount;
43066 const pingPong = ( loop === LoopPingPong );
43068 if ( deltaTime === 0 ) {
43070 if ( loopCount === - 1 ) return time;
43072 return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
43076 if ( loop === LoopOnce ) {
43078 if ( loopCount === - 1 ) {
43082 this._loopCount = 0;
43083 this._setEndings( true, true, false );
43089 if ( time >= duration ) {
43093 } else if ( time < 0 ) {
43105 if ( this.clampWhenFinished ) this.paused = true;
43106 else this.enabled = false;
43110 this._mixer.dispatchEvent( {
43111 type: 'finished', action: this,
43112 direction: deltaTime < 0 ? - 1 : 1
43117 } else { // repetitive Repeat or PingPong
43119 if ( loopCount === - 1 ) {
43123 if ( deltaTime >= 0 ) {
43127 this._setEndings( true, this.repetitions === 0, pingPong );
43131 // when looping in reverse direction, the initial
43132 // transition through zero counts as a repetition,
43133 // so leave loopCount at -1
43135 this._setEndings( this.repetitions === 0, true, pingPong );
43141 if ( time >= duration || time < 0 ) {
43145 const loopDelta = Math.floor( time / duration ); // signed
43146 time -= duration * loopDelta;
43148 loopCount += Math.abs( loopDelta );
43150 const pending = this.repetitions - loopCount;
43152 if ( pending <= 0 ) {
43154 // have to stop (switch state, clamp time, fire event)
43156 if ( this.clampWhenFinished ) this.paused = true;
43157 else this.enabled = false;
43159 time = deltaTime > 0 ? duration : 0;
43163 this._mixer.dispatchEvent( {
43164 type: 'finished', action: this,
43165 direction: deltaTime > 0 ? 1 : - 1
43172 if ( pending === 1 ) {
43174 // entering the last round
43176 const atStart = deltaTime < 0;
43177 this._setEndings( atStart, ! atStart, pingPong );
43181 this._setEndings( false, false, pingPong );
43185 this._loopCount = loopCount;
43189 this._mixer.dispatchEvent( {
43190 type: 'loop', action: this, loopDelta: loopDelta
43201 if ( pingPong && ( loopCount & 1 ) === 1 ) {
43203 // invert time for the "pong round"
43205 return duration - time;
43215 _setEndings( atStart, atEnd, pingPong ) {
43217 const settings = this._interpolantSettings;
43221 settings.endingStart = ZeroSlopeEnding;
43222 settings.endingEnd = ZeroSlopeEnding;
43226 // assuming for LoopOnce atStart == atEnd == true
43230 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
43234 settings.endingStart = WrapAroundEnding;
43240 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
43244 settings.endingEnd = WrapAroundEnding;
43252 _scheduleFading( duration, weightNow, weightThen ) {
43254 const mixer = this._mixer, now = mixer.time;
43255 let interpolant = this._weightInterpolant;
43257 if ( interpolant === null ) {
43259 interpolant = mixer._lendControlInterpolant();
43260 this._weightInterpolant = interpolant;
43264 const times = interpolant.parameterPositions,
43265 values = interpolant.sampleValues;
43268 values[ 0 ] = weightNow;
43269 times[ 1 ] = now + duration;
43270 values[ 1 ] = weightThen;
43278 function AnimationMixer( root ) {
43281 this._initMemoryManager();
43282 this._accuIndex = 0;
43286 this.timeScale = 1.0;
43290 AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
43292 constructor: AnimationMixer,
43294 _bindAction: function ( action, prototypeAction ) {
43296 const root = action._localRoot || this._root,
43297 tracks = action._clip.tracks,
43298 nTracks = tracks.length,
43299 bindings = action._propertyBindings,
43300 interpolants = action._interpolants,
43301 rootUuid = root.uuid,
43302 bindingsByRoot = this._bindingsByRootAndName;
43304 let bindingsByName = bindingsByRoot[ rootUuid ];
43306 if ( bindingsByName === undefined ) {
43308 bindingsByName = {};
43309 bindingsByRoot[ rootUuid ] = bindingsByName;
43313 for ( let i = 0; i !== nTracks; ++ i ) {
43315 const track = tracks[ i ],
43316 trackName = track.name;
43318 let binding = bindingsByName[ trackName ];
43320 if ( binding !== undefined ) {
43322 bindings[ i ] = binding;
43326 binding = bindings[ i ];
43328 if ( binding !== undefined ) {
43330 // existing binding, make sure the cache knows
43332 if ( binding._cacheIndex === null ) {
43334 ++ binding.referenceCount;
43335 this._addInactiveBinding( binding, rootUuid, trackName );
43343 const path = prototypeAction && prototypeAction.
43344 _propertyBindings[ i ].binding.parsedPath;
43346 binding = new PropertyMixer(
43347 PropertyBinding.create( root, trackName, path ),
43348 track.ValueTypeName, track.getValueSize() );
43350 ++ binding.referenceCount;
43351 this._addInactiveBinding( binding, rootUuid, trackName );
43353 bindings[ i ] = binding;
43357 interpolants[ i ].resultBuffer = binding.buffer;
43363 _activateAction: function ( action ) {
43365 if ( ! this._isActiveAction( action ) ) {
43367 if ( action._cacheIndex === null ) {
43369 // this action has been forgotten by the cache, but the user
43370 // appears to be still using it -> rebind
43372 const rootUuid = ( action._localRoot || this._root ).uuid,
43373 clipUuid = action._clip.uuid,
43374 actionsForClip = this._actionsByClip[ clipUuid ];
43376 this._bindAction( action,
43377 actionsForClip && actionsForClip.knownActions[ 0 ] );
43379 this._addInactiveAction( action, clipUuid, rootUuid );
43383 const bindings = action._propertyBindings;
43385 // increment reference counts / sort out state
43386 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
43388 const binding = bindings[ i ];
43390 if ( binding.useCount ++ === 0 ) {
43392 this._lendBinding( binding );
43393 binding.saveOriginalState();
43399 this._lendAction( action );
43405 _deactivateAction: function ( action ) {
43407 if ( this._isActiveAction( action ) ) {
43409 const bindings = action._propertyBindings;
43411 // decrement reference counts / sort out state
43412 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
43414 const binding = bindings[ i ];
43416 if ( -- binding.useCount === 0 ) {
43418 binding.restoreOriginalState();
43419 this._takeBackBinding( binding );
43425 this._takeBackAction( action );
43433 _initMemoryManager: function () {
43435 this._actions = []; // 'nActiveActions' followed by inactive ones
43436 this._nActiveActions = 0;
43438 this._actionsByClip = {};
43441 // knownActions: Array< AnimationAction > - used as prototypes
43442 // actionByRoot: AnimationAction - lookup
43446 this._bindings = []; // 'nActiveBindings' followed by inactive ones
43447 this._nActiveBindings = 0;
43449 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
43452 this._controlInterpolants = []; // same game as above
43453 this._nActiveControlInterpolants = 0;
43455 const scope = this;
43462 return scope._actions.length;
43467 return scope._nActiveActions;
43474 return scope._bindings.length;
43479 return scope._nActiveBindings;
43483 controlInterpolants: {
43486 return scope._controlInterpolants.length;
43491 return scope._nActiveControlInterpolants;
43500 // Memory management for AnimationAction objects
43502 _isActiveAction: function ( action ) {
43504 const index = action._cacheIndex;
43505 return index !== null && index < this._nActiveActions;
43509 _addInactiveAction: function ( action, clipUuid, rootUuid ) {
43511 const actions = this._actions,
43512 actionsByClip = this._actionsByClip;
43514 let actionsForClip = actionsByClip[ clipUuid ];
43516 if ( actionsForClip === undefined ) {
43520 knownActions: [ action ],
43525 action._byClipCacheIndex = 0;
43527 actionsByClip[ clipUuid ] = actionsForClip;
43531 const knownActions = actionsForClip.knownActions;
43533 action._byClipCacheIndex = knownActions.length;
43534 knownActions.push( action );
43538 action._cacheIndex = actions.length;
43539 actions.push( action );
43541 actionsForClip.actionByRoot[ rootUuid ] = action;
43545 _removeInactiveAction: function ( action ) {
43547 const actions = this._actions,
43548 lastInactiveAction = actions[ actions.length - 1 ],
43549 cacheIndex = action._cacheIndex;
43551 lastInactiveAction._cacheIndex = cacheIndex;
43552 actions[ cacheIndex ] = lastInactiveAction;
43555 action._cacheIndex = null;
43558 const clipUuid = action._clip.uuid,
43559 actionsByClip = this._actionsByClip,
43560 actionsForClip = actionsByClip[ clipUuid ],
43561 knownActionsForClip = actionsForClip.knownActions,
43564 knownActionsForClip[ knownActionsForClip.length - 1 ],
43566 byClipCacheIndex = action._byClipCacheIndex;
43568 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
43569 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
43570 knownActionsForClip.pop();
43572 action._byClipCacheIndex = null;
43575 const actionByRoot = actionsForClip.actionByRoot,
43576 rootUuid = ( action._localRoot || this._root ).uuid;
43578 delete actionByRoot[ rootUuid ];
43580 if ( knownActionsForClip.length === 0 ) {
43582 delete actionsByClip[ clipUuid ];
43586 this._removeInactiveBindingsForAction( action );
43590 _removeInactiveBindingsForAction: function ( action ) {
43592 const bindings = action._propertyBindings;
43594 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
43596 const binding = bindings[ i ];
43598 if ( -- binding.referenceCount === 0 ) {
43600 this._removeInactiveBinding( binding );
43608 _lendAction: function ( action ) {
43610 // [ active actions | inactive actions ]
43611 // [ active actions >| inactive actions ]
43616 const actions = this._actions,
43617 prevIndex = action._cacheIndex,
43619 lastActiveIndex = this._nActiveActions ++,
43621 firstInactiveAction = actions[ lastActiveIndex ];
43623 action._cacheIndex = lastActiveIndex;
43624 actions[ lastActiveIndex ] = action;
43626 firstInactiveAction._cacheIndex = prevIndex;
43627 actions[ prevIndex ] = firstInactiveAction;
43631 _takeBackAction: function ( action ) {
43633 // [ active actions | inactive actions ]
43634 // [ active actions |< inactive actions ]
43639 const actions = this._actions,
43640 prevIndex = action._cacheIndex,
43642 firstInactiveIndex = -- this._nActiveActions,
43644 lastActiveAction = actions[ firstInactiveIndex ];
43646 action._cacheIndex = firstInactiveIndex;
43647 actions[ firstInactiveIndex ] = action;
43649 lastActiveAction._cacheIndex = prevIndex;
43650 actions[ prevIndex ] = lastActiveAction;
43654 // Memory management for PropertyMixer objects
43656 _addInactiveBinding: function ( binding, rootUuid, trackName ) {
43658 const bindingsByRoot = this._bindingsByRootAndName,
43659 bindings = this._bindings;
43661 let bindingByName = bindingsByRoot[ rootUuid ];
43663 if ( bindingByName === undefined ) {
43665 bindingByName = {};
43666 bindingsByRoot[ rootUuid ] = bindingByName;
43670 bindingByName[ trackName ] = binding;
43672 binding._cacheIndex = bindings.length;
43673 bindings.push( binding );
43677 _removeInactiveBinding: function ( binding ) {
43679 const bindings = this._bindings,
43680 propBinding = binding.binding,
43681 rootUuid = propBinding.rootNode.uuid,
43682 trackName = propBinding.path,
43683 bindingsByRoot = this._bindingsByRootAndName,
43684 bindingByName = bindingsByRoot[ rootUuid ],
43686 lastInactiveBinding = bindings[ bindings.length - 1 ],
43687 cacheIndex = binding._cacheIndex;
43689 lastInactiveBinding._cacheIndex = cacheIndex;
43690 bindings[ cacheIndex ] = lastInactiveBinding;
43693 delete bindingByName[ trackName ];
43695 if ( Object.keys( bindingByName ).length === 0 ) {
43697 delete bindingsByRoot[ rootUuid ];
43703 _lendBinding: function ( binding ) {
43705 const bindings = this._bindings,
43706 prevIndex = binding._cacheIndex,
43708 lastActiveIndex = this._nActiveBindings ++,
43710 firstInactiveBinding = bindings[ lastActiveIndex ];
43712 binding._cacheIndex = lastActiveIndex;
43713 bindings[ lastActiveIndex ] = binding;
43715 firstInactiveBinding._cacheIndex = prevIndex;
43716 bindings[ prevIndex ] = firstInactiveBinding;
43720 _takeBackBinding: function ( binding ) {
43722 const bindings = this._bindings,
43723 prevIndex = binding._cacheIndex,
43725 firstInactiveIndex = -- this._nActiveBindings,
43727 lastActiveBinding = bindings[ firstInactiveIndex ];
43729 binding._cacheIndex = firstInactiveIndex;
43730 bindings[ firstInactiveIndex ] = binding;
43732 lastActiveBinding._cacheIndex = prevIndex;
43733 bindings[ prevIndex ] = lastActiveBinding;
43738 // Memory management of Interpolants for weight and time scale
43740 _lendControlInterpolant: function () {
43742 const interpolants = this._controlInterpolants,
43743 lastActiveIndex = this._nActiveControlInterpolants ++;
43745 let interpolant = interpolants[ lastActiveIndex ];
43747 if ( interpolant === undefined ) {
43749 interpolant = new LinearInterpolant(
43750 new Float32Array( 2 ), new Float32Array( 2 ),
43751 1, this._controlInterpolantsResultBuffer );
43753 interpolant.__cacheIndex = lastActiveIndex;
43754 interpolants[ lastActiveIndex ] = interpolant;
43758 return interpolant;
43762 _takeBackControlInterpolant: function ( interpolant ) {
43764 const interpolants = this._controlInterpolants,
43765 prevIndex = interpolant.__cacheIndex,
43767 firstInactiveIndex = -- this._nActiveControlInterpolants,
43769 lastActiveInterpolant = interpolants[ firstInactiveIndex ];
43771 interpolant.__cacheIndex = firstInactiveIndex;
43772 interpolants[ firstInactiveIndex ] = interpolant;
43774 lastActiveInterpolant.__cacheIndex = prevIndex;
43775 interpolants[ prevIndex ] = lastActiveInterpolant;
43779 _controlInterpolantsResultBuffer: new Float32Array( 1 ),
43781 // return an action for a clip optionally using a custom root target
43782 // object (this method allocates a lot of dynamic memory in case a
43783 // previously unknown clip/root combination is specified)
43784 clipAction: function ( clip, optionalRoot, blendMode ) {
43786 const root = optionalRoot || this._root,
43787 rootUuid = root.uuid;
43789 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
43791 const clipUuid = clipObject !== null ? clipObject.uuid : clip;
43793 const actionsForClip = this._actionsByClip[ clipUuid ];
43794 let prototypeAction = null;
43796 if ( blendMode === undefined ) {
43798 if ( clipObject !== null ) {
43800 blendMode = clipObject.blendMode;
43804 blendMode = NormalAnimationBlendMode;
43810 if ( actionsForClip !== undefined ) {
43812 const existingAction = actionsForClip.actionByRoot[ rootUuid ];
43814 if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
43816 return existingAction;
43820 // we know the clip, so we don't have to parse all
43821 // the bindings again but can just copy
43822 prototypeAction = actionsForClip.knownActions[ 0 ];
43824 // also, take the clip from the prototype action
43825 if ( clipObject === null )
43826 clipObject = prototypeAction._clip;
43830 // clip must be known when specified via string
43831 if ( clipObject === null ) return null;
43833 // allocate all resources required to run it
43834 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
43836 this._bindAction( newAction, prototypeAction );
43838 // and make the action known to the memory manager
43839 this._addInactiveAction( newAction, clipUuid, rootUuid );
43845 // get an existing action
43846 existingAction: function ( clip, optionalRoot ) {
43848 const root = optionalRoot || this._root,
43849 rootUuid = root.uuid,
43851 clipObject = typeof clip === 'string' ?
43852 AnimationClip.findByName( root, clip ) : clip,
43854 clipUuid = clipObject ? clipObject.uuid : clip,
43856 actionsForClip = this._actionsByClip[ clipUuid ];
43858 if ( actionsForClip !== undefined ) {
43860 return actionsForClip.actionByRoot[ rootUuid ] || null;
43868 // deactivates all previously scheduled actions
43869 stopAllAction: function () {
43871 const actions = this._actions,
43872 nActions = this._nActiveActions;
43874 for ( let i = nActions - 1; i >= 0; -- i ) {
43876 actions[ i ].stop();
43884 // advance the time and update apply the animation
43885 update: function ( deltaTime ) {
43887 deltaTime *= this.timeScale;
43889 const actions = this._actions,
43890 nActions = this._nActiveActions,
43892 time = this.time += deltaTime,
43893 timeDirection = Math.sign( deltaTime ),
43895 accuIndex = this._accuIndex ^= 1;
43897 // run active actions
43899 for ( let i = 0; i !== nActions; ++ i ) {
43901 const action = actions[ i ];
43903 action._update( time, deltaTime, timeDirection, accuIndex );
43907 // update scene graph
43909 const bindings = this._bindings,
43910 nBindings = this._nActiveBindings;
43912 for ( let i = 0; i !== nBindings; ++ i ) {
43914 bindings[ i ].apply( accuIndex );
43922 // Allows you to seek to a specific time in an animation.
43923 setTime: function ( timeInSeconds ) {
43925 this.time = 0; // Zero out time attribute for AnimationMixer object;
43926 for ( let i = 0; i < this._actions.length; i ++ ) {
43928 this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
43932 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
43936 // return this mixer's root target object
43937 getRoot: function () {
43943 // free all resources specific to a particular clip
43944 uncacheClip: function ( clip ) {
43946 const actions = this._actions,
43947 clipUuid = clip.uuid,
43948 actionsByClip = this._actionsByClip,
43949 actionsForClip = actionsByClip[ clipUuid ];
43951 if ( actionsForClip !== undefined ) {
43953 // note: just calling _removeInactiveAction would mess up the
43954 // iteration state and also require updating the state we can
43957 const actionsToRemove = actionsForClip.knownActions;
43959 for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
43961 const action = actionsToRemove[ i ];
43963 this._deactivateAction( action );
43965 const cacheIndex = action._cacheIndex,
43966 lastInactiveAction = actions[ actions.length - 1 ];
43968 action._cacheIndex = null;
43969 action._byClipCacheIndex = null;
43971 lastInactiveAction._cacheIndex = cacheIndex;
43972 actions[ cacheIndex ] = lastInactiveAction;
43975 this._removeInactiveBindingsForAction( action );
43979 delete actionsByClip[ clipUuid ];
43985 // free all resources specific to a particular root target object
43986 uncacheRoot: function ( root ) {
43988 const rootUuid = root.uuid,
43989 actionsByClip = this._actionsByClip;
43991 for ( const clipUuid in actionsByClip ) {
43993 const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
43994 action = actionByRoot[ rootUuid ];
43996 if ( action !== undefined ) {
43998 this._deactivateAction( action );
43999 this._removeInactiveAction( action );
44005 const bindingsByRoot = this._bindingsByRootAndName,
44006 bindingByName = bindingsByRoot[ rootUuid ];
44008 if ( bindingByName !== undefined ) {
44010 for ( const trackName in bindingByName ) {
44012 const binding = bindingByName[ trackName ];
44013 binding.restoreOriginalState();
44014 this._removeInactiveBinding( binding );
44022 // remove a targeted clip from the cache
44023 uncacheAction: function ( clip, optionalRoot ) {
44025 const action = this.existingAction( clip, optionalRoot );
44027 if ( action !== null ) {
44029 this._deactivateAction( action );
44030 this._removeInactiveAction( action );
44040 constructor( value ) {
44042 if ( typeof value === 'string' ) {
44044 console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
44045 value = arguments[ 1 ];
44049 this.value = value;
44055 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
44061 function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
44063 InterleavedBuffer.call( this, array, stride );
44065 this.meshPerAttribute = meshPerAttribute || 1;
44069 InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
44071 constructor: InstancedInterleavedBuffer,
44073 isInstancedInterleavedBuffer: true,
44075 copy: function ( source ) {
44077 InterleavedBuffer.prototype.copy.call( this, source );
44079 this.meshPerAttribute = source.meshPerAttribute;
44085 clone: function ( data ) {
44087 const ib = InterleavedBuffer.prototype.clone.call( this, data );
44089 ib.meshPerAttribute = this.meshPerAttribute;
44095 toJSON: function ( data ) {
44097 const json = InterleavedBuffer.prototype.toJSON.call( this, data );
44099 json.isInstancedInterleavedBuffer = true;
44100 json.meshPerAttribute = this.meshPerAttribute;
44108 function GLBufferAttribute( buffer, type, itemSize, elementSize, count ) {
44110 this.buffer = buffer;
44112 this.itemSize = itemSize;
44113 this.elementSize = elementSize;
44114 this.count = count;
44120 Object.defineProperty( GLBufferAttribute.prototype, 'needsUpdate', {
44122 set: function ( value ) {
44124 if ( value === true ) this.version ++;
44130 Object.assign( GLBufferAttribute.prototype, {
44132 isGLBufferAttribute: true,
44134 setBuffer: function ( buffer ) {
44136 this.buffer = buffer;
44142 setType: function ( type, elementSize ) {
44145 this.elementSize = elementSize;
44151 setItemSize: function ( itemSize ) {
44153 this.itemSize = itemSize;
44159 setCount: function ( count ) {
44161 this.count = count;
44169 function Raycaster( origin, direction, near, far ) {
44171 this.ray = new Ray( origin, direction );
44172 // direction is assumed to be normalized (for accurate distance calculations)
44174 this.near = near || 0;
44175 this.far = far || Infinity;
44176 this.camera = null;
44177 this.layers = new Layers();
44181 Line: { threshold: 1 },
44183 Points: { threshold: 1 },
44187 Object.defineProperties( this.params, {
44191 console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
44192 return this.Points;
44200 function ascSort( a, b ) {
44202 return a.distance - b.distance;
44206 function intersectObject( object, raycaster, intersects, recursive ) {
44208 if ( object.layers.test( raycaster.layers ) ) {
44210 object.raycast( raycaster, intersects );
44214 if ( recursive === true ) {
44216 const children = object.children;
44218 for ( let i = 0, l = children.length; i < l; i ++ ) {
44220 intersectObject( children[ i ], raycaster, intersects, true );
44228 Object.assign( Raycaster.prototype, {
44230 set: function ( origin, direction ) {
44232 // direction is assumed to be normalized (for accurate distance calculations)
44234 this.ray.set( origin, direction );
44238 setFromCamera: function ( coords, camera ) {
44240 if ( camera && camera.isPerspectiveCamera ) {
44242 this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
44243 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
44244 this.camera = camera;
44246 } else if ( camera && camera.isOrthographicCamera ) {
44248 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
44249 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
44250 this.camera = camera;
44254 console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
44260 intersectObject: function ( object, recursive, optionalTarget ) {
44262 const intersects = optionalTarget || [];
44264 intersectObject( object, this, intersects, recursive );
44266 intersects.sort( ascSort );
44272 intersectObjects: function ( objects, recursive, optionalTarget ) {
44274 const intersects = optionalTarget || [];
44276 if ( Array.isArray( objects ) === false ) {
44278 console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
44283 for ( let i = 0, l = objects.length; i < l; i ++ ) {
44285 intersectObject( objects[ i ], this, intersects, recursive );
44289 intersects.sort( ascSort );
44298 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
44300 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
44301 * The azimuthal angle (theta) is measured from the positive z-axis.
44306 constructor( radius = 1, phi = 0, theta = 0 ) {
44308 this.radius = radius;
44309 this.phi = phi; // polar angle
44310 this.theta = theta; // azimuthal angle
44316 set( radius, phi, theta ) {
44318 this.radius = radius;
44320 this.theta = theta;
44328 return new this.constructor().copy( this );
44334 this.radius = other.radius;
44335 this.phi = other.phi;
44336 this.theta = other.theta;
44342 // restrict phi to be betwee EPS and PI-EPS
44345 const EPS = 0.000001;
44346 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
44352 setFromVector3( v ) {
44354 return this.setFromCartesianCoords( v.x, v.y, v.z );
44358 setFromCartesianCoords( x, y, z ) {
44360 this.radius = Math.sqrt( x * x + y * y + z * z );
44362 if ( this.radius === 0 ) {
44369 this.theta = Math.atan2( x, z );
44370 this.phi = Math.acos( MathUtils.clamp( y / this.radius, - 1, 1 ) );
44381 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
44384 class Cylindrical {
44386 constructor( radius, theta, y ) {
44388 this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
44389 this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
44390 this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
44396 set( radius, theta, y ) {
44398 this.radius = radius;
44399 this.theta = theta;
44408 return new this.constructor().copy( this );
44414 this.radius = other.radius;
44415 this.theta = other.theta;
44422 setFromVector3( v ) {
44424 return this.setFromCartesianCoords( v.x, v.y, v.z );
44428 setFromCartesianCoords( x, y, z ) {
44430 this.radius = Math.sqrt( x * x + z * z );
44431 this.theta = Math.atan2( x, z );
44440 const _vector$8 = /*@__PURE__*/ new Vector2();
44444 constructor( min, max ) {
44446 Object.defineProperty( this, 'isBox2', { value: true } );
44448 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
44449 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
44455 this.min.copy( min );
44456 this.max.copy( max );
44462 setFromPoints( points ) {
44466 for ( let i = 0, il = points.length; i < il; i ++ ) {
44468 this.expandByPoint( points[ i ] );
44476 setFromCenterAndSize( center, size ) {
44478 const halfSize = _vector$8.copy( size ).multiplyScalar( 0.5 );
44479 this.min.copy( center ).sub( halfSize );
44480 this.max.copy( center ).add( halfSize );
44488 return new this.constructor().copy( this );
44494 this.min.copy( box.min );
44495 this.max.copy( box.max );
44503 this.min.x = this.min.y = + Infinity;
44504 this.max.x = this.max.y = - Infinity;
44512 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
44514 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
44518 getCenter( target ) {
44520 if ( target === undefined ) {
44522 console.warn( 'THREE.Box2: .getCenter() target is now required' );
44523 target = new Vector2();
44527 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
44531 getSize( target ) {
44533 if ( target === undefined ) {
44535 console.warn( 'THREE.Box2: .getSize() target is now required' );
44536 target = new Vector2();
44540 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
44544 expandByPoint( point ) {
44546 this.min.min( point );
44547 this.max.max( point );
44553 expandByVector( vector ) {
44555 this.min.sub( vector );
44556 this.max.add( vector );
44562 expandByScalar( scalar ) {
44564 this.min.addScalar( - scalar );
44565 this.max.addScalar( scalar );
44571 containsPoint( point ) {
44573 return point.x < this.min.x || point.x > this.max.x ||
44574 point.y < this.min.y || point.y > this.max.y ? false : true;
44578 containsBox( box ) {
44580 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
44581 this.min.y <= box.min.y && box.max.y <= this.max.y;
44585 getParameter( point, target ) {
44587 // This can potentially have a divide by zero if the box
44588 // has a size dimension of 0.
44590 if ( target === undefined ) {
44592 console.warn( 'THREE.Box2: .getParameter() target is now required' );
44593 target = new Vector2();
44598 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
44599 ( point.y - this.min.y ) / ( this.max.y - this.min.y )
44604 intersectsBox( box ) {
44606 // using 4 splitting planes to rule out intersections
44608 return box.max.x < this.min.x || box.min.x > this.max.x ||
44609 box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
44613 clampPoint( point, target ) {
44615 if ( target === undefined ) {
44617 console.warn( 'THREE.Box2: .clampPoint() target is now required' );
44618 target = new Vector2();
44622 return target.copy( point ).clamp( this.min, this.max );
44626 distanceToPoint( point ) {
44628 const clampedPoint = _vector$8.copy( point ).clamp( this.min, this.max );
44629 return clampedPoint.sub( point ).length();
44635 this.min.max( box.min );
44636 this.max.min( box.max );
44644 this.min.min( box.min );
44645 this.max.max( box.max );
44651 translate( offset ) {
44653 this.min.add( offset );
44654 this.max.add( offset );
44662 return box.min.equals( this.min ) && box.max.equals( this.max );
44668 const _startP = /*@__PURE__*/ new Vector3();
44669 const _startEnd = /*@__PURE__*/ new Vector3();
44673 constructor( start, end ) {
44675 this.start = ( start !== undefined ) ? start : new Vector3();
44676 this.end = ( end !== undefined ) ? end : new Vector3();
44680 set( start, end ) {
44682 this.start.copy( start );
44683 this.end.copy( end );
44691 return new this.constructor().copy( this );
44697 this.start.copy( line.start );
44698 this.end.copy( line.end );
44704 getCenter( target ) {
44706 if ( target === undefined ) {
44708 console.warn( 'THREE.Line3: .getCenter() target is now required' );
44709 target = new Vector3();
44713 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
44719 if ( target === undefined ) {
44721 console.warn( 'THREE.Line3: .delta() target is now required' );
44722 target = new Vector3();
44726 return target.subVectors( this.end, this.start );
44732 return this.start.distanceToSquared( this.end );
44738 return this.start.distanceTo( this.end );
44744 if ( target === undefined ) {
44746 console.warn( 'THREE.Line3: .at() target is now required' );
44747 target = new Vector3();
44751 return this.delta( target ).multiplyScalar( t ).add( this.start );
44755 closestPointToPointParameter( point, clampToLine ) {
44757 _startP.subVectors( point, this.start );
44758 _startEnd.subVectors( this.end, this.start );
44760 const startEnd2 = _startEnd.dot( _startEnd );
44761 const startEnd_startP = _startEnd.dot( _startP );
44763 let t = startEnd_startP / startEnd2;
44765 if ( clampToLine ) {
44767 t = MathUtils.clamp( t, 0, 1 );
44775 closestPointToPoint( point, clampToLine, target ) {
44777 const t = this.closestPointToPointParameter( point, clampToLine );
44779 if ( target === undefined ) {
44781 console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' );
44782 target = new Vector3();
44786 return this.delta( target ).multiplyScalar( t ).add( this.start );
44790 applyMatrix4( matrix ) {
44792 this.start.applyMatrix4( matrix );
44793 this.end.applyMatrix4( matrix );
44801 return line.start.equals( this.start ) && line.end.equals( this.end );
44807 function ImmediateRenderObject( material ) {
44809 Object3D.call( this );
44811 this.material = material;
44812 this.render = function ( /* renderCallback */ ) {};
44814 this.hasPositions = false;
44815 this.hasNormals = false;
44816 this.hasColors = false;
44817 this.hasUvs = false;
44819 this.positionArray = null;
44820 this.normalArray = null;
44821 this.colorArray = null;
44822 this.uvArray = null;
44828 ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
44829 ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
44831 ImmediateRenderObject.prototype.isImmediateRenderObject = true;
44833 const _vector$9 = /*@__PURE__*/ new Vector3();
44835 class SpotLightHelper extends Object3D {
44837 constructor( light, color ) {
44840 this.light = light;
44841 this.light.updateMatrixWorld();
44843 this.matrix = light.matrixWorld;
44844 this.matrixAutoUpdate = false;
44846 this.color = color;
44848 const geometry = new BufferGeometry();
44850 const positions = [
44853 0, 0, 0, - 1, 0, 1,
44858 for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
44860 const p1 = ( i / l ) * Math.PI * 2;
44861 const p2 = ( j / l ) * Math.PI * 2;
44864 Math.cos( p1 ), Math.sin( p1 ), 1,
44865 Math.cos( p2 ), Math.sin( p2 ), 1
44870 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
44872 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
44874 this.cone = new LineSegments( geometry, material );
44875 this.add( this.cone );
44883 this.cone.geometry.dispose();
44884 this.cone.material.dispose();
44890 this.light.updateMatrixWorld();
44892 const coneLength = this.light.distance ? this.light.distance : 1000;
44893 const coneWidth = coneLength * Math.tan( this.light.angle );
44895 this.cone.scale.set( coneWidth, coneWidth, coneLength );
44897 _vector$9.setFromMatrixPosition( this.light.target.matrixWorld );
44899 this.cone.lookAt( _vector$9 );
44901 if ( this.color !== undefined ) {
44903 this.cone.material.color.set( this.color );
44907 this.cone.material.color.copy( this.light.color );
44915 const _vector$a = /*@__PURE__*/ new Vector3();
44916 const _boneMatrix = /*@__PURE__*/ new Matrix4();
44917 const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
44920 class SkeletonHelper extends LineSegments {
44922 constructor( object ) {
44924 const bones = getBoneList( object );
44926 const geometry = new BufferGeometry();
44928 const vertices = [];
44931 const color1 = new Color( 0, 0, 1 );
44932 const color2 = new Color( 0, 1, 0 );
44934 for ( let i = 0; i < bones.length; i ++ ) {
44936 const bone = bones[ i ];
44938 if ( bone.parent && bone.parent.isBone ) {
44940 vertices.push( 0, 0, 0 );
44941 vertices.push( 0, 0, 0 );
44942 colors.push( color1.r, color1.g, color1.b );
44943 colors.push( color2.r, color2.g, color2.b );
44949 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
44950 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
44952 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
44954 super( geometry, material );
44956 this.type = 'SkeletonHelper';
44957 this.isSkeletonHelper = true;
44959 this.root = object;
44960 this.bones = bones;
44962 this.matrix = object.matrixWorld;
44963 this.matrixAutoUpdate = false;
44967 updateMatrixWorld( force ) {
44969 const bones = this.bones;
44971 const geometry = this.geometry;
44972 const position = geometry.getAttribute( 'position' );
44974 _matrixWorldInv.copy( this.root.matrixWorld ).invert();
44976 for ( let i = 0, j = 0; i < bones.length; i ++ ) {
44978 const bone = bones[ i ];
44980 if ( bone.parent && bone.parent.isBone ) {
44982 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
44983 _vector$a.setFromMatrixPosition( _boneMatrix );
44984 position.setXYZ( j, _vector$a.x, _vector$a.y, _vector$a.z );
44986 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
44987 _vector$a.setFromMatrixPosition( _boneMatrix );
44988 position.setXYZ( j + 1, _vector$a.x, _vector$a.y, _vector$a.z );
44996 geometry.getAttribute( 'position' ).needsUpdate = true;
44998 super.updateMatrixWorld( force );
45005 function getBoneList( object ) {
45007 const boneList = [];
45009 if ( object && object.isBone ) {
45011 boneList.push( object );
45015 for ( let i = 0; i < object.children.length; i ++ ) {
45017 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
45025 class PointLightHelper extends Mesh {
45027 constructor( light, sphereSize, color ) {
45029 const geometry = new SphereGeometry( sphereSize, 4, 2 );
45030 const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
45032 super( geometry, material );
45034 this.light = light;
45035 this.light.updateMatrixWorld();
45037 this.color = color;
45039 this.type = 'PointLightHelper';
45041 this.matrix = this.light.matrixWorld;
45042 this.matrixAutoUpdate = false;
45048 // TODO: delete this comment?
45049 const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 );
45050 const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
45052 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
45053 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
45055 const d = light.distance;
45059 this.lightDistance.visible = false;
45063 this.lightDistance.scale.set( d, d, d );
45067 this.add( this.lightDistance );
45074 this.geometry.dispose();
45075 this.material.dispose();
45081 if ( this.color !== undefined ) {
45083 this.material.color.set( this.color );
45087 this.material.color.copy( this.light.color );
45092 const d = this.light.distance;
45096 this.lightDistance.visible = false;
45100 this.lightDistance.visible = true;
45101 this.lightDistance.scale.set( d, d, d );
45110 const _vector$b = /*@__PURE__*/ new Vector3();
45111 const _color1 = /*@__PURE__*/ new Color();
45112 const _color2 = /*@__PURE__*/ new Color();
45114 class HemisphereLightHelper extends Object3D {
45116 constructor( light, size, color ) {
45119 this.light = light;
45120 this.light.updateMatrixWorld();
45122 this.matrix = light.matrixWorld;
45123 this.matrixAutoUpdate = false;
45125 this.color = color;
45127 const geometry = new OctahedronGeometry( size );
45128 geometry.rotateY( Math.PI * 0.5 );
45130 this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
45131 if ( this.color === undefined ) this.material.vertexColors = true;
45133 const position = geometry.getAttribute( 'position' );
45134 const colors = new Float32Array( position.count * 3 );
45136 geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
45138 this.add( new Mesh( geometry, this.material ) );
45146 this.children[ 0 ].geometry.dispose();
45147 this.children[ 0 ].material.dispose();
45153 const mesh = this.children[ 0 ];
45155 if ( this.color !== undefined ) {
45157 this.material.color.set( this.color );
45161 const colors = mesh.geometry.getAttribute( 'color' );
45163 _color1.copy( this.light.color );
45164 _color2.copy( this.light.groundColor );
45166 for ( let i = 0, l = colors.count; i < l; i ++ ) {
45168 const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
45170 colors.setXYZ( i, color.r, color.g, color.b );
45174 colors.needsUpdate = true;
45178 mesh.lookAt( _vector$b.setFromMatrixPosition( this.light.matrixWorld ).negate() );
45184 class GridHelper extends LineSegments {
45186 constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
45188 color1 = new Color( color1 );
45189 color2 = new Color( color2 );
45191 const center = divisions / 2;
45192 const step = size / divisions;
45193 const halfSize = size / 2;
45195 const vertices = [], colors = [];
45197 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
45199 vertices.push( - halfSize, 0, k, halfSize, 0, k );
45200 vertices.push( k, 0, - halfSize, k, 0, halfSize );
45202 const color = i === center ? color1 : color2;
45204 color.toArray( colors, j ); j += 3;
45205 color.toArray( colors, j ); j += 3;
45206 color.toArray( colors, j ); j += 3;
45207 color.toArray( colors, j ); j += 3;
45211 const geometry = new BufferGeometry();
45212 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
45213 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
45215 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
45217 super( geometry, material );
45219 this.type = 'GridHelper';
45225 class PolarGridHelper extends LineSegments {
45227 constructor( radius = 10, radials = 16, circles = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
45229 color1 = new Color( color1 );
45230 color2 = new Color( color2 );
45232 const vertices = [];
45235 // create the radials
45237 for ( let i = 0; i <= radials; i ++ ) {
45239 const v = ( i / radials ) * ( Math.PI * 2 );
45241 const x = Math.sin( v ) * radius;
45242 const z = Math.cos( v ) * radius;
45244 vertices.push( 0, 0, 0 );
45245 vertices.push( x, 0, z );
45247 const color = ( i & 1 ) ? color1 : color2;
45249 colors.push( color.r, color.g, color.b );
45250 colors.push( color.r, color.g, color.b );
45254 // create the circles
45256 for ( let i = 0; i <= circles; i ++ ) {
45258 const color = ( i & 1 ) ? color1 : color2;
45260 const r = radius - ( radius / circles * i );
45262 for ( let j = 0; j < divisions; j ++ ) {
45266 let v = ( j / divisions ) * ( Math.PI * 2 );
45268 let x = Math.sin( v ) * r;
45269 let z = Math.cos( v ) * r;
45271 vertices.push( x, 0, z );
45272 colors.push( color.r, color.g, color.b );
45276 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
45278 x = Math.sin( v ) * r;
45279 z = Math.cos( v ) * r;
45281 vertices.push( x, 0, z );
45282 colors.push( color.r, color.g, color.b );
45288 const geometry = new BufferGeometry();
45289 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
45290 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
45292 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
45294 super( geometry, material );
45296 this.type = 'PolarGridHelper';
45302 const _v1$6 = /*@__PURE__*/ new Vector3();
45303 const _v2$3 = /*@__PURE__*/ new Vector3();
45304 const _v3$1 = /*@__PURE__*/ new Vector3();
45306 class DirectionalLightHelper extends Object3D {
45308 constructor( light, size, color ) {
45311 this.light = light;
45312 this.light.updateMatrixWorld();
45314 this.matrix = light.matrixWorld;
45315 this.matrixAutoUpdate = false;
45317 this.color = color;
45319 if ( size === undefined ) size = 1;
45321 let geometry = new BufferGeometry();
45322 geometry.setAttribute( 'position', new Float32BufferAttribute( [
45330 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
45332 this.lightPlane = new Line( geometry, material );
45333 this.add( this.lightPlane );
45335 geometry = new BufferGeometry();
45336 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
45338 this.targetLine = new Line( geometry, material );
45339 this.add( this.targetLine );
45347 this.lightPlane.geometry.dispose();
45348 this.lightPlane.material.dispose();
45349 this.targetLine.geometry.dispose();
45350 this.targetLine.material.dispose();
45356 _v1$6.setFromMatrixPosition( this.light.matrixWorld );
45357 _v2$3.setFromMatrixPosition( this.light.target.matrixWorld );
45358 _v3$1.subVectors( _v2$3, _v1$6 );
45360 this.lightPlane.lookAt( _v2$3 );
45362 if ( this.color !== undefined ) {
45364 this.lightPlane.material.color.set( this.color );
45365 this.targetLine.material.color.set( this.color );
45369 this.lightPlane.material.color.copy( this.light.color );
45370 this.targetLine.material.color.copy( this.light.color );
45374 this.targetLine.lookAt( _v2$3 );
45375 this.targetLine.scale.z = _v3$1.length();
45381 const _vector$c = /*@__PURE__*/ new Vector3();
45382 const _camera = /*@__PURE__*/ new Camera();
45385 * - shows frustum, line of sight and up of the camera
45386 * - suitable for fast updates
45387 * - based on frustum visualization in lightgl.js shadowmap example
45388 * http://evanw.github.com/lightgl.js/tests/shadowmap.html
45391 class CameraHelper extends LineSegments {
45393 constructor( camera ) {
45395 const geometry = new BufferGeometry();
45396 const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
45398 const vertices = [];
45401 const pointMap = {};
45405 const colorFrustum = new Color( 0xffaa00 );
45406 const colorCone = new Color( 0xff0000 );
45407 const colorUp = new Color( 0x00aaff );
45408 const colorTarget = new Color( 0xffffff );
45409 const colorCross = new Color( 0x333333 );
45413 addLine( 'n1', 'n2', colorFrustum );
45414 addLine( 'n2', 'n4', colorFrustum );
45415 addLine( 'n4', 'n3', colorFrustum );
45416 addLine( 'n3', 'n1', colorFrustum );
45420 addLine( 'f1', 'f2', colorFrustum );
45421 addLine( 'f2', 'f4', colorFrustum );
45422 addLine( 'f4', 'f3', colorFrustum );
45423 addLine( 'f3', 'f1', colorFrustum );
45427 addLine( 'n1', 'f1', colorFrustum );
45428 addLine( 'n2', 'f2', colorFrustum );
45429 addLine( 'n3', 'f3', colorFrustum );
45430 addLine( 'n4', 'f4', colorFrustum );
45434 addLine( 'p', 'n1', colorCone );
45435 addLine( 'p', 'n2', colorCone );
45436 addLine( 'p', 'n3', colorCone );
45437 addLine( 'p', 'n4', colorCone );
45441 addLine( 'u1', 'u2', colorUp );
45442 addLine( 'u2', 'u3', colorUp );
45443 addLine( 'u3', 'u1', colorUp );
45447 addLine( 'c', 't', colorTarget );
45448 addLine( 'p', 'c', colorCross );
45452 addLine( 'cn1', 'cn2', colorCross );
45453 addLine( 'cn3', 'cn4', colorCross );
45455 addLine( 'cf1', 'cf2', colorCross );
45456 addLine( 'cf3', 'cf4', colorCross );
45458 function addLine( a, b, color ) {
45460 addPoint( a, color );
45461 addPoint( b, color );
45465 function addPoint( id, color ) {
45467 vertices.push( 0, 0, 0 );
45468 colors.push( color.r, color.g, color.b );
45470 if ( pointMap[ id ] === undefined ) {
45472 pointMap[ id ] = [];
45476 pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
45480 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
45481 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
45483 super( geometry, material );
45485 this.type = 'CameraHelper';
45487 this.camera = camera;
45488 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
45490 this.matrix = camera.matrixWorld;
45491 this.matrixAutoUpdate = false;
45493 this.pointMap = pointMap;
45501 const geometry = this.geometry;
45502 const pointMap = this.pointMap;
45504 const w = 1, h = 1;
45506 // we need just camera projection matrix inverse
45507 // world matrix must be identity
45509 _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
45513 setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
45514 setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
45518 setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
45519 setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
45520 setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
45521 setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
45525 setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
45526 setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
45527 setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
45528 setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
45532 setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
45533 setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
45534 setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
45538 setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
45539 setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
45540 setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
45541 setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
45543 setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
45544 setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
45545 setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
45546 setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
45548 geometry.getAttribute( 'position' ).needsUpdate = true;
45555 function setPoint( point, pointMap, geometry, camera, x, y, z ) {
45557 _vector$c.set( x, y, z ).unproject( camera );
45559 const points = pointMap[ point ];
45561 if ( points !== undefined ) {
45563 const position = geometry.getAttribute( 'position' );
45565 for ( let i = 0, l = points.length; i < l; i ++ ) {
45567 position.setXYZ( points[ i ], _vector$c.x, _vector$c.y, _vector$c.z );
45575 const _box$3 = /*@__PURE__*/ new Box3();
45577 class BoxHelper extends LineSegments {
45579 constructor( object, color = 0xffff00 ) {
45581 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 ] );
45582 const positions = new Float32Array( 8 * 3 );
45584 const geometry = new BufferGeometry();
45585 geometry.setIndex( new BufferAttribute( indices, 1 ) );
45586 geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
45588 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
45590 this.object = object;
45591 this.type = 'BoxHelper';
45593 this.matrixAutoUpdate = false;
45601 if ( object !== undefined ) {
45603 console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
45607 if ( this.object !== undefined ) {
45609 _box$3.setFromObject( this.object );
45613 if ( _box$3.isEmpty() ) return;
45615 const min = _box$3.min;
45616 const max = _box$3.max;
45624 0: max.x, max.y, max.z
45625 1: min.x, max.y, max.z
45626 2: min.x, min.y, max.z
45627 3: max.x, min.y, max.z
45628 4: max.x, max.y, min.z
45629 5: min.x, max.y, min.z
45630 6: min.x, min.y, min.z
45631 7: max.x, min.y, min.z
45634 const position = this.geometry.attributes.position;
45635 const array = position.array;
45637 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
45638 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
45639 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
45640 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
45641 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
45642 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
45643 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
45644 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
45646 position.needsUpdate = true;
45648 this.geometry.computeBoundingSphere();
45653 setFromObject( object ) {
45655 this.object = object;
45664 LineSegments.prototype.copy.call( this, source );
45666 this.object = source.object;
45674 class Box3Helper extends LineSegments {
45676 constructor( box, color = 0xffff00 ) {
45678 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 ] );
45680 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 ];
45682 const geometry = new BufferGeometry();
45684 geometry.setIndex( new BufferAttribute( indices, 1 ) );
45686 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
45688 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
45692 this.type = 'Box3Helper';
45694 this.geometry.computeBoundingSphere();
45698 updateMatrixWorld( force ) {
45700 const box = this.box;
45702 if ( box.isEmpty() ) return;
45704 box.getCenter( this.position );
45706 box.getSize( this.scale );
45708 this.scale.multiplyScalar( 0.5 );
45710 super.updateMatrixWorld( force );
45716 class PlaneHelper extends Line {
45718 constructor( plane, size = 1, hex = 0xffff00 ) {
45722 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, 0, 0, 1, 0, 0, 0 ];
45724 const geometry = new BufferGeometry();
45725 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
45726 geometry.computeBoundingSphere();
45728 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
45730 this.type = 'PlaneHelper';
45732 this.plane = plane;
45736 const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
45738 const geometry2 = new BufferGeometry();
45739 geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
45740 geometry2.computeBoundingSphere();
45742 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
45746 updateMatrixWorld( force ) {
45748 let scale = - this.plane.constant;
45750 if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
45752 this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
45754 this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
45756 this.lookAt( this.plane.normal );
45758 super.updateMatrixWorld( force );
45764 const _axis = /*@__PURE__*/ new Vector3();
45765 let _lineGeometry, _coneGeometry;
45767 class ArrowHelper extends Object3D {
45769 constructor( dir, origin, length, color, headLength, headWidth ) {
45772 // dir is assumed to be normalized
45774 this.type = 'ArrowHelper';
45776 if ( dir === undefined ) dir = new Vector3( 0, 0, 1 );
45777 if ( origin === undefined ) origin = new Vector3( 0, 0, 0 );
45778 if ( length === undefined ) length = 1;
45779 if ( color === undefined ) color = 0xffff00;
45780 if ( headLength === undefined ) headLength = 0.2 * length;
45781 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
45783 if ( _lineGeometry === undefined ) {
45785 _lineGeometry = new BufferGeometry();
45786 _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
45788 _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );
45789 _coneGeometry.translate( 0, - 0.5, 0 );
45793 this.position.copy( origin );
45795 this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
45796 this.line.matrixAutoUpdate = false;
45797 this.add( this.line );
45799 this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
45800 this.cone.matrixAutoUpdate = false;
45801 this.add( this.cone );
45803 this.setDirection( dir );
45804 this.setLength( length, headLength, headWidth );
45808 setDirection( dir ) {
45810 // dir is assumed to be normalized
45812 if ( dir.y > 0.99999 ) {
45814 this.quaternion.set( 0, 0, 0, 1 );
45816 } else if ( dir.y < - 0.99999 ) {
45818 this.quaternion.set( 1, 0, 0, 0 );
45822 _axis.set( dir.z, 0, - dir.x ).normalize();
45824 const radians = Math.acos( dir.y );
45826 this.quaternion.setFromAxisAngle( _axis, radians );
45832 setLength( length, headLength, headWidth ) {
45834 if ( headLength === undefined ) headLength = 0.2 * length;
45835 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
45837 this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
45838 this.line.updateMatrix();
45840 this.cone.scale.set( headWidth, headLength, headWidth );
45841 this.cone.position.y = length;
45842 this.cone.updateMatrix();
45846 setColor( color ) {
45848 this.line.material.color.set( color );
45849 this.cone.material.color.set( color );
45855 super.copy( source, false );
45857 this.line.copy( source.line );
45858 this.cone.copy( source.cone );
45866 class AxesHelper extends LineSegments {
45868 constructor( size = 1 ) {
45871 0, 0, 0, size, 0, 0,
45872 0, 0, 0, 0, size, 0,
45873 0, 0, 0, 0, 0, size
45877 1, 0, 0, 1, 0.6, 0,
45878 0, 1, 0, 0.6, 1, 0,
45882 const geometry = new BufferGeometry();
45883 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
45884 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
45886 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
45888 super( geometry, material );
45890 this.type = 'AxesHelper';
45896 const _floatView = new Float32Array( 1 );
45897 const _int32View = new Int32Array( _floatView.buffer );
45899 const DataUtils = {
45901 // Converts float32 to float16 (stored as uint16 value).
45903 toHalfFloat: function ( val ) {
45905 // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
45907 /* This method is faster than the OpenEXR implementation (very often
45908 * used, eg. in Ogre), with the additional benefit of rounding, inspired
45909 * by James Tursa?s half-precision code. */
45911 _floatView[ 0 ] = val;
45912 const x = _int32View[ 0 ];
45914 let bits = ( x >> 16 ) & 0x8000; /* Get the sign */
45915 let m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
45916 const e = ( x >> 23 ) & 0xff; /* Using int is faster here */
45918 /* If zero, or denormal, or exponent underflows too much for a denormal
45919 * half, return signed zero. */
45920 if ( e < 103 ) return bits;
45922 /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
45926 /* If exponent was 0xff and one mantissa bit was set, it means NaN,
45927 * not Inf, so make sure we set one mantissa bit too. */
45928 bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
45933 /* If exponent underflows but not too much, return a denormal */
45937 /* Extra rounding may overflow and set mantissa to 0 and exponent
45938 * to 1, which is OK. */
45939 bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
45944 bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
45945 /* Extra rounding. An overflow will set mantissa to 0 and increment
45946 * the exponent, which is OK. */
45956 const SIZE_MAX = Math.pow( 2, LOD_MAX );
45958 // The standard deviations (radians) associated with the extra mips. These are
45959 // chosen to approximate a Trowbridge-Reitz distribution function times the
45960 // geometric shadowing function. These sigma values squared must match the
45961 // variance #defines in cube_uv_reflection_fragment.glsl.js.
45962 const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
45964 const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
45966 // The maximum length of the blur for loop. Smaller sigmas will use fewer
45967 // samples and exit early, but not recompile the shader.
45968 const MAX_SAMPLES = 20;
45970 const ENCODINGS = {
45971 [ LinearEncoding ]: 0,
45972 [ sRGBEncoding ]: 1,
45973 [ RGBEEncoding ]: 2,
45974 [ RGBM7Encoding ]: 3,
45975 [ RGBM16Encoding ]: 4,
45976 [ RGBDEncoding ]: 5,
45977 [ GammaEncoding ]: 6
45980 const backgroundMaterial = new MeshBasicMaterial( {
45985 const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
45987 const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
45988 const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
45989 const _clearColor = /*@__PURE__*/ new Color();
45990 let _oldTarget = null;
45993 const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
45994 const INV_PHI = 1 / PHI;
45996 // Vertices of a dodecahedron (except the opposites, which represent the
45997 // same axis), used as axis directions evenly spread on a sphere.
45998 const _axisDirections = [
45999 /*@__PURE__*/ new Vector3( 1, 1, 1 ),
46000 /*@__PURE__*/ new Vector3( - 1, 1, 1 ),
46001 /*@__PURE__*/ new Vector3( 1, 1, - 1 ),
46002 /*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
46003 /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
46004 /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
46005 /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
46006 /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
46007 /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
46008 /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
46011 * This class generates a Prefiltered, Mipmapped Radiance Environment Map
46012 * (PMREM) from a cubeMap environment texture. This allows different levels of
46013 * blur to be quickly accessed based on material roughness. It is packed into a
46014 * special CubeUV format that allows us to perform custom interpolation so that
46015 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
46016 * chain, it only goes down to the LOD_MIN level (above), and then creates extra
46017 * even more filtered 'mips' at the same LOD_MIN resolution, associated with
46018 * higher roughness levels. In this way we maintain resolution to smoothly
46019 * interpolate diffuse lighting while limiting sampling computation.
46022 function convertLinearToRGBE( color ) {
46024 const maxComponent = Math.max( color.r, color.g, color.b );
46025 const fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 );
46026 color.multiplyScalar( Math.pow( 2.0, - fExp ) );
46028 const alpha = ( fExp + 128.0 ) / 255.0;
46033 class PMREMGenerator {
46035 constructor( renderer ) {
46037 this._renderer = renderer;
46038 this._pingPongRenderTarget = null;
46040 this._blurMaterial = _getBlurShader( MAX_SAMPLES );
46041 this._equirectShader = null;
46042 this._cubemapShader = null;
46044 this._compileMaterial( this._blurMaterial );
46049 * Generates a PMREM from a supplied Scene, which can be faster than using an
46050 * image if networking bandwidth is low. Optional sigma specifies a blur radius
46051 * in radians to be applied to the scene before PMREM generation. Optional near
46052 * and far planes ensure the scene is rendered in its entirety (the cubeCamera
46053 * is placed at the origin).
46055 fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
46057 _oldTarget = this._renderer.getRenderTarget();
46058 const cubeUVRenderTarget = this._allocateTargets();
46060 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
46063 this._blur( cubeUVRenderTarget, 0, 0, sigma );
46067 this._applyPMREM( cubeUVRenderTarget );
46068 this._cleanup( cubeUVRenderTarget );
46070 return cubeUVRenderTarget;
46075 * Generates a PMREM from an equirectangular texture, which can be either LDR
46076 * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
46077 * as this matches best with the 256 x 256 cubemap output.
46079 fromEquirectangular( equirectangular ) {
46081 return this._fromTexture( equirectangular );
46086 * Generates a PMREM from an cubemap texture, which can be either LDR
46087 * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
46088 * as this matches best with the 256 x 256 cubemap output.
46090 fromCubemap( cubemap ) {
46092 return this._fromTexture( cubemap );
46097 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
46098 * your texture's network fetch for increased concurrency.
46100 compileCubemapShader() {
46102 if ( this._cubemapShader === null ) {
46104 this._cubemapShader = _getCubemapShader();
46105 this._compileMaterial( this._cubemapShader );
46112 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
46113 * your texture's network fetch for increased concurrency.
46115 compileEquirectangularShader() {
46117 if ( this._equirectShader === null ) {
46119 this._equirectShader = _getEquirectShader();
46120 this._compileMaterial( this._equirectShader );
46127 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
46128 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
46129 * one of them will cause any others to also become unusable.
46133 this._blurMaterial.dispose();
46135 if ( this._cubemapShader !== null ) this._cubemapShader.dispose();
46136 if ( this._equirectShader !== null ) this._equirectShader.dispose();
46138 for ( let i = 0; i < _lodPlanes.length; i ++ ) {
46140 _lodPlanes[ i ].dispose();
46146 // private interface
46148 _cleanup( outputTarget ) {
46150 this._pingPongRenderTarget.dispose();
46151 this._renderer.setRenderTarget( _oldTarget );
46152 outputTarget.scissorTest = false;
46153 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
46157 _fromTexture( texture ) {
46159 _oldTarget = this._renderer.getRenderTarget();
46160 const cubeUVRenderTarget = this._allocateTargets( texture );
46161 this._textureToCubeUV( texture, cubeUVRenderTarget );
46162 this._applyPMREM( cubeUVRenderTarget );
46163 this._cleanup( cubeUVRenderTarget );
46165 return cubeUVRenderTarget;
46169 _allocateTargets( texture ) { // warning: null texture is valid
46172 magFilter: NearestFilter,
46173 minFilter: NearestFilter,
46174 generateMipmaps: false,
46175 type: UnsignedByteType,
46176 format: RGBEFormat,
46177 encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding,
46181 const cubeUVRenderTarget = _createRenderTarget( params );
46182 cubeUVRenderTarget.depthBuffer = texture ? false : true;
46183 this._pingPongRenderTarget = _createRenderTarget( params );
46184 return cubeUVRenderTarget;
46188 _compileMaterial( material ) {
46190 const tmpMesh = new Mesh( _lodPlanes[ 0 ], material );
46191 this._renderer.compile( tmpMesh, _flatCamera );
46195 _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
46199 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
46200 const upSign = [ 1, - 1, 1, 1, 1, 1 ];
46201 const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
46202 const renderer = this._renderer;
46204 const originalAutoClear = renderer.autoClear;
46205 const outputEncoding = renderer.outputEncoding;
46206 const toneMapping = renderer.toneMapping;
46207 renderer.getClearColor( _clearColor );
46209 renderer.toneMapping = NoToneMapping;
46210 renderer.outputEncoding = LinearEncoding;
46211 renderer.autoClear = false;
46213 let useSolidColor = false;
46214 const background = scene.background;
46215 if ( background ) {
46217 if ( background.isColor ) {
46219 backgroundMaterial.color.copy( background ).convertSRGBToLinear();
46220 scene.background = null;
46222 const alpha = convertLinearToRGBE( backgroundMaterial.color );
46223 backgroundMaterial.opacity = alpha;
46224 useSolidColor = true;
46230 backgroundMaterial.color.copy( _clearColor ).convertSRGBToLinear();
46232 const alpha = convertLinearToRGBE( backgroundMaterial.color );
46233 backgroundMaterial.opacity = alpha;
46234 useSolidColor = true;
46239 for ( let i = 0; i < 6; i ++ ) {
46244 cubeCamera.up.set( 0, upSign[ i ], 0 );
46245 cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
46247 } else if ( col == 1 ) {
46249 cubeCamera.up.set( 0, 0, upSign[ i ] );
46250 cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
46254 cubeCamera.up.set( 0, upSign[ i ], 0 );
46255 cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
46259 _setViewport( cubeUVRenderTarget,
46260 col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX );
46261 renderer.setRenderTarget( cubeUVRenderTarget );
46263 if ( useSolidColor ) {
46265 renderer.render( backgroundBox, cubeCamera );
46269 renderer.render( scene, cubeCamera );
46273 renderer.toneMapping = toneMapping;
46274 renderer.outputEncoding = outputEncoding;
46275 renderer.autoClear = originalAutoClear;
46279 _textureToCubeUV( texture, cubeUVRenderTarget ) {
46281 const renderer = this._renderer;
46283 if ( texture.isCubeTexture ) {
46285 if ( this._cubemapShader == null ) {
46287 this._cubemapShader = _getCubemapShader();
46293 if ( this._equirectShader == null ) {
46295 this._equirectShader = _getEquirectShader();
46301 const material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader;
46302 const mesh = new Mesh( _lodPlanes[ 0 ], material );
46304 const uniforms = material.uniforms;
46306 uniforms[ 'envMap' ].value = texture;
46308 if ( ! texture.isCubeTexture ) {
46310 uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height );
46314 uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ];
46315 uniforms[ 'outputEncoding' ].value = ENCODINGS[ cubeUVRenderTarget.texture.encoding ];
46317 _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
46319 renderer.setRenderTarget( cubeUVRenderTarget );
46320 renderer.render( mesh, _flatCamera );
46324 _applyPMREM( cubeUVRenderTarget ) {
46326 const renderer = this._renderer;
46327 const autoClear = renderer.autoClear;
46328 renderer.autoClear = false;
46330 for ( let i = 1; i < TOTAL_LODS; i ++ ) {
46332 const sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] );
46334 const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
46336 this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
46340 renderer.autoClear = autoClear;
46345 * This is a two-pass Gaussian blur for a cubemap. Normally this is done
46346 * vertically and horizontally, but this breaks down on a cube. Here we apply
46347 * the blur latitudinally (around the poles), and then longitudinally (towards
46348 * the poles) to approximate the orthogonally-separable blur. It is least
46349 * accurate at the poles, but still does a decent job.
46351 _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
46353 const pingPongRenderTarget = this._pingPongRenderTarget;
46356 cubeUVRenderTarget,
46357 pingPongRenderTarget,
46365 pingPongRenderTarget,
46366 cubeUVRenderTarget,
46375 _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
46377 const renderer = this._renderer;
46378 const blurMaterial = this._blurMaterial;
46380 if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
46383 'blur direction must be either latitudinal or longitudinal!' );
46387 // Number of standard deviations at which to cut off the discrete approximation.
46388 const STANDARD_DEVIATIONS = 3;
46390 const blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial );
46391 const blurUniforms = blurMaterial.uniforms;
46393 const pixels = _sizeLods[ lodIn ] - 1;
46394 const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
46395 const sigmaPixels = sigmaRadians / radiansPerPixel;
46396 const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
46398 if ( samples > MAX_SAMPLES ) {
46400 console.warn( `sigmaRadians, ${
46401 sigmaRadians}, is too large and will clip, as it requested ${
46402 samples} samples when the maximum is set to ${MAX_SAMPLES}` );
46406 const weights = [];
46409 for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
46411 const x = i / sigmaPixels;
46412 const weight = Math.exp( - x * x / 2 );
46413 weights.push( weight );
46419 } else if ( i < samples ) {
46427 for ( let i = 0; i < weights.length; i ++ ) {
46429 weights[ i ] = weights[ i ] / sum;
46433 blurUniforms[ 'envMap' ].value = targetIn.texture;
46434 blurUniforms[ 'samples' ].value = samples;
46435 blurUniforms[ 'weights' ].value = weights;
46436 blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
46440 blurUniforms[ 'poleAxis' ].value = poleAxis;
46444 blurUniforms[ 'dTheta' ].value = radiansPerPixel;
46445 blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
46446 blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
46447 blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
46449 const outputSize = _sizeLods[ lodOut ];
46450 const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );
46451 const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 );
46453 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
46454 renderer.setRenderTarget( targetOut );
46455 renderer.render( blurMesh, _flatCamera );
46461 function _isLDR( texture ) {
46463 if ( texture === undefined || texture.type !== UnsignedByteType ) return false;
46465 return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding;
46469 function _createPlanes() {
46471 const _lodPlanes = [];
46472 const _sizeLods = [];
46473 const _sigmas = [];
46477 for ( let i = 0; i < TOTAL_LODS; i ++ ) {
46479 const sizeLod = Math.pow( 2, lod );
46480 _sizeLods.push( sizeLod );
46481 let sigma = 1.0 / sizeLod;
46483 if ( i > LOD_MAX - LOD_MIN ) {
46485 sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ];
46487 } else if ( i == 0 ) {
46493 _sigmas.push( sigma );
46495 const texelSize = 1.0 / ( sizeLod - 1 );
46496 const min = - texelSize / 2;
46497 const max = 1 + texelSize / 2;
46498 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
46500 const cubeFaces = 6;
46501 const vertices = 6;
46502 const positionSize = 3;
46504 const faceIndexSize = 1;
46506 const position = new Float32Array( positionSize * vertices * cubeFaces );
46507 const uv = new Float32Array( uvSize * vertices * cubeFaces );
46508 const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
46510 for ( let face = 0; face < cubeFaces; face ++ ) {
46512 const x = ( face % 3 ) * 2 / 3 - 1;
46513 const y = face > 2 ? 0 : - 1;
46514 const coordinates = [
46517 x + 2 / 3, y + 1, 0,
46519 x + 2 / 3, y + 1, 0,
46522 position.set( coordinates, positionSize * vertices * face );
46523 uv.set( uv1, uvSize * vertices * face );
46524 const fill = [ face, face, face, face, face, face ];
46525 faceIndex.set( fill, faceIndexSize * vertices * face );
46529 const planes = new BufferGeometry();
46530 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
46531 planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
46532 planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
46533 _lodPlanes.push( planes );
46535 if ( lod > LOD_MIN ) {
46543 return { _lodPlanes, _sizeLods, _sigmas };
46547 function _createRenderTarget( params ) {
46549 const cubeUVRenderTarget = new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params );
46550 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
46551 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
46552 cubeUVRenderTarget.scissorTest = true;
46553 return cubeUVRenderTarget;
46557 function _setViewport( target, x, y, width, height ) {
46559 target.viewport.set( x, y, width, height );
46560 target.scissor.set( x, y, width, height );
46564 function _getBlurShader( maxSamples ) {
46566 const weights = new Float32Array( maxSamples );
46567 const poleAxis = new Vector3( 0, 1, 0 );
46568 const shaderMaterial = new RawShaderMaterial( {
46570 name: 'SphericalGaussianBlur',
46572 defines: { 'n': maxSamples },
46575 'envMap': { value: null },
46576 'samples': { value: 1 },
46577 'weights': { value: weights },
46578 'latitudinal': { value: false },
46579 'dTheta': { value: 0 },
46580 'mipInt': { value: 0 },
46581 'poleAxis': { value: poleAxis },
46582 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
46583 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
46586 vertexShader: _getCommonVertexShader(),
46588 fragmentShader: /* glsl */`
46590 precision mediump float;
46591 precision mediump int;
46593 varying vec3 vOutputDirection;
46595 uniform sampler2D envMap;
46596 uniform int samples;
46597 uniform float weights[ n ];
46598 uniform bool latitudinal;
46599 uniform float dTheta;
46600 uniform float mipInt;
46601 uniform vec3 poleAxis;
46603 ${ _getEncodings() }
46605 #define ENVMAP_TYPE_CUBE_UV
46606 #include <cube_uv_reflection_fragment>
46608 vec3 getSample( float theta, vec3 axis ) {
46610 float cosTheta = cos( theta );
46611 // Rodrigues' axis-angle rotation
46612 vec3 sampleDirection = vOutputDirection * cosTheta
46613 + cross( axis, vOutputDirection ) * sin( theta )
46614 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
46616 return bilinearCubeUV( envMap, sampleDirection, mipInt );
46622 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
46624 if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
46626 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
46630 axis = normalize( axis );
46632 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
46633 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
46635 for ( int i = 1; i < n; i++ ) {
46637 if ( i >= samples ) {
46643 float theta = dTheta * float( i );
46644 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
46645 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
46649 gl_FragColor = linearToOutputTexel( gl_FragColor );
46654 blending: NoBlending,
46660 return shaderMaterial;
46664 function _getEquirectShader() {
46666 const texelSize = new Vector2( 1, 1 );
46667 const shaderMaterial = new RawShaderMaterial( {
46669 name: 'EquirectangularToCubeUV',
46672 'envMap': { value: null },
46673 'texelSize': { value: texelSize },
46674 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
46675 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
46678 vertexShader: _getCommonVertexShader(),
46680 fragmentShader: /* glsl */`
46682 precision mediump float;
46683 precision mediump int;
46685 varying vec3 vOutputDirection;
46687 uniform sampler2D envMap;
46688 uniform vec2 texelSize;
46690 ${ _getEncodings() }
46696 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
46698 vec3 outputDirection = normalize( vOutputDirection );
46699 vec2 uv = equirectUv( outputDirection );
46701 vec2 f = fract( uv / texelSize - 0.5 );
46702 uv -= f * texelSize;
46703 vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
46704 uv.x += texelSize.x;
46705 vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
46706 uv.y += texelSize.y;
46707 vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
46708 uv.x -= texelSize.x;
46709 vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
46711 vec3 tm = mix( tl, tr, f.x );
46712 vec3 bm = mix( bl, br, f.x );
46713 gl_FragColor.rgb = mix( tm, bm, f.y );
46715 gl_FragColor = linearToOutputTexel( gl_FragColor );
46720 blending: NoBlending,
46726 return shaderMaterial;
46730 function _getCubemapShader() {
46732 const shaderMaterial = new RawShaderMaterial( {
46734 name: 'CubemapToCubeUV',
46737 'envMap': { value: null },
46738 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
46739 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
46742 vertexShader: _getCommonVertexShader(),
46744 fragmentShader: /* glsl */`
46746 precision mediump float;
46747 precision mediump int;
46749 varying vec3 vOutputDirection;
46751 uniform samplerCube envMap;
46753 ${ _getEncodings() }
46757 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
46758 gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;
46759 gl_FragColor = linearToOutputTexel( gl_FragColor );
46764 blending: NoBlending,
46770 return shaderMaterial;
46774 function _getCommonVertexShader() {
46778 precision mediump float;
46779 precision mediump int;
46781 attribute vec3 position;
46783 attribute float faceIndex;
46785 varying vec3 vOutputDirection;
46787 // RH coordinate system; PMREM face-indexing convention
46788 vec3 getDirection( vec2 uv, float face ) {
46790 uv = 2.0 * uv - 1.0;
46792 vec3 direction = vec3( uv, 1.0 );
46794 if ( face == 0.0 ) {
46796 direction = direction.zyx; // ( 1, v, u ) pos x
46798 } else if ( face == 1.0 ) {
46800 direction = direction.xzy;
46801 direction.xz *= -1.0; // ( -u, 1, -v ) pos y
46803 } else if ( face == 2.0 ) {
46805 direction.x *= -1.0; // ( -u, v, 1 ) pos z
46807 } else if ( face == 3.0 ) {
46809 direction = direction.zyx;
46810 direction.xz *= -1.0; // ( -1, v, -u ) neg x
46812 } else if ( face == 4.0 ) {
46814 direction = direction.xzy;
46815 direction.xy *= -1.0; // ( -u, -1, v ) neg y
46817 } else if ( face == 5.0 ) {
46819 direction.z *= -1.0; // ( u, v, -1 ) neg z
46829 vOutputDirection = getDirection( uv, faceIndex );
46830 gl_Position = vec4( position, 1.0 );
46837 function _getEncodings() {
46841 uniform int inputEncoding;
46842 uniform int outputEncoding;
46844 #include <encodings_pars_fragment>
46846 vec4 inputTexelToLinear( vec4 value ) {
46848 if ( inputEncoding == 0 ) {
46852 } else if ( inputEncoding == 1 ) {
46854 return sRGBToLinear( value );
46856 } else if ( inputEncoding == 2 ) {
46858 return RGBEToLinear( value );
46860 } else if ( inputEncoding == 3 ) {
46862 return RGBMToLinear( value, 7.0 );
46864 } else if ( inputEncoding == 4 ) {
46866 return RGBMToLinear( value, 16.0 );
46868 } else if ( inputEncoding == 5 ) {
46870 return RGBDToLinear( value, 256.0 );
46874 return GammaToLinear( value, 2.2 );
46880 vec4 linearToOutputTexel( vec4 value ) {
46882 if ( outputEncoding == 0 ) {
46886 } else if ( outputEncoding == 1 ) {
46888 return LinearTosRGB( value );
46890 } else if ( outputEncoding == 2 ) {
46892 return LinearToRGBE( value );
46894 } else if ( outputEncoding == 3 ) {
46896 return LinearToRGBM( value, 7.0 );
46898 } else if ( outputEncoding == 4 ) {
46900 return LinearToRGBM( value, 16.0 );
46902 } else if ( outputEncoding == 5 ) {
46904 return LinearToRGBD( value, 256.0 );
46908 return LinearToGamma( value, 2.2 );
46914 vec4 envMapTexelToLinear( vec4 color ) {
46916 return inputTexelToLinear( color );
46923 function Face4( a, b, c, d, normal, color, materialIndex ) {
46925 console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
46926 return new Face3( a, b, c, normal, color, materialIndex );
46930 const LineStrip = 0;
46931 const LinePieces = 1;
46932 const NoColors = 0;
46933 const FaceColors = 1;
46934 const VertexColors = 2;
46936 function MeshFaceMaterial( materials ) {
46938 console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );
46943 function MultiMaterial( materials = [] ) {
46945 console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );
46946 materials.isMultiMaterial = true;
46947 materials.materials = materials;
46948 materials.clone = function () {
46950 return materials.slice();
46958 function PointCloud( geometry, material ) {
46960 console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
46961 return new Points( geometry, material );
46965 function Particle( material ) {
46967 console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
46968 return new Sprite( material );
46972 function ParticleSystem( geometry, material ) {
46974 console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
46975 return new Points( geometry, material );
46979 function PointCloudMaterial( parameters ) {
46981 console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
46982 return new PointsMaterial( parameters );
46986 function ParticleBasicMaterial( parameters ) {
46988 console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
46989 return new PointsMaterial( parameters );
46993 function ParticleSystemMaterial( parameters ) {
46995 console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
46996 return new PointsMaterial( parameters );
47000 function Vertex( x, y, z ) {
47002 console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
47003 return new Vector3( x, y, z );
47009 function DynamicBufferAttribute( array, itemSize ) {
47011 console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead.' );
47012 return new BufferAttribute( array, itemSize ).setUsage( DynamicDrawUsage );
47016 function Int8Attribute( array, itemSize ) {
47018 console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
47019 return new Int8BufferAttribute( array, itemSize );
47023 function Uint8Attribute( array, itemSize ) {
47025 console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
47026 return new Uint8BufferAttribute( array, itemSize );
47030 function Uint8ClampedAttribute( array, itemSize ) {
47032 console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
47033 return new Uint8ClampedBufferAttribute( array, itemSize );
47037 function Int16Attribute( array, itemSize ) {
47039 console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
47040 return new Int16BufferAttribute( array, itemSize );
47044 function Uint16Attribute( array, itemSize ) {
47046 console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
47047 return new Uint16BufferAttribute( array, itemSize );
47051 function Int32Attribute( array, itemSize ) {
47053 console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
47054 return new Int32BufferAttribute( array, itemSize );
47058 function Uint32Attribute( array, itemSize ) {
47060 console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
47061 return new Uint32BufferAttribute( array, itemSize );
47065 function Float32Attribute( array, itemSize ) {
47067 console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
47068 return new Float32BufferAttribute( array, itemSize );
47072 function Float64Attribute( array, itemSize ) {
47074 console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
47075 return new Float64BufferAttribute( array, itemSize );
47081 Curve.create = function ( construct, getPoint ) {
47083 console.log( 'THREE.Curve.create() has been deprecated' );
47085 construct.prototype = Object.create( Curve.prototype );
47086 construct.prototype.constructor = construct;
47087 construct.prototype.getPoint = getPoint;
47095 Object.assign( Path.prototype, {
47097 fromPoints: function ( points ) {
47099 console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
47100 return this.setFromPoints( points );
47108 function ClosedSplineCurve3( points ) {
47110 console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
47112 CatmullRomCurve3.call( this, points );
47113 this.type = 'catmullrom';
47114 this.closed = true;
47118 ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
47122 function SplineCurve3( points ) {
47124 console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
47126 CatmullRomCurve3.call( this, points );
47127 this.type = 'catmullrom';
47131 SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
47135 function Spline( points ) {
47137 console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
47139 CatmullRomCurve3.call( this, points );
47140 this.type = 'catmullrom';
47144 Spline.prototype = Object.create( CatmullRomCurve3.prototype );
47146 Object.assign( Spline.prototype, {
47148 initFromArray: function ( /* a */ ) {
47150 console.error( 'THREE.Spline: .initFromArray() has been removed.' );
47153 getControlPointsArray: function ( /* optionalTarget */ ) {
47155 console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
47158 reparametrizeByArcLength: function ( /* samplingCoef */ ) {
47160 console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
47168 function AxisHelper( size ) {
47170 console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' );
47171 return new AxesHelper( size );
47175 function BoundingBoxHelper( object, color ) {
47177 console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
47178 return new BoxHelper( object, color );
47182 function EdgesHelper( object, hex ) {
47184 console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
47185 return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
47189 GridHelper.prototype.setColors = function () {
47191 console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
47195 SkeletonHelper.prototype.update = function () {
47197 console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
47201 function WireframeHelper( object, hex ) {
47203 console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
47204 return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
47210 Object.assign( Loader.prototype, {
47212 extractUrlBase: function ( url ) {
47214 console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
47215 return LoaderUtils.extractUrlBase( url );
47221 Loader.Handlers = {
47223 add: function ( /* regex, loader */ ) {
47225 console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' );
47229 get: function ( /* file */ ) {
47231 console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' );
47237 function XHRLoader( manager ) {
47239 console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
47240 return new FileLoader( manager );
47244 function BinaryTextureLoader( manager ) {
47246 console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
47247 return new DataTextureLoader( manager );
47253 Object.assign( Box2.prototype, {
47255 center: function ( optionalTarget ) {
47257 console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
47258 return this.getCenter( optionalTarget );
47261 empty: function () {
47263 console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
47264 return this.isEmpty();
47267 isIntersectionBox: function ( box ) {
47269 console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
47270 return this.intersectsBox( box );
47273 size: function ( optionalTarget ) {
47275 console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
47276 return this.getSize( optionalTarget );
47281 Object.assign( Box3.prototype, {
47283 center: function ( optionalTarget ) {
47285 console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
47286 return this.getCenter( optionalTarget );
47289 empty: function () {
47291 console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
47292 return this.isEmpty();
47295 isIntersectionBox: function ( box ) {
47297 console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
47298 return this.intersectsBox( box );
47301 isIntersectionSphere: function ( sphere ) {
47303 console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
47304 return this.intersectsSphere( sphere );
47307 size: function ( optionalTarget ) {
47309 console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
47310 return this.getSize( optionalTarget );
47315 Object.assign( Sphere.prototype, {
47317 empty: function () {
47319 console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' );
47320 return this.isEmpty();
47326 Frustum.prototype.setFromMatrix = function ( m ) {
47328 console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' );
47329 return this.setFromProjectionMatrix( m );
47333 Line3.prototype.center = function ( optionalTarget ) {
47335 console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
47336 return this.getCenter( optionalTarget );
47340 Object.assign( MathUtils, {
47342 random16: function () {
47344 console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' );
47345 return Math.random();
47349 nearestPowerOfTwo: function ( value ) {
47351 console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' );
47352 return MathUtils.floorPowerOfTwo( value );
47356 nextPowerOfTwo: function ( value ) {
47358 console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' );
47359 return MathUtils.ceilPowerOfTwo( value );
47365 Object.assign( Matrix3.prototype, {
47367 flattenToArrayOffset: function ( array, offset ) {
47369 console.warn( 'THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
47370 return this.toArray( array, offset );
47373 multiplyVector3: function ( vector ) {
47375 console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
47376 return vector.applyMatrix3( this );
47379 multiplyVector3Array: function ( /* a */ ) {
47381 console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
47384 applyToBufferAttribute: function ( attribute ) {
47386 console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' );
47387 return attribute.applyMatrix3( this );
47390 applyToVector3Array: function ( /* array, offset, length */ ) {
47392 console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
47395 getInverse: function ( matrix ) {
47397 console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
47398 return this.copy( matrix ).invert();
47404 Object.assign( Matrix4.prototype, {
47406 extractPosition: function ( m ) {
47408 console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
47409 return this.copyPosition( m );
47412 flattenToArrayOffset: function ( array, offset ) {
47414 console.warn( 'THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
47415 return this.toArray( array, offset );
47418 getPosition: function () {
47420 console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
47421 return new Vector3().setFromMatrixColumn( this, 3 );
47424 setRotationFromQuaternion: function ( q ) {
47426 console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
47427 return this.makeRotationFromQuaternion( q );
47430 multiplyToArray: function () {
47432 console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
47435 multiplyVector3: function ( vector ) {
47437 console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
47438 return vector.applyMatrix4( this );
47441 multiplyVector4: function ( vector ) {
47443 console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
47444 return vector.applyMatrix4( this );
47447 multiplyVector3Array: function ( /* a */ ) {
47449 console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
47452 rotateAxis: function ( v ) {
47454 console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
47455 v.transformDirection( this );
47458 crossVector: function ( vector ) {
47460 console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
47461 return vector.applyMatrix4( this );
47464 translate: function () {
47466 console.error( 'THREE.Matrix4: .translate() has been removed.' );
47469 rotateX: function () {
47471 console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
47474 rotateY: function () {
47476 console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
47479 rotateZ: function () {
47481 console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
47484 rotateByAxis: function () {
47486 console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
47489 applyToBufferAttribute: function ( attribute ) {
47491 console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' );
47492 return attribute.applyMatrix4( this );
47495 applyToVector3Array: function ( /* array, offset, length */ ) {
47497 console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
47500 makeFrustum: function ( left, right, bottom, top, near, far ) {
47502 console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
47503 return this.makePerspective( left, right, top, bottom, near, far );
47506 getInverse: function ( matrix ) {
47508 console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
47509 return this.copy( matrix ).invert();
47515 Plane.prototype.isIntersectionLine = function ( line ) {
47517 console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
47518 return this.intersectsLine( line );
47522 Object.assign( Quaternion.prototype, {
47524 multiplyVector3: function ( vector ) {
47526 console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
47527 return vector.applyQuaternion( this );
47530 inverse: function ( ) {
47532 console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' );
47533 return this.invert();
47539 Object.assign( Ray.prototype, {
47541 isIntersectionBox: function ( box ) {
47543 console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
47544 return this.intersectsBox( box );
47547 isIntersectionPlane: function ( plane ) {
47549 console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
47550 return this.intersectsPlane( plane );
47553 isIntersectionSphere: function ( sphere ) {
47555 console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
47556 return this.intersectsSphere( sphere );
47562 Object.assign( Triangle.prototype, {
47564 area: function () {
47566 console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
47567 return this.getArea();
47570 barycoordFromPoint: function ( point, target ) {
47572 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
47573 return this.getBarycoord( point, target );
47576 midpoint: function ( target ) {
47578 console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
47579 return this.getMidpoint( target );
47582 normal: function ( target ) {
47584 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
47585 return this.getNormal( target );
47588 plane: function ( target ) {
47590 console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
47591 return this.getPlane( target );
47597 Object.assign( Triangle, {
47599 barycoordFromPoint: function ( point, a, b, c, target ) {
47601 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
47602 return Triangle.getBarycoord( point, a, b, c, target );
47605 normal: function ( a, b, c, target ) {
47607 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
47608 return Triangle.getNormal( a, b, c, target );
47614 Object.assign( Shape.prototype, {
47616 extractAllPoints: function ( divisions ) {
47618 console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
47619 return this.extractPoints( divisions );
47622 extrude: function ( options ) {
47624 console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
47625 return new ExtrudeGeometry( this, options );
47628 makeGeometry: function ( options ) {
47630 console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
47631 return new ShapeGeometry( this, options );
47637 Object.assign( Vector2.prototype, {
47639 fromAttribute: function ( attribute, index, offset ) {
47641 console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
47642 return this.fromBufferAttribute( attribute, index, offset );
47645 distanceToManhattan: function ( v ) {
47647 console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
47648 return this.manhattanDistanceTo( v );
47651 lengthManhattan: function () {
47653 console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
47654 return this.manhattanLength();
47660 Object.assign( Vector3.prototype, {
47662 setEulerFromRotationMatrix: function () {
47664 console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
47667 setEulerFromQuaternion: function () {
47669 console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
47672 getPositionFromMatrix: function ( m ) {
47674 console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
47675 return this.setFromMatrixPosition( m );
47678 getScaleFromMatrix: function ( m ) {
47680 console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
47681 return this.setFromMatrixScale( m );
47684 getColumnFromMatrix: function ( index, matrix ) {
47686 console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
47687 return this.setFromMatrixColumn( matrix, index );
47690 applyProjection: function ( m ) {
47692 console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
47693 return this.applyMatrix4( m );
47696 fromAttribute: function ( attribute, index, offset ) {
47698 console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
47699 return this.fromBufferAttribute( attribute, index, offset );
47702 distanceToManhattan: function ( v ) {
47704 console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
47705 return this.manhattanDistanceTo( v );
47708 lengthManhattan: function () {
47710 console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
47711 return this.manhattanLength();
47717 Object.assign( Vector4.prototype, {
47719 fromAttribute: function ( attribute, index, offset ) {
47721 console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
47722 return this.fromBufferAttribute( attribute, index, offset );
47725 lengthManhattan: function () {
47727 console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
47728 return this.manhattanLength();
47736 Object.assign( Object3D.prototype, {
47738 getChildByName: function ( name ) {
47740 console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
47741 return this.getObjectByName( name );
47744 renderDepth: function () {
47746 console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
47749 translate: function ( distance, axis ) {
47751 console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
47752 return this.translateOnAxis( axis, distance );
47755 getWorldRotation: function () {
47757 console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
47760 applyMatrix: function ( matrix ) {
47762 console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' );
47763 return this.applyMatrix4( matrix );
47769 Object.defineProperties( Object3D.prototype, {
47774 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
47775 return this.rotation.order;
47778 set: function ( value ) {
47780 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
47781 this.rotation.order = value;
47788 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
47793 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
47800 Object.assign( Mesh.prototype, {
47802 setDrawMode: function () {
47804 console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
47810 Object.defineProperties( Mesh.prototype, {
47815 console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' );
47816 return TrianglesDrawMode;
47821 console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
47828 Object.defineProperties( LOD.prototype, {
47833 console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
47834 return this.levels;
47841 Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
47845 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
47850 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
47856 SkinnedMesh.prototype.initBones = function () {
47858 console.error( 'THREE.SkinnedMesh: initBones() has been removed.' );
47862 Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
47866 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
47867 return this.arcLengthDivisions;
47870 set: function ( value ) {
47872 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
47873 this.arcLengthDivisions = value;
47881 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
47883 console.warn( 'THREE.PerspectiveCamera.setLens is deprecated. ' +
47884 'Use .setFocalLength and .filmGauge for a photographic setup.' );
47886 if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
47887 this.setFocalLength( focalLength );
47893 Object.defineProperties( Light.prototype, {
47897 console.warn( 'THREE.Light: .onlyShadow has been removed.' );
47902 set: function ( value ) {
47904 console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
47905 this.shadow.camera.fov = value;
47909 shadowCameraLeft: {
47910 set: function ( value ) {
47912 console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
47913 this.shadow.camera.left = value;
47917 shadowCameraRight: {
47918 set: function ( value ) {
47920 console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
47921 this.shadow.camera.right = value;
47926 set: function ( value ) {
47928 console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
47929 this.shadow.camera.top = value;
47933 shadowCameraBottom: {
47934 set: function ( value ) {
47936 console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
47937 this.shadow.camera.bottom = value;
47941 shadowCameraNear: {
47942 set: function ( value ) {
47944 console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
47945 this.shadow.camera.near = value;
47950 set: function ( value ) {
47952 console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
47953 this.shadow.camera.far = value;
47957 shadowCameraVisible: {
47960 console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
47965 set: function ( value ) {
47967 console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
47968 this.shadow.bias = value;
47975 console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
47980 set: function ( value ) {
47982 console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
47983 this.shadow.mapSize.width = value;
47988 set: function ( value ) {
47990 console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
47991 this.shadow.mapSize.height = value;
47999 Object.defineProperties( BufferAttribute.prototype, {
48004 console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
48005 return this.array.length;
48012 console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
48013 return this.usage === DynamicDrawUsage;
48016 set: function ( /* value */ ) {
48018 console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
48019 this.setUsage( DynamicDrawUsage );
48026 Object.assign( BufferAttribute.prototype, {
48027 setDynamic: function ( value ) {
48029 console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' );
48030 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
48034 copyIndicesArray: function ( /* indices */ ) {
48036 console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
48039 setArray: function ( /* array */ ) {
48041 console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
48046 Object.assign( BufferGeometry.prototype, {
48048 addIndex: function ( index ) {
48050 console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
48051 this.setIndex( index );
48054 addAttribute: function ( name, attribute ) {
48056 console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' );
48058 if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
48060 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
48062 return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
48066 if ( name === 'index' ) {
48068 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
48069 this.setIndex( attribute );
48075 return this.setAttribute( name, attribute );
48078 addDrawCall: function ( start, count, indexOffset ) {
48080 if ( indexOffset !== undefined ) {
48082 console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
48086 console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
48087 this.addGroup( start, count );
48090 clearDrawCalls: function () {
48092 console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
48093 this.clearGroups();
48096 computeOffsets: function () {
48098 console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
48101 removeAttribute: function ( name ) {
48103 console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' );
48105 return this.deleteAttribute( name );
48108 applyMatrix: function ( matrix ) {
48110 console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' );
48111 return this.applyMatrix4( matrix );
48117 Object.defineProperties( BufferGeometry.prototype, {
48122 console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
48123 return this.groups;
48130 console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
48131 return this.groups;
48138 Object.defineProperties( InstancedBufferGeometry.prototype, {
48140 maxInstancedCount: {
48143 console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
48144 return this.instanceCount;
48147 set: function ( value ) {
48149 console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
48150 this.instanceCount = value;
48157 Object.defineProperties( Raycaster.prototype, {
48162 console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
48163 return this.params.Line.threshold;
48166 set: function ( value ) {
48168 console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
48169 this.params.Line.threshold = value;
48176 Object.defineProperties( InterleavedBuffer.prototype, {
48181 console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
48182 return this.usage === DynamicDrawUsage;
48185 set: function ( value ) {
48187 console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
48188 this.setUsage( value );
48195 Object.assign( InterleavedBuffer.prototype, {
48196 setDynamic: function ( value ) {
48198 console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' );
48199 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
48203 setArray: function ( /* array */ ) {
48205 console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
48212 Object.assign( ExtrudeGeometry.prototype, {
48214 getArrays: function () {
48216 console.error( 'THREE.ExtrudeGeometry: .getArrays() has been removed.' );
48220 addShapeList: function () {
48222 console.error( 'THREE.ExtrudeGeometry: .addShapeList() has been removed.' );
48226 addShape: function () {
48228 console.error( 'THREE.ExtrudeGeometry: .addShape() has been removed.' );
48236 Object.assign( Scene.prototype, {
48238 dispose: function () {
48240 console.error( 'THREE.Scene: .dispose() has been removed.' );
48248 Object.defineProperties( Uniform.prototype, {
48253 console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
48258 value: function () {
48260 console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
48270 Object.defineProperties( Material.prototype, {
48275 console.warn( 'THREE.Material: .wrapAround has been removed.' );
48280 console.warn( 'THREE.Material: .wrapAround has been removed.' );
48288 console.warn( 'THREE.Material: .overdraw has been removed.' );
48293 console.warn( 'THREE.Material: .overdraw has been removed.' );
48301 console.warn( 'THREE.Material: .wrapRGB has been removed.' );
48302 return new Color();
48310 console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
48313 set: function ( value ) {
48315 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
48316 this.flatShading = ( value === FlatShading );
48324 console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
48325 return this.stencilFuncMask;
48328 set: function ( value ) {
48330 console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
48331 this.stencilFuncMask = value;
48338 Object.defineProperties( MeshPhongMaterial.prototype, {
48343 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
48349 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
48356 Object.defineProperties( MeshPhysicalMaterial.prototype, {
48361 console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
48362 return this.transmission;
48365 set: function ( value ) {
48367 console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
48368 this.transmission = value;
48375 Object.defineProperties( ShaderMaterial.prototype, {
48380 console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
48381 return this.extensions.derivatives;
48384 set: function ( value ) {
48386 console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
48387 this.extensions.derivatives = value;
48396 Object.assign( WebGLRenderer.prototype, {
48398 clearTarget: function ( renderTarget, color, depth, stencil ) {
48400 console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' );
48401 this.setRenderTarget( renderTarget );
48402 this.clear( color, depth, stencil );
48405 animate: function ( callback ) {
48407 console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
48408 this.setAnimationLoop( callback );
48411 getCurrentRenderTarget: function () {
48413 console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
48414 return this.getRenderTarget();
48417 getMaxAnisotropy: function () {
48419 console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
48420 return this.capabilities.getMaxAnisotropy();
48423 getPrecision: function () {
48425 console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
48426 return this.capabilities.precision;
48429 resetGLState: function () {
48431 console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
48432 return this.state.reset();
48435 supportsFloatTextures: function () {
48437 console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
48438 return this.extensions.get( 'OES_texture_float' );
48441 supportsHalfFloatTextures: function () {
48443 console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
48444 return this.extensions.get( 'OES_texture_half_float' );
48447 supportsStandardDerivatives: function () {
48449 console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
48450 return this.extensions.get( 'OES_standard_derivatives' );
48453 supportsCompressedTextureS3TC: function () {
48455 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
48456 return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
48459 supportsCompressedTexturePVRTC: function () {
48461 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
48462 return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
48465 supportsBlendMinMax: function () {
48467 console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
48468 return this.extensions.get( 'EXT_blend_minmax' );
48471 supportsVertexTextures: function () {
48473 console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
48474 return this.capabilities.vertexTextures;
48477 supportsInstancedArrays: function () {
48479 console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
48480 return this.extensions.get( 'ANGLE_instanced_arrays' );
48483 enableScissorTest: function ( boolean ) {
48485 console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
48486 this.setScissorTest( boolean );
48489 initMaterial: function () {
48491 console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
48494 addPrePlugin: function () {
48496 console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
48499 addPostPlugin: function () {
48501 console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
48504 updateShadowMap: function () {
48506 console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
48509 setFaceCulling: function () {
48511 console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
48514 allocTextureUnit: function () {
48516 console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' );
48519 setTexture: function () {
48521 console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' );
48524 setTexture2D: function () {
48526 console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' );
48529 setTextureCube: function () {
48531 console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' );
48534 getActiveMipMapLevel: function () {
48536 console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' );
48537 return this.getActiveMipmapLevel();
48543 Object.defineProperties( WebGLRenderer.prototype, {
48545 shadowMapEnabled: {
48548 return this.shadowMap.enabled;
48551 set: function ( value ) {
48553 console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
48554 this.shadowMap.enabled = value;
48561 return this.shadowMap.type;
48564 set: function ( value ) {
48566 console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
48567 this.shadowMap.type = value;
48571 shadowMapCullFace: {
48574 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
48578 set: function ( /* value */ ) {
48580 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
48587 console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' );
48588 return this.getContext();
48595 console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' );
48603 console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
48609 console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
48616 console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
48620 set: function ( value ) {
48622 console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
48623 this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding;
48627 toneMappingWhitePoint: {
48630 console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
48636 console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
48643 Object.defineProperties( WebGLShadowMap.prototype, {
48648 console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
48652 set: function ( /* cullFace */ ) {
48654 console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
48658 renderReverseSided: {
48661 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
48667 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
48671 renderSingleSided: {
48674 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
48680 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
48687 function WebGLRenderTargetCube( width, height, options ) {
48689 console.warn( 'THREE.WebGLRenderTargetCube( width, height, options ) is now WebGLCubeRenderTarget( size, options ).' );
48690 return new WebGLCubeRenderTarget( width, options );
48696 Object.defineProperties( WebGLRenderTarget.prototype, {
48701 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
48702 return this.texture.wrapS;
48705 set: function ( value ) {
48707 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
48708 this.texture.wrapS = value;
48715 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
48716 return this.texture.wrapT;
48719 set: function ( value ) {
48721 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
48722 this.texture.wrapT = value;
48729 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
48730 return this.texture.magFilter;
48733 set: function ( value ) {
48735 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
48736 this.texture.magFilter = value;
48743 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
48744 return this.texture.minFilter;
48747 set: function ( value ) {
48749 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
48750 this.texture.minFilter = value;
48757 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
48758 return this.texture.anisotropy;
48761 set: function ( value ) {
48763 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
48764 this.texture.anisotropy = value;
48771 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
48772 return this.texture.offset;
48775 set: function ( value ) {
48777 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
48778 this.texture.offset = value;
48785 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
48786 return this.texture.repeat;
48789 set: function ( value ) {
48791 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
48792 this.texture.repeat = value;
48799 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
48800 return this.texture.format;
48803 set: function ( value ) {
48805 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
48806 this.texture.format = value;
48813 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
48814 return this.texture.type;
48817 set: function ( value ) {
48819 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
48820 this.texture.type = value;
48827 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
48828 return this.texture.generateMipmaps;
48831 set: function ( value ) {
48833 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
48834 this.texture.generateMipmaps = value;
48843 Object.defineProperties( Audio.prototype, {
48846 value: function ( file ) {
48848 console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
48849 const scope = this;
48850 const audioLoader = new AudioLoader();
48851 audioLoader.load( file, function ( buffer ) {
48853 scope.setBuffer( buffer );
48863 console.warn( 'THREE.Audio: .startTime is now .play( delay ).' );
48870 AudioAnalyser.prototype.getData = function () {
48872 console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
48873 return this.getFrequencyData();
48879 CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
48881 console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
48882 return this.update( renderer, scene );
48886 CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) {
48888 console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' );
48889 return this.renderTarget.clear( renderer, color, depth, stencil );
48895 const GeometryUtils = {
48897 merge: function ( geometry1, geometry2, materialIndexOffset ) {
48899 console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
48902 if ( geometry2.isMesh ) {
48904 geometry2.matrixAutoUpdate && geometry2.updateMatrix();
48906 matrix = geometry2.matrix;
48907 geometry2 = geometry2.geometry;
48911 geometry1.merge( geometry2, matrix, materialIndexOffset );
48915 center: function ( geometry ) {
48917 console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
48918 return geometry.center();
48924 ImageUtils.crossOrigin = undefined;
48926 ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) {
48928 console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
48930 const loader = new TextureLoader();
48931 loader.setCrossOrigin( this.crossOrigin );
48933 const texture = loader.load( url, onLoad, undefined, onError );
48935 if ( mapping ) texture.mapping = mapping;
48941 ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) {
48943 console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
48945 const loader = new CubeTextureLoader();
48946 loader.setCrossOrigin( this.crossOrigin );
48948 const texture = loader.load( urls, onLoad, undefined, onError );
48950 if ( mapping ) texture.mapping = mapping;
48956 ImageUtils.loadCompressedTexture = function () {
48958 console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
48962 ImageUtils.loadCompressedTextureCube = function () {
48964 console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
48970 function CanvasRenderer() {
48972 console.error( 'THREE.CanvasRenderer has been removed' );
48978 function JSONLoader() {
48980 console.error( 'THREE.JSONLoader has been removed.' );
48986 const SceneUtils = {
48988 createMultiMaterialObject: function ( /* geometry, materials */ ) {
48990 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
48994 detach: function ( /* child, parent, scene */ ) {
48996 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
49000 attach: function ( /* child, scene, parent */ ) {
49002 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
49010 function LensFlare() {
49012 console.error( 'THREE.LensFlare has been moved to /examples/jsm/objects/Lensflare.js' );
49016 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
49018 /* eslint-disable no-undef */
49019 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
49020 revision: REVISION,
49022 /* eslint-enable no-undef */
49026 if ( typeof window !== 'undefined' ) {
49028 if ( window.__THREE__ ) {
49030 console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
49034 window.__THREE__ = REVISION;
49040 export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AlphaFormat, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightProbe, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, AxisHelper, BackSide, BasicDepthPacking, BasicShadowMap, BinaryTextureLoader, Bone, BooleanKeyframeTrack, BoundingBoxHelper, Box2, Box3, Box3Helper, BoxGeometry as BoxBufferGeometry, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasRenderer, CanvasTexture, CatmullRomCurve3, CineonToneMapping, CircleGeometry as CircleBufferGeometry, CircleGeometry, ClampToEdgeWrapping, Clock, ClosedSplineCurve3, Color, ColorKeyframeTrack, CompressedTexture, CompressedTextureLoader, ConeGeometry as ConeBufferGeometry, ConeGeometry, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubeUVRefractionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry as CylinderBufferGeometry, CylinderGeometry, Cylindrical, DataTexture, DataTexture2DArray, DataTexture3D, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry as DodecahedronBufferGeometry, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicBufferAttribute, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EdgesHelper, EllipseCurve, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry as ExtrudeBufferGeometry, ExtrudeGeometry, Face3, Face4, FaceColors, FileLoader, FlatShading, Float16BufferAttribute, Float32Attribute, Float32BufferAttribute, Float64Attribute, Float64BufferAttribute, FloatType, Fog, FogExp2, Font, FontLoader, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GammaEncoding, GeometryUtils, GreaterDepth, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, HemisphereLightProbe, IcosahedronGeometry as IcosahedronBufferGeometry, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, ImmediateRenderObject, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16Attribute, Int16BufferAttribute, Int32Attribute, Int32BufferAttribute, Int8Attribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, JSONLoader, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry as LatheBufferGeometry, LatheGeometry, Layers, LensFlare, LessDepth, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LinePieces, LineSegments, LineStrip, LinearEncoding, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearToneMapping, Loader, LoaderUtils, LoadingManager, LogLuvEncoding, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils as Math, MathUtils, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshFaceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiMaterial, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverDepth, NeverStencilFunc, NoBlending, NoColors, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry as OctahedronBufferGeometry, OctahedronGeometry, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, ParametricGeometry as ParametricBufferGeometry, ParametricGeometry, Particle, ParticleBasicMaterial, ParticleSystem, ParticleSystemMaterial, Path, PerspectiveCamera, Plane, PlaneGeometry as PlaneBufferGeometry, PlaneGeometry, PlaneHelper, PointCloud, PointCloudMaterial, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry as PolyhedronBufferGeometry, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, 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, RGBDEncoding, RGBEEncoding, RGBEFormat, RGBFormat, RGBIntegerFormat, RGBM16Encoding, RGBM7Encoding, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry as RingBufferGeometry, RingGeometry, SRGB8_ALPHA8_ASTC_10x10_Format, SRGB8_ALPHA8_ASTC_10x5_Format, SRGB8_ALPHA8_ASTC_10x6_Format, SRGB8_ALPHA8_ASTC_10x8_Format, SRGB8_ALPHA8_ASTC_12x10_Format, SRGB8_ALPHA8_ASTC_12x12_Format, SRGB8_ALPHA8_ASTC_4x4_Format, SRGB8_ALPHA8_ASTC_5x4_Format, SRGB8_ALPHA8_ASTC_5x5_Format, SRGB8_ALPHA8_ASTC_6x5_Format, SRGB8_ALPHA8_ASTC_6x6_Format, SRGB8_ALPHA8_ASTC_8x5_Format, SRGB8_ALPHA8_ASTC_8x6_Format, SRGB8_ALPHA8_ASTC_8x8_Format, Scene, SceneUtils, ShaderChunk, ShaderLib, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry as ShapeBufferGeometry, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, SmoothShading, Sphere, SphereGeometry as SphereBufferGeometry, SphereGeometry, Spherical, SphericalHarmonics3, Spline, SplineCurve, SplineCurve3, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry as TetrahedronBufferGeometry, TetrahedronGeometry, TextGeometry as TextBufferGeometry, TextGeometry, Texture, TextureLoader, TorusGeometry as TorusBufferGeometry, TorusGeometry, TorusKnotGeometry as TorusKnotBufferGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry as TubeBufferGeometry, TubeGeometry, UVMapping, Uint16Attribute, Uint16BufferAttribute, Uint32Attribute, Uint32BufferAttribute, Uint8Attribute, Uint8BufferAttribute, Uint8ClampedAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShort565Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, Vertex, VertexColors, VideoTexture, WebGL1Renderer, WebGLCubeRenderTarget, WebGLMultisampleRenderTarget, WebGLRenderTarget, WebGLRenderTargetCube, WebGLRenderer, WebGLUtils, WireframeGeometry, WireframeHelper, WrapAroundEnding, XHRLoader, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, sRGBEncoding };