2 const REVISION = '123';
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://en.wikipedia.org/wiki/Smoothstep
354 smoothstep: function ( x, min, max ) {
356 if ( x <= min ) return 0;
357 if ( x >= max ) return 1;
359 x = ( x - min ) / ( max - min );
361 return x * x * ( 3 - 2 * x );
365 smootherstep: function ( x, min, max ) {
367 if ( x <= min ) return 0;
368 if ( x >= max ) return 1;
370 x = ( x - min ) / ( max - min );
372 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
376 // Random integer from <low, high> interval
378 randInt: function ( low, high ) {
380 return low + Math.floor( Math.random() * ( high - low + 1 ) );
384 // Random float from <low, high> interval
386 randFloat: function ( low, high ) {
388 return low + Math.random() * ( high - low );
392 // Random float from <-range/2, range/2> interval
394 randFloatSpread: function ( range ) {
396 return range * ( 0.5 - Math.random() );
400 // Deterministic pseudo-random float in the interval [ 0, 1 ]
402 seededRandom: function ( s ) {
404 if ( s !== undefined ) _seed = s % 2147483647;
406 // Park-Miller algorithm
408 _seed = _seed * 16807 % 2147483647;
410 return ( _seed - 1 ) / 2147483646;
414 degToRad: function ( degrees ) {
416 return degrees * MathUtils.DEG2RAD;
420 radToDeg: function ( radians ) {
422 return radians * MathUtils.RAD2DEG;
426 isPowerOfTwo: function ( value ) {
428 return ( value & ( value - 1 ) ) === 0 && value !== 0;
432 ceilPowerOfTwo: function ( value ) {
434 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
438 floorPowerOfTwo: function ( value ) {
440 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
444 setQuaternionFromProperEuler: function ( q, a, b, c, order ) {
446 // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
448 // rotations are applied to the axes in the order specified by 'order'
449 // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
450 // angles are in radians
452 const cos = Math.cos;
453 const sin = Math.sin;
455 const c2 = cos( b / 2 );
456 const s2 = sin( b / 2 );
458 const c13 = cos( ( a + c ) / 2 );
459 const s13 = sin( ( a + c ) / 2 );
461 const c1_3 = cos( ( a - c ) / 2 );
462 const s1_3 = sin( ( a - c ) / 2 );
464 const c3_1 = cos( ( c - a ) / 2 );
465 const s3_1 = sin( ( c - a ) / 2 );
470 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
474 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
478 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
482 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
486 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
490 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
494 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
504 constructor( x = 0, y = 0 ) {
506 Object.defineProperty( this, 'isVector2', { value: true } );
531 set height( value ) {
546 setScalar( scalar ) {
571 setComponent( index, value ) {
575 case 0: this.x = value; break;
576 case 1: this.y = value; break;
577 default: throw new Error( 'index is out of range: ' + index );
585 getComponent( index ) {
589 case 0: return this.x;
590 case 1: return this.y;
591 default: throw new Error( 'index is out of range: ' + index );
599 return new this.constructor( this.x, this.y );
614 if ( w !== undefined ) {
616 console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
617 return this.addVectors( v, w );
646 addScaledVector( v, s ) {
657 if ( w !== undefined ) {
659 console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
660 return this.subVectors( v, w );
698 multiplyScalar( scalar ) {
716 divideScalar( scalar ) {
718 return this.multiplyScalar( 1 / scalar );
724 const x = this.x, y = this.y;
725 const e = m.elements;
727 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
728 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
736 this.x = Math.min( this.x, v.x );
737 this.y = Math.min( this.y, v.y );
745 this.x = Math.max( this.x, v.x );
746 this.y = Math.max( this.y, v.y );
754 // assumes min < max, componentwise
756 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
757 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
763 clampScalar( minVal, maxVal ) {
765 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
766 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
772 clampLength( min, max ) {
774 const length = this.length();
776 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
782 this.x = Math.floor( this.x );
783 this.y = Math.floor( this.y );
791 this.x = Math.ceil( this.x );
792 this.y = Math.ceil( this.y );
800 this.x = Math.round( this.x );
801 this.y = Math.round( this.y );
809 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
810 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
827 return this.x * v.x + this.y * v.y;
833 return this.x * v.y - this.y * v.x;
839 return this.x * this.x + this.y * this.y;
845 return Math.sqrt( this.x * this.x + this.y * this.y );
851 return Math.abs( this.x ) + Math.abs( this.y );
857 return this.divideScalar( this.length() || 1 );
863 // computes the angle in radians with respect to the positive x-axis
865 const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
873 return Math.sqrt( this.distanceToSquared( v ) );
877 distanceToSquared( v ) {
879 const dx = this.x - v.x, dy = this.y - v.y;
880 return dx * dx + dy * dy;
884 manhattanDistanceTo( v ) {
886 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
890 setLength( length ) {
892 return this.normalize().multiplyScalar( length );
898 this.x += ( v.x - this.x ) * alpha;
899 this.y += ( v.y - this.y ) * alpha;
905 lerpVectors( v1, v2, alpha ) {
907 this.x = v1.x + ( v2.x - v1.x ) * alpha;
908 this.y = v1.y + ( v2.y - v1.y ) * alpha;
916 return ( ( v.x === this.x ) && ( v.y === this.y ) );
920 fromArray( array, offset = 0 ) {
922 this.x = array[ offset ];
923 this.y = array[ offset + 1 ];
929 toArray( array = [], offset = 0 ) {
931 array[ offset ] = this.x;
932 array[ offset + 1 ] = this.y;
938 fromBufferAttribute( attribute, index, offset ) {
940 if ( offset !== undefined ) {
942 console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
946 this.x = attribute.getX( index );
947 this.y = attribute.getY( index );
953 rotateAround( center, angle ) {
955 const c = Math.cos( angle ), s = Math.sin( angle );
957 const x = this.x - center.x;
958 const y = this.y - center.y;
960 this.x = x * c - y * s + center.x;
961 this.y = x * s + y * c + center.y;
969 this.x = Math.random();
970 this.y = Math.random();
982 Object.defineProperty( this, 'isMatrix3', { value: true } );
992 if ( arguments.length > 0 ) {
994 console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
1000 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1002 const te = this.elements;
1004 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
1005 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
1006 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
1028 return new this.constructor().fromArray( this.elements );
1034 const te = this.elements;
1035 const me = m.elements;
1037 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
1038 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
1039 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
1045 extractBasis( xAxis, yAxis, zAxis ) {
1047 xAxis.setFromMatrix3Column( this, 0 );
1048 yAxis.setFromMatrix3Column( this, 1 );
1049 zAxis.setFromMatrix3Column( this, 2 );
1055 setFromMatrix4( m ) {
1057 const me = m.elements;
1061 me[ 0 ], me[ 4 ], me[ 8 ],
1062 me[ 1 ], me[ 5 ], me[ 9 ],
1063 me[ 2 ], me[ 6 ], me[ 10 ]
1073 return this.multiplyMatrices( this, m );
1079 return this.multiplyMatrices( m, this );
1083 multiplyMatrices( a, b ) {
1085 const ae = a.elements;
1086 const be = b.elements;
1087 const te = this.elements;
1089 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
1090 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
1091 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
1093 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
1094 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
1095 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
1097 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
1098 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
1099 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
1101 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
1102 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
1103 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
1105 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
1106 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
1107 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
1113 multiplyScalar( s ) {
1115 const te = this.elements;
1117 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
1118 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
1119 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
1127 const te = this.elements;
1129 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
1130 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
1131 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
1133 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
1139 const te = this.elements,
1141 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
1142 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
1143 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
1145 t11 = n33 * n22 - n32 * n23,
1146 t12 = n32 * n13 - n33 * n12,
1147 t13 = n23 * n12 - n22 * n13,
1149 det = n11 * t11 + n21 * t12 + n31 * t13;
1151 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1153 const detInv = 1 / det;
1155 te[ 0 ] = t11 * detInv;
1156 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
1157 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
1159 te[ 3 ] = t12 * detInv;
1160 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
1161 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
1163 te[ 6 ] = t13 * detInv;
1164 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
1165 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
1174 const m = this.elements;
1176 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
1177 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
1178 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
1184 getNormalMatrix( matrix4 ) {
1186 return this.setFromMatrix4( matrix4 ).copy( this ).invert().transpose();
1190 transposeIntoArray( r ) {
1192 const m = this.elements;
1208 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
1210 const c = Math.cos( rotation );
1211 const s = Math.sin( rotation );
1214 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
1215 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
1223 const te = this.elements;
1225 te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
1226 te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
1234 const c = Math.cos( theta );
1235 const s = Math.sin( theta );
1237 const te = this.elements;
1239 const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
1240 const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
1242 te[ 0 ] = c * a11 + s * a21;
1243 te[ 3 ] = c * a12 + s * a22;
1244 te[ 6 ] = c * a13 + s * a23;
1246 te[ 1 ] = - s * a11 + c * a21;
1247 te[ 4 ] = - s * a12 + c * a22;
1248 te[ 7 ] = - s * a13 + c * a23;
1254 translate( tx, ty ) {
1256 const te = this.elements;
1258 te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
1259 te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
1267 const te = this.elements;
1268 const me = matrix.elements;
1270 for ( let i = 0; i < 9; i ++ ) {
1272 if ( te[ i ] !== me[ i ] ) return false;
1280 fromArray( array, offset = 0 ) {
1282 for ( let i = 0; i < 9; i ++ ) {
1284 this.elements[ i ] = array[ i + offset ];
1292 toArray( array = [], offset = 0 ) {
1294 const te = this.elements;
1296 array[ offset ] = te[ 0 ];
1297 array[ offset + 1 ] = te[ 1 ];
1298 array[ offset + 2 ] = te[ 2 ];
1300 array[ offset + 3 ] = te[ 3 ];
1301 array[ offset + 4 ] = te[ 4 ];
1302 array[ offset + 5 ] = te[ 5 ];
1304 array[ offset + 6 ] = te[ 6 ];
1305 array[ offset + 7 ] = te[ 7 ];
1306 array[ offset + 8 ] = te[ 8 ];
1316 const ImageUtils = {
1318 getDataURL: function ( image ) {
1320 if ( /^data:/i.test( image.src ) ) {
1326 if ( typeof HTMLCanvasElement == 'undefined' ) {
1334 if ( image instanceof HTMLCanvasElement ) {
1340 if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
1342 _canvas.width = image.width;
1343 _canvas.height = image.height;
1345 const context = _canvas.getContext( '2d' );
1347 if ( image instanceof ImageData ) {
1349 context.putImageData( image, 0, 0 );
1353 context.drawImage( image, 0, 0, image.width, image.height );
1361 if ( canvas.width > 2048 || canvas.height > 2048 ) {
1363 return canvas.toDataURL( 'image/jpeg', 0.6 );
1367 return canvas.toDataURL( 'image/png' );
1377 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 ) {
1379 Object.defineProperty( this, 'id', { value: textureId ++ } );
1381 this.uuid = MathUtils.generateUUID();
1388 this.mapping = mapping;
1393 this.magFilter = magFilter;
1394 this.minFilter = minFilter;
1396 this.anisotropy = anisotropy;
1398 this.format = format;
1399 this.internalFormat = null;
1402 this.offset = new Vector2( 0, 0 );
1403 this.repeat = new Vector2( 1, 1 );
1404 this.center = new Vector2( 0, 0 );
1407 this.matrixAutoUpdate = true;
1408 this.matrix = new Matrix3();
1410 this.generateMipmaps = true;
1411 this.premultiplyAlpha = false;
1413 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
1415 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
1417 // Also changing the encoding after already used by a Material will not automatically make the Material
1418 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
1419 this.encoding = encoding;
1422 this.onUpdate = null;
1426 Texture.DEFAULT_IMAGE = undefined;
1427 Texture.DEFAULT_MAPPING = UVMapping;
1429 Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
1431 constructor: Texture,
1435 updateMatrix: function () {
1437 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
1441 clone: function () {
1443 return new this.constructor().copy( this );
1447 copy: function ( source ) {
1449 this.name = source.name;
1451 this.image = source.image;
1452 this.mipmaps = source.mipmaps.slice( 0 );
1454 this.mapping = source.mapping;
1456 this.wrapS = source.wrapS;
1457 this.wrapT = source.wrapT;
1459 this.magFilter = source.magFilter;
1460 this.minFilter = source.minFilter;
1462 this.anisotropy = source.anisotropy;
1464 this.format = source.format;
1465 this.internalFormat = source.internalFormat;
1466 this.type = source.type;
1468 this.offset.copy( source.offset );
1469 this.repeat.copy( source.repeat );
1470 this.center.copy( source.center );
1471 this.rotation = source.rotation;
1473 this.matrixAutoUpdate = source.matrixAutoUpdate;
1474 this.matrix.copy( source.matrix );
1476 this.generateMipmaps = source.generateMipmaps;
1477 this.premultiplyAlpha = source.premultiplyAlpha;
1478 this.flipY = source.flipY;
1479 this.unpackAlignment = source.unpackAlignment;
1480 this.encoding = source.encoding;
1486 toJSON: function ( meta ) {
1488 const isRootObject = ( meta === undefined || typeof meta === 'string' );
1490 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
1492 return meta.textures[ this.uuid ];
1501 generator: 'Texture.toJSON'
1507 mapping: this.mapping,
1509 repeat: [ this.repeat.x, this.repeat.y ],
1510 offset: [ this.offset.x, this.offset.y ],
1511 center: [ this.center.x, this.center.y ],
1512 rotation: this.rotation,
1514 wrap: [ this.wrapS, this.wrapT ],
1516 format: this.format,
1518 encoding: this.encoding,
1520 minFilter: this.minFilter,
1521 magFilter: this.magFilter,
1522 anisotropy: this.anisotropy,
1526 premultiplyAlpha: this.premultiplyAlpha,
1527 unpackAlignment: this.unpackAlignment
1531 if ( this.image !== undefined ) {
1533 // TODO: Move to THREE.Image
1535 const image = this.image;
1537 if ( image.uuid === undefined ) {
1539 image.uuid = MathUtils.generateUUID(); // UGH
1543 if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
1547 if ( Array.isArray( image ) ) {
1549 // process array of images e.g. CubeTexture
1553 for ( let i = 0, l = image.length; i < l; i ++ ) {
1555 // check cube texture with data textures
1557 if ( image[ i ].isDataTexture ) {
1559 url.push( serializeImage( image[ i ].image ) );
1563 url.push( serializeImage( image[ i ] ) );
1571 // process single image
1573 url = serializeImage( image );
1577 meta.images[ image.uuid ] = {
1584 output.image = image.uuid;
1588 if ( ! isRootObject ) {
1590 meta.textures[ this.uuid ] = output;
1598 dispose: function () {
1600 this.dispatchEvent( { type: 'dispose' } );
1604 transformUv: function ( uv ) {
1606 if ( this.mapping !== UVMapping ) return uv;
1608 uv.applyMatrix3( this.matrix );
1610 if ( uv.x < 0 || uv.x > 1 ) {
1612 switch ( this.wrapS ) {
1614 case RepeatWrapping:
1616 uv.x = uv.x - Math.floor( uv.x );
1619 case ClampToEdgeWrapping:
1621 uv.x = uv.x < 0 ? 0 : 1;
1624 case MirroredRepeatWrapping:
1626 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
1628 uv.x = Math.ceil( uv.x ) - uv.x;
1632 uv.x = uv.x - Math.floor( uv.x );
1642 if ( uv.y < 0 || uv.y > 1 ) {
1644 switch ( this.wrapT ) {
1646 case RepeatWrapping:
1648 uv.y = uv.y - Math.floor( uv.y );
1651 case ClampToEdgeWrapping:
1653 uv.y = uv.y < 0 ? 0 : 1;
1656 case MirroredRepeatWrapping:
1658 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
1660 uv.y = Math.ceil( uv.y ) - uv.y;
1664 uv.y = uv.y - Math.floor( uv.y );
1686 Object.defineProperty( Texture.prototype, "needsUpdate", {
1688 set: function ( value ) {
1690 if ( value === true ) this.version ++;
1696 function serializeImage( image ) {
1698 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1699 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
1700 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1704 return ImageUtils.getDataURL( image );
1710 // images of DataTexture
1713 data: Array.prototype.slice.call( image.data ),
1715 height: image.height,
1716 type: image.data.constructor.name
1721 console.warn( 'THREE.Texture: Unable to serialize Texture.' );
1732 constructor( x = 0, y = 0, z = 0, w = 1 ) {
1734 Object.defineProperty( this, 'isVector4', { value: true } );
1749 set width( value ) {
1761 set height( value ) {
1778 setScalar( scalar ) {
1821 setComponent( index, value ) {
1825 case 0: this.x = value; break;
1826 case 1: this.y = value; break;
1827 case 2: this.z = value; break;
1828 case 3: this.w = value; break;
1829 default: throw new Error( 'index is out of range: ' + index );
1837 getComponent( index ) {
1841 case 0: return this.x;
1842 case 1: return this.y;
1843 case 2: return this.z;
1844 case 3: return this.w;
1845 default: throw new Error( 'index is out of range: ' + index );
1853 return new this.constructor( this.x, this.y, this.z, this.w );
1862 this.w = ( v.w !== undefined ) ? v.w : 1;
1870 if ( w !== undefined ) {
1872 console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
1873 return this.addVectors( v, w );
1897 addVectors( a, b ) {
1908 addScaledVector( v, s ) {
1921 if ( w !== undefined ) {
1923 console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
1924 return this.subVectors( v, w );
1948 subVectors( a, b ) {
1959 multiplyScalar( scalar ) {
1972 const x = this.x, y = this.y, z = this.z, w = this.w;
1973 const e = m.elements;
1975 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
1976 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
1977 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
1978 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
1984 divideScalar( scalar ) {
1986 return this.multiplyScalar( 1 / scalar );
1990 setAxisAngleFromQuaternion( q ) {
1992 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
1994 // q is assumed to be normalized
1996 this.w = 2 * Math.acos( q.w );
1998 const s = Math.sqrt( 1 - q.w * q.w );
2018 setAxisAngleFromRotationMatrix( m ) {
2020 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
2022 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2024 let angle, x, y, z; // variables for result
2025 const epsilon = 0.01, // margin to allow for rounding errors
2026 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
2030 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2031 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2032 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
2034 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
2035 ( Math.abs( m13 - m31 ) < epsilon ) &&
2036 ( Math.abs( m23 - m32 ) < epsilon ) ) {
2038 // singularity found
2039 // first check for identity matrix which must have +1 for all terms
2040 // in leading diagonal and zero in other terms
2042 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
2043 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
2044 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
2045 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
2047 // this singularity is identity matrix so angle = 0
2049 this.set( 1, 0, 0, 0 );
2051 return this; // zero angle, arbitrary axis
2055 // otherwise this singularity is angle = 180
2059 const xx = ( m11 + 1 ) / 2;
2060 const yy = ( m22 + 1 ) / 2;
2061 const zz = ( m33 + 1 ) / 2;
2062 const xy = ( m12 + m21 ) / 4;
2063 const xz = ( m13 + m31 ) / 4;
2064 const yz = ( m23 + m32 ) / 4;
2066 if ( ( xx > yy ) && ( xx > zz ) ) {
2068 // m11 is the largest diagonal term
2070 if ( xx < epsilon ) {
2078 x = Math.sqrt( xx );
2084 } else if ( yy > zz ) {
2086 // m22 is the largest diagonal term
2088 if ( yy < epsilon ) {
2096 y = Math.sqrt( yy );
2104 // m33 is the largest diagonal term so base result on this
2106 if ( zz < epsilon ) {
2114 z = Math.sqrt( zz );
2122 this.set( x, y, z, angle );
2124 return this; // return 180 deg rotation
2128 // as we have reached here there are no singularities so we can handle normally
2130 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
2131 ( m13 - m31 ) * ( m13 - m31 ) +
2132 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
2134 if ( Math.abs( s ) < 0.001 ) s = 1;
2136 // prevent divide by zero, should not happen if matrix is orthogonal and should be
2137 // caught by singularity test above, but I've left it in just in case
2139 this.x = ( m32 - m23 ) / s;
2140 this.y = ( m13 - m31 ) / s;
2141 this.z = ( m21 - m12 ) / s;
2142 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
2150 this.x = Math.min( this.x, v.x );
2151 this.y = Math.min( this.y, v.y );
2152 this.z = Math.min( this.z, v.z );
2153 this.w = Math.min( this.w, v.w );
2161 this.x = Math.max( this.x, v.x );
2162 this.y = Math.max( this.y, v.y );
2163 this.z = Math.max( this.z, v.z );
2164 this.w = Math.max( this.w, v.w );
2172 // assumes min < max, componentwise
2174 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2175 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2176 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
2177 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
2183 clampScalar( minVal, maxVal ) {
2185 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
2186 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
2187 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
2188 this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
2194 clampLength( min, max ) {
2196 const length = this.length();
2198 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
2204 this.x = Math.floor( this.x );
2205 this.y = Math.floor( this.y );
2206 this.z = Math.floor( this.z );
2207 this.w = Math.floor( this.w );
2215 this.x = Math.ceil( this.x );
2216 this.y = Math.ceil( this.y );
2217 this.z = Math.ceil( this.z );
2218 this.w = Math.ceil( this.w );
2226 this.x = Math.round( this.x );
2227 this.y = Math.round( this.y );
2228 this.z = Math.round( this.z );
2229 this.w = Math.round( this.w );
2237 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
2238 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
2239 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
2240 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
2259 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
2265 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
2271 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
2277 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
2283 return this.divideScalar( this.length() || 1 );
2287 setLength( length ) {
2289 return this.normalize().multiplyScalar( length );
2295 this.x += ( v.x - this.x ) * alpha;
2296 this.y += ( v.y - this.y ) * alpha;
2297 this.z += ( v.z - this.z ) * alpha;
2298 this.w += ( v.w - this.w ) * alpha;
2304 lerpVectors( v1, v2, alpha ) {
2306 this.x = v1.x + ( v2.x - v1.x ) * alpha;
2307 this.y = v1.y + ( v2.y - v1.y ) * alpha;
2308 this.z = v1.z + ( v2.z - v1.z ) * alpha;
2309 this.w = v1.w + ( v2.w - v1.w ) * alpha;
2317 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
2321 fromArray( array, offset = 0 ) {
2323 this.x = array[ offset ];
2324 this.y = array[ offset + 1 ];
2325 this.z = array[ offset + 2 ];
2326 this.w = array[ offset + 3 ];
2332 toArray( array = [], offset = 0 ) {
2334 array[ offset ] = this.x;
2335 array[ offset + 1 ] = this.y;
2336 array[ offset + 2 ] = this.z;
2337 array[ offset + 3 ] = this.w;
2343 fromBufferAttribute( attribute, index, offset ) {
2345 if ( offset !== undefined ) {
2347 console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
2351 this.x = attribute.getX( index );
2352 this.y = attribute.getY( index );
2353 this.z = attribute.getZ( index );
2354 this.w = attribute.getW( index );
2362 this.x = Math.random();
2363 this.y = Math.random();
2364 this.z = Math.random();
2365 this.w = Math.random();
2374 In options, we can specify:
2375 * Texture parameters for an auto-generated target texture
2376 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
2378 function WebGLRenderTarget( width, height, options ) {
2381 this.height = height;
2383 this.scissor = new Vector4( 0, 0, width, height );
2384 this.scissorTest = false;
2386 this.viewport = new Vector4( 0, 0, width, height );
2388 options = options || {};
2390 this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
2392 this.texture.image = {};
2393 this.texture.image.width = width;
2394 this.texture.image.height = height;
2396 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
2397 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
2399 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
2400 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
2401 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
2405 WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
2407 constructor: WebGLRenderTarget,
2409 isWebGLRenderTarget: true,
2411 setSize: function ( width, height ) {
2413 if ( this.width !== width || this.height !== height ) {
2416 this.height = height;
2418 this.texture.image.width = width;
2419 this.texture.image.height = height;
2425 this.viewport.set( 0, 0, width, height );
2426 this.scissor.set( 0, 0, width, height );
2430 clone: function () {
2432 return new this.constructor().copy( this );
2436 copy: function ( source ) {
2438 this.width = source.width;
2439 this.height = source.height;
2441 this.viewport.copy( source.viewport );
2443 this.texture = source.texture.clone();
2445 this.depthBuffer = source.depthBuffer;
2446 this.stencilBuffer = source.stencilBuffer;
2447 this.depthTexture = source.depthTexture;
2453 dispose: function () {
2455 this.dispatchEvent( { type: 'dispose' } );
2461 function WebGLMultisampleRenderTarget( width, height, options ) {
2463 WebGLRenderTarget.call( this, width, height, options );
2469 WebGLMultisampleRenderTarget.prototype = Object.assign( Object.create( WebGLRenderTarget.prototype ), {
2471 constructor: WebGLMultisampleRenderTarget,
2473 isWebGLMultisampleRenderTarget: true,
2475 copy: function ( source ) {
2477 WebGLRenderTarget.prototype.copy.call( this, source );
2479 this.samples = source.samples;
2489 constructor( x = 0, y = 0, z = 0, w = 1 ) {
2491 Object.defineProperty( this, 'isQuaternion', { value: true } );
2500 static slerp( qa, qb, qm, t ) {
2502 return qm.copy( qa ).slerp( qb, t );
2506 static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
2508 // fuzz-free, array-based Quaternion SLERP operation
2510 let x0 = src0[ srcOffset0 + 0 ],
2511 y0 = src0[ srcOffset0 + 1 ],
2512 z0 = src0[ srcOffset0 + 2 ],
2513 w0 = src0[ srcOffset0 + 3 ];
2515 const x1 = src1[ srcOffset1 + 0 ],
2516 y1 = src1[ srcOffset1 + 1 ],
2517 z1 = src1[ srcOffset1 + 2 ],
2518 w1 = src1[ srcOffset1 + 3 ];
2520 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
2523 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
2524 dir = ( cos >= 0 ? 1 : - 1 ),
2525 sqrSin = 1 - cos * cos;
2527 // Skip the Slerp for tiny steps to avoid numeric problems:
2528 if ( sqrSin > Number.EPSILON ) {
2530 const sin = Math.sqrt( sqrSin ),
2531 len = Math.atan2( sin, cos * dir );
2533 s = Math.sin( s * len ) / sin;
2534 t = Math.sin( t * len ) / sin;
2538 const tDir = t * dir;
2540 x0 = x0 * s + x1 * tDir;
2541 y0 = y0 * s + y1 * tDir;
2542 z0 = z0 * s + z1 * tDir;
2543 w0 = w0 * s + w1 * tDir;
2545 // Normalize in case we just did a lerp:
2546 if ( s === 1 - t ) {
2548 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
2559 dst[ dstOffset ] = x0;
2560 dst[ dstOffset + 1 ] = y0;
2561 dst[ dstOffset + 2 ] = z0;
2562 dst[ dstOffset + 3 ] = w0;
2566 static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
2568 const x0 = src0[ srcOffset0 ];
2569 const y0 = src0[ srcOffset0 + 1 ];
2570 const z0 = src0[ srcOffset0 + 2 ];
2571 const w0 = src0[ srcOffset0 + 3 ];
2573 const x1 = src1[ srcOffset1 ];
2574 const y1 = src1[ srcOffset1 + 1 ];
2575 const z1 = src1[ srcOffset1 + 2 ];
2576 const w1 = src1[ srcOffset1 + 3 ];
2578 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
2579 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
2580 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
2581 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
2596 this._onChangeCallback();
2609 this._onChangeCallback();
2622 this._onChangeCallback();
2635 this._onChangeCallback();
2646 this._onChangeCallback();
2654 return new this.constructor( this._x, this._y, this._z, this._w );
2658 copy( quaternion ) {
2660 this._x = quaternion.x;
2661 this._y = quaternion.y;
2662 this._z = quaternion.z;
2663 this._w = quaternion.w;
2665 this._onChangeCallback();
2671 setFromEuler( euler, update ) {
2673 if ( ! ( euler && euler.isEuler ) ) {
2675 throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
2679 const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
2681 // http://www.mathworks.com/matlabcentral/fileexchange/
2682 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
2683 // content/SpinCalc.m
2685 const cos = Math.cos;
2686 const sin = Math.sin;
2688 const c1 = cos( x / 2 );
2689 const c2 = cos( y / 2 );
2690 const c3 = cos( z / 2 );
2692 const s1 = sin( x / 2 );
2693 const s2 = sin( y / 2 );
2694 const s3 = sin( z / 2 );
2699 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2700 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2701 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2702 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2706 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2707 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2708 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2709 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2713 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2714 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2715 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2716 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2720 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2721 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2722 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2723 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2727 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2728 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2729 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2730 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2734 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2735 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2736 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2737 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2741 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
2745 if ( update !== false ) this._onChangeCallback();
2751 setFromAxisAngle( axis, angle ) {
2753 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
2755 // assumes axis is normalized
2757 const halfAngle = angle / 2, s = Math.sin( halfAngle );
2759 this._x = axis.x * s;
2760 this._y = axis.y * s;
2761 this._z = axis.z * s;
2762 this._w = Math.cos( halfAngle );
2764 this._onChangeCallback();
2770 setFromRotationMatrix( m ) {
2772 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
2774 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2776 const te = m.elements,
2778 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2779 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2780 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
2782 trace = m11 + m22 + m33;
2786 const s = 0.5 / Math.sqrt( trace + 1.0 );
2789 this._x = ( m32 - m23 ) * s;
2790 this._y = ( m13 - m31 ) * s;
2791 this._z = ( m21 - m12 ) * s;
2793 } else if ( m11 > m22 && m11 > m33 ) {
2795 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
2797 this._w = ( m32 - m23 ) / s;
2799 this._y = ( m12 + m21 ) / s;
2800 this._z = ( m13 + m31 ) / s;
2802 } else if ( m22 > m33 ) {
2804 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
2806 this._w = ( m13 - m31 ) / s;
2807 this._x = ( m12 + m21 ) / s;
2809 this._z = ( m23 + m32 ) / s;
2813 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
2815 this._w = ( m21 - m12 ) / s;
2816 this._x = ( m13 + m31 ) / s;
2817 this._y = ( m23 + m32 ) / s;
2822 this._onChangeCallback();
2828 setFromUnitVectors( vFrom, vTo ) {
2830 // assumes direction vectors vFrom and vTo are normalized
2832 const EPS = 0.000001;
2834 let r = vFrom.dot( vTo ) + 1;
2840 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
2842 this._x = - vFrom.y;
2850 this._y = - vFrom.z;
2858 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
2860 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
2861 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
2862 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
2867 return this.normalize();
2873 return 2 * Math.acos( Math.abs( MathUtils.clamp( this.dot( q ), - 1, 1 ) ) );
2877 rotateTowards( q, step ) {
2879 const angle = this.angleTo( q );
2881 if ( angle === 0 ) return this;
2883 const t = Math.min( 1, step / angle );
2893 return this.set( 0, 0, 0, 1 );
2899 // quaternion is assumed to have unit length
2901 return this.conjugate();
2911 this._onChangeCallback();
2919 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
2925 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
2931 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
2937 let l = this.length();
2950 this._x = this._x * l;
2951 this._y = this._y * l;
2952 this._z = this._z * l;
2953 this._w = this._w * l;
2957 this._onChangeCallback();
2965 if ( p !== undefined ) {
2967 console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
2968 return this.multiplyQuaternions( q, p );
2972 return this.multiplyQuaternions( this, q );
2978 return this.multiplyQuaternions( q, this );
2982 multiplyQuaternions( a, b ) {
2984 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
2986 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
2987 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
2989 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
2990 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
2991 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
2992 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
2994 this._onChangeCallback();
3002 if ( t === 0 ) return this;
3003 if ( t === 1 ) return this.copy( qb );
3005 const x = this._x, y = this._y, z = this._z, w = this._w;
3007 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
3009 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
3011 if ( cosHalfTheta < 0 ) {
3018 cosHalfTheta = - cosHalfTheta;
3026 if ( cosHalfTheta >= 1.0 ) {
3037 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
3039 if ( sqrSinHalfTheta <= Number.EPSILON ) {
3042 this._w = s * w + t * this._w;
3043 this._x = s * x + t * this._x;
3044 this._y = s * y + t * this._y;
3045 this._z = s * z + t * this._z;
3048 this._onChangeCallback();
3054 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
3055 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
3056 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
3057 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
3059 this._w = ( w * ratioA + this._w * ratioB );
3060 this._x = ( x * ratioA + this._x * ratioB );
3061 this._y = ( y * ratioA + this._y * ratioB );
3062 this._z = ( z * ratioA + this._z * ratioB );
3064 this._onChangeCallback();
3070 equals( quaternion ) {
3072 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
3076 fromArray( array, offset = 0 ) {
3078 this._x = array[ offset ];
3079 this._y = array[ offset + 1 ];
3080 this._z = array[ offset + 2 ];
3081 this._w = array[ offset + 3 ];
3083 this._onChangeCallback();
3089 toArray( array = [], offset = 0 ) {
3091 array[ offset ] = this._x;
3092 array[ offset + 1 ] = this._y;
3093 array[ offset + 2 ] = this._z;
3094 array[ offset + 3 ] = this._w;
3100 fromBufferAttribute( attribute, index ) {
3102 this._x = attribute.getX( index );
3103 this._y = attribute.getY( index );
3104 this._z = attribute.getZ( index );
3105 this._w = attribute.getW( index );
3111 _onChange( callback ) {
3113 this._onChangeCallback = callback;
3119 _onChangeCallback() {}
3125 constructor( x = 0, y = 0, z = 0 ) {
3127 Object.defineProperty( this, 'isVector3', { value: true } );
3137 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
3147 setScalar( scalar ) {
3181 setComponent( index, value ) {
3185 case 0: this.x = value; break;
3186 case 1: this.y = value; break;
3187 case 2: this.z = value; break;
3188 default: throw new Error( 'index is out of range: ' + index );
3196 getComponent( index ) {
3200 case 0: return this.x;
3201 case 1: return this.y;
3202 case 2: return this.z;
3203 default: throw new Error( 'index is out of range: ' + index );
3211 return new this.constructor( this.x, this.y, this.z );
3227 if ( w !== undefined ) {
3229 console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
3230 return this.addVectors( v, w );
3252 addVectors( a, b ) {
3262 addScaledVector( v, s ) {
3274 if ( w !== undefined ) {
3276 console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
3277 return this.subVectors( v, w );
3299 subVectors( a, b ) {
3311 if ( w !== undefined ) {
3313 console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
3314 return this.multiplyVectors( v, w );
3326 multiplyScalar( scalar ) {
3336 multiplyVectors( a, b ) {
3346 applyEuler( euler ) {
3348 if ( ! ( euler && euler.isEuler ) ) {
3350 console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
3354 return this.applyQuaternion( _quaternion.setFromEuler( euler ) );
3358 applyAxisAngle( axis, angle ) {
3360 return this.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) );
3366 const x = this.x, y = this.y, z = this.z;
3367 const e = m.elements;
3369 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
3370 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
3371 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
3377 applyNormalMatrix( m ) {
3379 return this.applyMatrix3( m ).normalize();
3385 const x = this.x, y = this.y, z = this.z;
3386 const e = m.elements;
3388 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
3390 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
3391 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
3392 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
3398 applyQuaternion( q ) {
3400 const x = this.x, y = this.y, z = this.z;
3401 const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
3403 // calculate quat * vector
3405 const ix = qw * x + qy * z - qz * y;
3406 const iy = qw * y + qz * x - qx * z;
3407 const iz = qw * z + qx * y - qy * x;
3408 const iw = - qx * x - qy * y - qz * z;
3410 // calculate result * inverse quat
3412 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
3413 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
3414 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
3422 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
3426 unproject( camera ) {
3428 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
3432 transformDirection( m ) {
3434 // input: THREE.Matrix4 affine matrix
3435 // vector interpreted as a direction
3437 const x = this.x, y = this.y, z = this.z;
3438 const e = m.elements;
3440 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
3441 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
3442 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
3444 return this.normalize();
3458 divideScalar( scalar ) {
3460 return this.multiplyScalar( 1 / scalar );
3466 this.x = Math.min( this.x, v.x );
3467 this.y = Math.min( this.y, v.y );
3468 this.z = Math.min( this.z, v.z );
3476 this.x = Math.max( this.x, v.x );
3477 this.y = Math.max( this.y, v.y );
3478 this.z = Math.max( this.z, v.z );
3486 // assumes min < max, componentwise
3488 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
3489 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
3490 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
3496 clampScalar( minVal, maxVal ) {
3498 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
3499 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
3500 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
3506 clampLength( min, max ) {
3508 const length = this.length();
3510 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
3516 this.x = Math.floor( this.x );
3517 this.y = Math.floor( this.y );
3518 this.z = Math.floor( this.z );
3526 this.x = Math.ceil( this.x );
3527 this.y = Math.ceil( this.y );
3528 this.z = Math.ceil( this.z );
3536 this.x = Math.round( this.x );
3537 this.y = Math.round( this.y );
3538 this.z = Math.round( this.z );
3546 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
3547 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
3548 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
3566 return this.x * v.x + this.y * v.y + this.z * v.z;
3570 // TODO lengthSquared?
3574 return this.x * this.x + this.y * this.y + this.z * this.z;
3580 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
3586 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
3592 return this.divideScalar( this.length() || 1 );
3596 setLength( length ) {
3598 return this.normalize().multiplyScalar( length );
3604 this.x += ( v.x - this.x ) * alpha;
3605 this.y += ( v.y - this.y ) * alpha;
3606 this.z += ( v.z - this.z ) * alpha;
3612 lerpVectors( v1, v2, alpha ) {
3614 this.x = v1.x + ( v2.x - v1.x ) * alpha;
3615 this.y = v1.y + ( v2.y - v1.y ) * alpha;
3616 this.z = v1.z + ( v2.z - v1.z ) * alpha;
3624 if ( w !== undefined ) {
3626 console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
3627 return this.crossVectors( v, w );
3631 return this.crossVectors( this, v );
3635 crossVectors( a, b ) {
3637 const ax = a.x, ay = a.y, az = a.z;
3638 const bx = b.x, by = b.y, bz = b.z;
3640 this.x = ay * bz - az * by;
3641 this.y = az * bx - ax * bz;
3642 this.z = ax * by - ay * bx;
3648 projectOnVector( v ) {
3650 const denominator = v.lengthSq();
3652 if ( denominator === 0 ) return this.set( 0, 0, 0 );
3654 const scalar = v.dot( this ) / denominator;
3656 return this.copy( v ).multiplyScalar( scalar );
3660 projectOnPlane( planeNormal ) {
3662 _vector.copy( this ).projectOnVector( planeNormal );
3664 return this.sub( _vector );
3670 // reflect incident vector off plane orthogonal to normal
3671 // normal is assumed to have unit length
3673 return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
3679 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
3681 if ( denominator === 0 ) return Math.PI / 2;
3683 const theta = this.dot( v ) / denominator;
3685 // clamp, to handle numerical problems
3687 return Math.acos( MathUtils.clamp( theta, - 1, 1 ) );
3693 return Math.sqrt( this.distanceToSquared( v ) );
3697 distanceToSquared( v ) {
3699 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
3701 return dx * dx + dy * dy + dz * dz;
3705 manhattanDistanceTo( v ) {
3707 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
3711 setFromSpherical( s ) {
3713 return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
3717 setFromSphericalCoords( radius, phi, theta ) {
3719 const sinPhiRadius = Math.sin( phi ) * radius;
3721 this.x = sinPhiRadius * Math.sin( theta );
3722 this.y = Math.cos( phi ) * radius;
3723 this.z = sinPhiRadius * Math.cos( theta );
3729 setFromCylindrical( c ) {
3731 return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
3735 setFromCylindricalCoords( radius, theta, y ) {
3737 this.x = radius * Math.sin( theta );
3739 this.z = radius * Math.cos( theta );
3745 setFromMatrixPosition( m ) {
3747 const e = m.elements;
3757 setFromMatrixScale( m ) {
3759 const sx = this.setFromMatrixColumn( m, 0 ).length();
3760 const sy = this.setFromMatrixColumn( m, 1 ).length();
3761 const sz = this.setFromMatrixColumn( m, 2 ).length();
3771 setFromMatrixColumn( m, index ) {
3773 return this.fromArray( m.elements, index * 4 );
3777 setFromMatrix3Column( m, index ) {
3779 return this.fromArray( m.elements, index * 3 );
3785 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
3789 fromArray( array, offset = 0 ) {
3791 this.x = array[ offset ];
3792 this.y = array[ offset + 1 ];
3793 this.z = array[ offset + 2 ];
3799 toArray( array = [], offset = 0 ) {
3801 array[ offset ] = this.x;
3802 array[ offset + 1 ] = this.y;
3803 array[ offset + 2 ] = this.z;
3809 fromBufferAttribute( attribute, index, offset ) {
3811 if ( offset !== undefined ) {
3813 console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
3817 this.x = attribute.getX( index );
3818 this.y = attribute.getY( index );
3819 this.z = attribute.getZ( index );
3827 this.x = Math.random();
3828 this.y = Math.random();
3829 this.z = Math.random();
3837 const _vector = /*@__PURE__*/ new Vector3();
3838 const _quaternion = /*@__PURE__*/ new Quaternion();
3842 constructor( min, max ) {
3844 Object.defineProperty( this, 'isBox3', { value: true } );
3846 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
3847 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
3853 this.min.copy( min );
3854 this.max.copy( max );
3860 setFromArray( array ) {
3862 let minX = + Infinity;
3863 let minY = + Infinity;
3864 let minZ = + Infinity;
3866 let maxX = - Infinity;
3867 let maxY = - Infinity;
3868 let maxZ = - Infinity;
3870 for ( let i = 0, l = array.length; i < l; i += 3 ) {
3872 const x = array[ i ];
3873 const y = array[ i + 1 ];
3874 const z = array[ i + 2 ];
3876 if ( x < minX ) minX = x;
3877 if ( y < minY ) minY = y;
3878 if ( z < minZ ) minZ = z;
3880 if ( x > maxX ) maxX = x;
3881 if ( y > maxY ) maxY = y;
3882 if ( z > maxZ ) maxZ = z;
3886 this.min.set( minX, minY, minZ );
3887 this.max.set( maxX, maxY, maxZ );
3893 setFromBufferAttribute( attribute ) {
3895 let minX = + Infinity;
3896 let minY = + Infinity;
3897 let minZ = + Infinity;
3899 let maxX = - Infinity;
3900 let maxY = - Infinity;
3901 let maxZ = - Infinity;
3903 for ( let i = 0, l = attribute.count; i < l; i ++ ) {
3905 const x = attribute.getX( i );
3906 const y = attribute.getY( i );
3907 const z = attribute.getZ( i );
3909 if ( x < minX ) minX = x;
3910 if ( y < minY ) minY = y;
3911 if ( z < minZ ) minZ = z;
3913 if ( x > maxX ) maxX = x;
3914 if ( y > maxY ) maxY = y;
3915 if ( z > maxZ ) maxZ = z;
3919 this.min.set( minX, minY, minZ );
3920 this.max.set( maxX, maxY, maxZ );
3926 setFromPoints( points ) {
3930 for ( let i = 0, il = points.length; i < il; i ++ ) {
3932 this.expandByPoint( points[ i ] );
3940 setFromCenterAndSize( center, size ) {
3942 const halfSize = _vector$1.copy( size ).multiplyScalar( 0.5 );
3944 this.min.copy( center ).sub( halfSize );
3945 this.max.copy( center ).add( halfSize );
3951 setFromObject( object ) {
3955 return this.expandByObject( object );
3961 return new this.constructor().copy( this );
3967 this.min.copy( box.min );
3968 this.max.copy( box.max );
3976 this.min.x = this.min.y = this.min.z = + Infinity;
3977 this.max.x = this.max.y = this.max.z = - Infinity;
3985 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
3987 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
3991 getCenter( target ) {
3993 if ( target === undefined ) {
3995 console.warn( 'THREE.Box3: .getCenter() target is now required' );
3996 target = new Vector3();
4000 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
4006 if ( target === undefined ) {
4008 console.warn( 'THREE.Box3: .getSize() target is now required' );
4009 target = new Vector3();
4013 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
4017 expandByPoint( point ) {
4019 this.min.min( point );
4020 this.max.max( point );
4026 expandByVector( vector ) {
4028 this.min.sub( vector );
4029 this.max.add( vector );
4035 expandByScalar( scalar ) {
4037 this.min.addScalar( - scalar );
4038 this.max.addScalar( scalar );
4044 expandByObject( object ) {
4046 // Computes the world-axis-aligned bounding box of an object (including its children),
4047 // accounting for both the object's, and children's, world transforms
4049 object.updateWorldMatrix( false, false );
4051 const geometry = object.geometry;
4053 if ( geometry !== undefined ) {
4055 if ( geometry.boundingBox === null ) {
4057 geometry.computeBoundingBox();
4061 _box.copy( geometry.boundingBox );
4062 _box.applyMatrix4( object.matrixWorld );
4068 const children = object.children;
4070 for ( let i = 0, l = children.length; i < l; i ++ ) {
4072 this.expandByObject( children[ i ] );
4080 containsPoint( point ) {
4082 return point.x < this.min.x || point.x > this.max.x ||
4083 point.y < this.min.y || point.y > this.max.y ||
4084 point.z < this.min.z || point.z > this.max.z ? false : true;
4088 containsBox( box ) {
4090 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
4091 this.min.y <= box.min.y && box.max.y <= this.max.y &&
4092 this.min.z <= box.min.z && box.max.z <= this.max.z;
4096 getParameter( point, target ) {
4098 // This can potentially have a divide by zero if the box
4099 // has a size dimension of 0.
4101 if ( target === undefined ) {
4103 console.warn( 'THREE.Box3: .getParameter() target is now required' );
4104 target = new Vector3();
4109 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
4110 ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
4111 ( point.z - this.min.z ) / ( this.max.z - this.min.z )
4116 intersectsBox( box ) {
4118 // using 6 splitting planes to rule out intersections.
4119 return box.max.x < this.min.x || box.min.x > this.max.x ||
4120 box.max.y < this.min.y || box.min.y > this.max.y ||
4121 box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
4125 intersectsSphere( sphere ) {
4127 // Find the point on the AABB closest to the sphere center.
4128 this.clampPoint( sphere.center, _vector$1 );
4130 // If that point is inside the sphere, the AABB and sphere intersect.
4131 return _vector$1.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
4135 intersectsPlane( plane ) {
4137 // We compute the minimum and maximum dot product values. If those values
4138 // are on the same side (back or front) of the plane, then there is no intersection.
4142 if ( plane.normal.x > 0 ) {
4144 min = plane.normal.x * this.min.x;
4145 max = plane.normal.x * this.max.x;
4149 min = plane.normal.x * this.max.x;
4150 max = plane.normal.x * this.min.x;
4154 if ( plane.normal.y > 0 ) {
4156 min += plane.normal.y * this.min.y;
4157 max += plane.normal.y * this.max.y;
4161 min += plane.normal.y * this.max.y;
4162 max += plane.normal.y * this.min.y;
4166 if ( plane.normal.z > 0 ) {
4168 min += plane.normal.z * this.min.z;
4169 max += plane.normal.z * this.max.z;
4173 min += plane.normal.z * this.max.z;
4174 max += plane.normal.z * this.min.z;
4178 return ( min <= - plane.constant && max >= - plane.constant );
4182 intersectsTriangle( triangle ) {
4184 if ( this.isEmpty() ) {
4190 // compute box center and extents
4191 this.getCenter( _center );
4192 _extents.subVectors( this.max, _center );
4194 // translate triangle to aabb origin
4195 _v0.subVectors( triangle.a, _center );
4196 _v1.subVectors( triangle.b, _center );
4197 _v2.subVectors( triangle.c, _center );
4199 // compute edge vectors for triangle
4200 _f0.subVectors( _v1, _v0 );
4201 _f1.subVectors( _v2, _v1 );
4202 _f2.subVectors( _v0, _v2 );
4204 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
4205 // 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
4206 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
4208 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
4209 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
4210 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
4212 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
4218 // test 3 face normals from the aabb
4219 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
4220 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
4226 // finally testing the face normal of the triangle
4227 // use already existing triangle edge vectors here
4228 _triangleNormal.crossVectors( _f0, _f1 );
4229 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
4231 return satForAxes( axes, _v0, _v1, _v2, _extents );
4235 clampPoint( point, target ) {
4237 if ( target === undefined ) {
4239 console.warn( 'THREE.Box3: .clampPoint() target is now required' );
4240 target = new Vector3();
4244 return target.copy( point ).clamp( this.min, this.max );
4248 distanceToPoint( point ) {
4250 const clampedPoint = _vector$1.copy( point ).clamp( this.min, this.max );
4252 return clampedPoint.sub( point ).length();
4256 getBoundingSphere( target ) {
4258 if ( target === undefined ) {
4260 console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
4261 //target = new Sphere(); // removed to avoid cyclic dependency
4265 this.getCenter( target.center );
4267 target.radius = this.getSize( _vector$1 ).length() * 0.5;
4275 this.min.max( box.min );
4276 this.max.min( box.max );
4278 // 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.
4279 if ( this.isEmpty() ) this.makeEmpty();
4287 this.min.min( box.min );
4288 this.max.max( box.max );
4294 applyMatrix4( matrix ) {
4296 // transform of empty box is an empty box.
4297 if ( this.isEmpty() ) return this;
4299 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
4300 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
4301 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
4302 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
4303 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
4304 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
4305 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
4306 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
4307 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
4309 this.setFromPoints( _points );
4315 translate( offset ) {
4317 this.min.add( offset );
4318 this.max.add( offset );
4326 return box.min.equals( this.min ) && box.max.equals( this.max );
4332 function satForAxes( axes, v0, v1, v2, extents ) {
4334 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
4336 _testAxis.fromArray( axes, i );
4337 // project the aabb onto the seperating axis
4338 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
4339 // project all 3 vertices of the triangle onto the seperating axis
4340 const p0 = v0.dot( _testAxis );
4341 const p1 = v1.dot( _testAxis );
4342 const p2 = v2.dot( _testAxis );
4343 // actual test, basically see if either of the most extreme of the triangle points intersects r
4344 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
4346 // points of the projected triangle are outside the projected half-length of the aabb
4347 // the axis is seperating and we can exit
4359 /*@__PURE__*/ new Vector3(),
4360 /*@__PURE__*/ new Vector3(),
4361 /*@__PURE__*/ new Vector3(),
4362 /*@__PURE__*/ new Vector3(),
4363 /*@__PURE__*/ new Vector3(),
4364 /*@__PURE__*/ new Vector3(),
4365 /*@__PURE__*/ new Vector3(),
4366 /*@__PURE__*/ new Vector3()
4369 const _vector$1 = /*@__PURE__*/ new Vector3();
4371 const _box = /*@__PURE__*/ new Box3();
4373 // triangle centered vertices
4375 const _v0 = /*@__PURE__*/ new Vector3();
4376 const _v1 = /*@__PURE__*/ new Vector3();
4377 const _v2 = /*@__PURE__*/ new Vector3();
4379 // triangle edge vectors
4381 const _f0 = /*@__PURE__*/ new Vector3();
4382 const _f1 = /*@__PURE__*/ new Vector3();
4383 const _f2 = /*@__PURE__*/ new Vector3();
4385 const _center = /*@__PURE__*/ new Vector3();
4386 const _extents = /*@__PURE__*/ new Vector3();
4387 const _triangleNormal = /*@__PURE__*/ new Vector3();
4388 const _testAxis = /*@__PURE__*/ new Vector3();
4390 const _box$1 = /*@__PURE__*/ new Box3();
4394 constructor( center, radius ) {
4396 this.center = ( center !== undefined ) ? center : new Vector3();
4397 this.radius = ( radius !== undefined ) ? radius : - 1;
4401 set( center, radius ) {
4403 this.center.copy( center );
4404 this.radius = radius;
4410 setFromPoints( points, optionalCenter ) {
4412 const center = this.center;
4414 if ( optionalCenter !== undefined ) {
4416 center.copy( optionalCenter );
4420 _box$1.setFromPoints( points ).getCenter( center );
4424 let maxRadiusSq = 0;
4426 for ( let i = 0, il = points.length; i < il; i ++ ) {
4428 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
4432 this.radius = Math.sqrt( maxRadiusSq );
4440 return new this.constructor().copy( this );
4446 this.center.copy( sphere.center );
4447 this.radius = sphere.radius;
4455 return ( this.radius < 0 );
4461 this.center.set( 0, 0, 0 );
4468 containsPoint( point ) {
4470 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
4474 distanceToPoint( point ) {
4476 return ( point.distanceTo( this.center ) - this.radius );
4480 intersectsSphere( sphere ) {
4482 const radiusSum = this.radius + sphere.radius;
4484 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
4488 intersectsBox( box ) {
4490 return box.intersectsSphere( this );
4494 intersectsPlane( plane ) {
4496 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
4500 clampPoint( point, target ) {
4502 const deltaLengthSq = this.center.distanceToSquared( point );
4504 if ( target === undefined ) {
4506 console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
4507 target = new Vector3();
4511 target.copy( point );
4513 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
4515 target.sub( this.center ).normalize();
4516 target.multiplyScalar( this.radius ).add( this.center );
4524 getBoundingBox( target ) {
4526 if ( target === undefined ) {
4528 console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
4529 target = new Box3();
4533 if ( this.isEmpty() ) {
4535 // Empty sphere produces empty bounding box
4541 target.set( this.center, this.center );
4542 target.expandByScalar( this.radius );
4548 applyMatrix4( matrix ) {
4550 this.center.applyMatrix4( matrix );
4551 this.radius = this.radius * matrix.getMaxScaleOnAxis();
4557 translate( offset ) {
4559 this.center.add( offset );
4567 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
4573 const _vector$2 = /*@__PURE__*/ new Vector3();
4574 const _segCenter = /*@__PURE__*/ new Vector3();
4575 const _segDir = /*@__PURE__*/ new Vector3();
4576 const _diff = /*@__PURE__*/ new Vector3();
4578 const _edge1 = /*@__PURE__*/ new Vector3();
4579 const _edge2 = /*@__PURE__*/ new Vector3();
4580 const _normal = /*@__PURE__*/ new Vector3();
4584 constructor( origin, direction ) {
4586 this.origin = ( origin !== undefined ) ? origin : new Vector3();
4587 this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
4591 set( origin, direction ) {
4593 this.origin.copy( origin );
4594 this.direction.copy( direction );
4602 return new this.constructor().copy( this );
4608 this.origin.copy( ray.origin );
4609 this.direction.copy( ray.direction );
4617 if ( target === undefined ) {
4619 console.warn( 'THREE.Ray: .at() target is now required' );
4620 target = new Vector3();
4624 return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
4630 this.direction.copy( v ).sub( this.origin ).normalize();
4638 this.origin.copy( this.at( t, _vector$2 ) );
4644 closestPointToPoint( point, target ) {
4646 if ( target === undefined ) {
4648 console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
4649 target = new Vector3();
4653 target.subVectors( point, this.origin );
4655 const directionDistance = target.dot( this.direction );
4657 if ( directionDistance < 0 ) {
4659 return target.copy( this.origin );
4663 return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
4667 distanceToPoint( point ) {
4669 return Math.sqrt( this.distanceSqToPoint( point ) );
4673 distanceSqToPoint( point ) {
4675 const directionDistance = _vector$2.subVectors( point, this.origin ).dot( this.direction );
4677 // point behind the ray
4679 if ( directionDistance < 0 ) {
4681 return this.origin.distanceToSquared( point );
4685 _vector$2.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
4687 return _vector$2.distanceToSquared( point );
4691 distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
4693 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
4694 // It returns the min distance between the ray and the segment
4695 // defined by v0 and v1
4696 // It can also set two optional targets :
4697 // - The closest point on the ray
4698 // - The closest point on the segment
4700 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
4701 _segDir.copy( v1 ).sub( v0 ).normalize();
4702 _diff.copy( this.origin ).sub( _segCenter );
4704 const segExtent = v0.distanceTo( v1 ) * 0.5;
4705 const a01 = - this.direction.dot( _segDir );
4706 const b0 = _diff.dot( this.direction );
4707 const b1 = - _diff.dot( _segDir );
4708 const c = _diff.lengthSq();
4709 const det = Math.abs( 1 - a01 * a01 );
4710 let s0, s1, sqrDist, extDet;
4714 // The ray and segment are not parallel.
4718 extDet = segExtent * det;
4722 if ( s1 >= - extDet ) {
4724 if ( s1 <= extDet ) {
4727 // Minimum at interior points of ray and segment.
4729 const invDet = 1 / det;
4732 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
4739 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4740 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4749 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4750 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4756 if ( s1 <= - extDet ) {
4760 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
4761 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
4762 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4764 } else if ( s1 <= extDet ) {
4769 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
4770 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
4776 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
4777 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
4778 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4786 // Ray and segment are parallel.
4788 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
4789 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
4790 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
4794 if ( optionalPointOnRay ) {
4796 optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
4800 if ( optionalPointOnSegment ) {
4802 optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
4810 intersectSphere( sphere, target ) {
4812 _vector$2.subVectors( sphere.center, this.origin );
4813 const tca = _vector$2.dot( this.direction );
4814 const d2 = _vector$2.dot( _vector$2 ) - tca * tca;
4815 const radius2 = sphere.radius * sphere.radius;
4817 if ( d2 > radius2 ) return null;
4819 const thc = Math.sqrt( radius2 - d2 );
4821 // t0 = first intersect point - entrance on front of sphere
4822 const t0 = tca - thc;
4824 // t1 = second intersect point - exit point on back of sphere
4825 const t1 = tca + thc;
4827 // test to see if both t0 and t1 are behind the ray - if so, return null
4828 if ( t0 < 0 && t1 < 0 ) return null;
4830 // test to see if t0 is behind the ray:
4831 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
4832 // in order to always return an intersect point that is in front of the ray.
4833 if ( t0 < 0 ) return this.at( t1, target );
4835 // else t0 is in front of the ray, so return the first collision point scaled by t0
4836 return this.at( t0, target );
4840 intersectsSphere( sphere ) {
4842 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
4846 distanceToPlane( plane ) {
4848 const denominator = plane.normal.dot( this.direction );
4850 if ( denominator === 0 ) {
4852 // line is coplanar, return origin
4853 if ( plane.distanceToPoint( this.origin ) === 0 ) {
4859 // Null is preferable to undefined since undefined means.... it is undefined
4865 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
4867 // Return if the ray never intersects the plane
4869 return t >= 0 ? t : null;
4873 intersectPlane( plane, target ) {
4875 const t = this.distanceToPlane( plane );
4883 return this.at( t, target );
4887 intersectsPlane( plane ) {
4889 // check if the ray lies on the plane first
4891 const distToPoint = plane.distanceToPoint( this.origin );
4893 if ( distToPoint === 0 ) {
4899 const denominator = plane.normal.dot( this.direction );
4901 if ( denominator * distToPoint < 0 ) {
4907 // ray origin is behind the plane (and is pointing behind it)
4913 intersectBox( box, target ) {
4915 let tmin, tmax, tymin, tymax, tzmin, tzmax;
4917 const invdirx = 1 / this.direction.x,
4918 invdiry = 1 / this.direction.y,
4919 invdirz = 1 / this.direction.z;
4921 const origin = this.origin;
4923 if ( invdirx >= 0 ) {
4925 tmin = ( box.min.x - origin.x ) * invdirx;
4926 tmax = ( box.max.x - origin.x ) * invdirx;
4930 tmin = ( box.max.x - origin.x ) * invdirx;
4931 tmax = ( box.min.x - origin.x ) * invdirx;
4935 if ( invdiry >= 0 ) {
4937 tymin = ( box.min.y - origin.y ) * invdiry;
4938 tymax = ( box.max.y - origin.y ) * invdiry;
4942 tymin = ( box.max.y - origin.y ) * invdiry;
4943 tymax = ( box.min.y - origin.y ) * invdiry;
4947 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
4949 // These lines also handle the case where tmin or tmax is NaN
4950 // (result of 0 * Infinity). x !== x returns true if x is NaN
4952 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
4954 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
4956 if ( invdirz >= 0 ) {
4958 tzmin = ( box.min.z - origin.z ) * invdirz;
4959 tzmax = ( box.max.z - origin.z ) * invdirz;
4963 tzmin = ( box.max.z - origin.z ) * invdirz;
4964 tzmax = ( box.min.z - origin.z ) * invdirz;
4968 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
4970 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
4972 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
4974 //return point closest to the ray (positive side)
4976 if ( tmax < 0 ) return null;
4978 return this.at( tmin >= 0 ? tmin : tmax, target );
4982 intersectsBox( box ) {
4984 return this.intersectBox( box, _vector$2 ) !== null;
4988 intersectTriangle( a, b, c, backfaceCulling, target ) {
4990 // Compute the offset origin, edges, and normal.
4992 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
4994 _edge1.subVectors( b, a );
4995 _edge2.subVectors( c, a );
4996 _normal.crossVectors( _edge1, _edge2 );
4998 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
4999 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
5000 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
5001 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
5002 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
5003 let DdN = this.direction.dot( _normal );
5008 if ( backfaceCulling ) return null;
5011 } else if ( DdN < 0 ) {
5022 _diff.subVectors( this.origin, a );
5023 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
5025 // b1 < 0, no intersection
5032 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
5034 // b2 < 0, no intersection
5041 // b1+b2 > 1, no intersection
5042 if ( DdQxE2 + DdE1xQ > DdN ) {
5048 // Line intersects triangle, check if ray does.
5049 const QdN = - sign * _diff.dot( _normal );
5051 // t < 0, no intersection
5058 // Ray intersects triangle.
5059 return this.at( QdN / DdN, target );
5063 applyMatrix4( matrix4 ) {
5065 this.origin.applyMatrix4( matrix4 );
5066 this.direction.transformDirection( matrix4 );
5074 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
5084 Object.defineProperty( this, 'isMatrix4', { value: true } );
5095 if ( arguments.length > 0 ) {
5097 console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
5103 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5105 const te = this.elements;
5107 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
5108 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
5109 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
5110 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
5133 return new Matrix4().fromArray( this.elements );
5139 const te = this.elements;
5140 const me = m.elements;
5142 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
5143 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
5144 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
5145 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
5153 const te = this.elements, me = m.elements;
5155 te[ 12 ] = me[ 12 ];
5156 te[ 13 ] = me[ 13 ];
5157 te[ 14 ] = me[ 14 ];
5163 extractBasis( xAxis, yAxis, zAxis ) {
5165 xAxis.setFromMatrixColumn( this, 0 );
5166 yAxis.setFromMatrixColumn( this, 1 );
5167 zAxis.setFromMatrixColumn( this, 2 );
5173 makeBasis( xAxis, yAxis, zAxis ) {
5176 xAxis.x, yAxis.x, zAxis.x, 0,
5177 xAxis.y, yAxis.y, zAxis.y, 0,
5178 xAxis.z, yAxis.z, zAxis.z, 0,
5186 extractRotation( m ) {
5188 // this method does not support reflection matrices
5190 const te = this.elements;
5191 const me = m.elements;
5193 const scaleX = 1 / _v1$1.setFromMatrixColumn( m, 0 ).length();
5194 const scaleY = 1 / _v1$1.setFromMatrixColumn( m, 1 ).length();
5195 const scaleZ = 1 / _v1$1.setFromMatrixColumn( m, 2 ).length();
5197 te[ 0 ] = me[ 0 ] * scaleX;
5198 te[ 1 ] = me[ 1 ] * scaleX;
5199 te[ 2 ] = me[ 2 ] * scaleX;
5202 te[ 4 ] = me[ 4 ] * scaleY;
5203 te[ 5 ] = me[ 5 ] * scaleY;
5204 te[ 6 ] = me[ 6 ] * scaleY;
5207 te[ 8 ] = me[ 8 ] * scaleZ;
5208 te[ 9 ] = me[ 9 ] * scaleZ;
5209 te[ 10 ] = me[ 10 ] * scaleZ;
5221 makeRotationFromEuler( euler ) {
5223 if ( ! ( euler && euler.isEuler ) ) {
5225 console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
5229 const te = this.elements;
5231 const x = euler.x, y = euler.y, z = euler.z;
5232 const a = Math.cos( x ), b = Math.sin( x );
5233 const c = Math.cos( y ), d = Math.sin( y );
5234 const e = Math.cos( z ), f = Math.sin( z );
5236 if ( euler.order === 'XYZ' ) {
5238 const ae = a * e, af = a * f, be = b * e, bf = b * f;
5244 te[ 1 ] = af + be * d;
5245 te[ 5 ] = ae - bf * d;
5248 te[ 2 ] = bf - ae * d;
5249 te[ 6 ] = be + af * d;
5252 } else if ( euler.order === 'YXZ' ) {
5254 const ce = c * e, cf = c * f, de = d * e, df = d * f;
5256 te[ 0 ] = ce + df * b;
5257 te[ 4 ] = de * b - cf;
5264 te[ 2 ] = cf * b - de;
5265 te[ 6 ] = df + ce * b;
5268 } else if ( euler.order === 'ZXY' ) {
5270 const ce = c * e, cf = c * f, de = d * e, df = d * f;
5272 te[ 0 ] = ce - df * b;
5274 te[ 8 ] = de + cf * b;
5276 te[ 1 ] = cf + de * b;
5278 te[ 9 ] = df - ce * b;
5284 } else if ( euler.order === 'ZYX' ) {
5286 const ae = a * e, af = a * f, be = b * e, bf = b * f;
5289 te[ 4 ] = be * d - af;
5290 te[ 8 ] = ae * d + bf;
5293 te[ 5 ] = bf * d + ae;
5294 te[ 9 ] = af * d - be;
5300 } else if ( euler.order === 'YZX' ) {
5302 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
5305 te[ 4 ] = bd - ac * f;
5306 te[ 8 ] = bc * f + ad;
5313 te[ 6 ] = ad * f + bc;
5314 te[ 10 ] = ac - bd * f;
5316 } else if ( euler.order === 'XZY' ) {
5318 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
5324 te[ 1 ] = ac * f + bd;
5326 te[ 9 ] = ad * f - bc;
5328 te[ 2 ] = bc * f - ad;
5330 te[ 10 ] = bd * f + ac;
5349 makeRotationFromQuaternion( q ) {
5351 return this.compose( _zero, q, _one );
5355 lookAt( eye, target, up ) {
5357 const te = this.elements;
5359 _z.subVectors( eye, target );
5361 if ( _z.lengthSq() === 0 ) {
5363 // eye and target are in the same position
5370 _x.crossVectors( up, _z );
5372 if ( _x.lengthSq() === 0 ) {
5374 // up and z are parallel
5376 if ( Math.abs( up.z ) === 1 ) {
5387 _x.crossVectors( up, _z );
5392 _y.crossVectors( _z, _x );
5394 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
5395 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
5396 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
5404 if ( n !== undefined ) {
5406 console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
5407 return this.multiplyMatrices( m, n );
5411 return this.multiplyMatrices( this, m );
5417 return this.multiplyMatrices( m, this );
5421 multiplyMatrices( a, b ) {
5423 const ae = a.elements;
5424 const be = b.elements;
5425 const te = this.elements;
5427 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
5428 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
5429 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
5430 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
5432 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
5433 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
5434 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
5435 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
5437 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
5438 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
5439 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
5440 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
5442 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
5443 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
5444 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
5445 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
5447 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
5448 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
5449 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
5450 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
5452 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
5453 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
5454 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
5455 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
5461 multiplyScalar( s ) {
5463 const te = this.elements;
5465 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
5466 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
5467 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
5468 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
5476 const te = this.elements;
5478 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
5479 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
5480 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
5481 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
5483 //TODO: make this more efficient
5484 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
5526 const te = this.elements;
5529 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
5530 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
5531 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
5533 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
5534 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
5535 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
5541 setPosition( x, y, z ) {
5543 const te = this.elements;
5545 if ( x.isVector3 ) {
5565 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
5566 const te = this.elements,
5568 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
5569 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
5570 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
5571 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
5573 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
5574 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
5575 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
5576 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
5578 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
5580 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
5582 const detInv = 1 / det;
5584 te[ 0 ] = t11 * detInv;
5585 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
5586 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
5587 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
5589 te[ 4 ] = t12 * detInv;
5590 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
5591 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
5592 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
5594 te[ 8 ] = t13 * detInv;
5595 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
5596 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
5597 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
5599 te[ 12 ] = t14 * detInv;
5600 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
5601 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
5602 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
5610 const te = this.elements;
5611 const x = v.x, y = v.y, z = v.z;
5613 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
5614 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
5615 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
5616 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
5622 getMaxScaleOnAxis() {
5624 const te = this.elements;
5626 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
5627 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
5628 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
5630 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
5634 makeTranslation( x, y, z ) {
5649 makeRotationX( theta ) {
5651 const c = Math.cos( theta ), s = Math.sin( theta );
5666 makeRotationY( theta ) {
5668 const c = Math.cos( theta ), s = Math.sin( theta );
5683 makeRotationZ( theta ) {
5685 const c = Math.cos( theta ), s = Math.sin( theta );
5700 makeRotationAxis( axis, angle ) {
5702 // Based on http://www.gamedev.net/reference/articles/article1199.asp
5704 const c = Math.cos( angle );
5705 const s = Math.sin( angle );
5707 const x = axis.x, y = axis.y, z = axis.z;
5708 const tx = t * x, ty = t * y;
5712 tx * x + c, tx * y - s * z, tx * z + s * y, 0,
5713 tx * y + s * z, ty * y + c, ty * z - s * x, 0,
5714 tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
5723 makeScale( x, y, z ) {
5738 makeShear( x, y, z ) {
5753 compose( position, quaternion, scale ) {
5755 const te = this.elements;
5757 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
5758 const x2 = x + x, y2 = y + y, z2 = z + z;
5759 const xx = x * x2, xy = x * y2, xz = x * z2;
5760 const yy = y * y2, yz = y * z2, zz = z * z2;
5761 const wx = w * x2, wy = w * y2, wz = w * z2;
5763 const sx = scale.x, sy = scale.y, sz = scale.z;
5765 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
5766 te[ 1 ] = ( xy + wz ) * sx;
5767 te[ 2 ] = ( xz - wy ) * sx;
5770 te[ 4 ] = ( xy - wz ) * sy;
5771 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
5772 te[ 6 ] = ( yz + wx ) * sy;
5775 te[ 8 ] = ( xz + wy ) * sz;
5776 te[ 9 ] = ( yz - wx ) * sz;
5777 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
5780 te[ 12 ] = position.x;
5781 te[ 13 ] = position.y;
5782 te[ 14 ] = position.z;
5789 decompose( position, quaternion, scale ) {
5791 const te = this.elements;
5793 let sx = _v1$1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
5794 const sy = _v1$1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
5795 const sz = _v1$1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
5797 // if determine is negative, we need to invert one scale
5798 const det = this.determinant();
5799 if ( det < 0 ) sx = - sx;
5801 position.x = te[ 12 ];
5802 position.y = te[ 13 ];
5803 position.z = te[ 14 ];
5805 // scale the rotation part
5808 const invSX = 1 / sx;
5809 const invSY = 1 / sy;
5810 const invSZ = 1 / sz;
5812 _m1.elements[ 0 ] *= invSX;
5813 _m1.elements[ 1 ] *= invSX;
5814 _m1.elements[ 2 ] *= invSX;
5816 _m1.elements[ 4 ] *= invSY;
5817 _m1.elements[ 5 ] *= invSY;
5818 _m1.elements[ 6 ] *= invSY;
5820 _m1.elements[ 8 ] *= invSZ;
5821 _m1.elements[ 9 ] *= invSZ;
5822 _m1.elements[ 10 ] *= invSZ;
5824 quaternion.setFromRotationMatrix( _m1 );
5834 makePerspective( left, right, top, bottom, near, far ) {
5836 if ( far === undefined ) {
5838 console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
5842 const te = this.elements;
5843 const x = 2 * near / ( right - left );
5844 const y = 2 * near / ( top - bottom );
5846 const a = ( right + left ) / ( right - left );
5847 const b = ( top + bottom ) / ( top - bottom );
5848 const c = - ( far + near ) / ( far - near );
5849 const d = - 2 * far * near / ( far - near );
5851 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
5852 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
5853 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
5854 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
5860 makeOrthographic( left, right, top, bottom, near, far ) {
5862 const te = this.elements;
5863 const w = 1.0 / ( right - left );
5864 const h = 1.0 / ( top - bottom );
5865 const p = 1.0 / ( far - near );
5867 const x = ( right + left ) * w;
5868 const y = ( top + bottom ) * h;
5869 const z = ( far + near ) * p;
5871 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
5872 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
5873 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
5874 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
5882 const te = this.elements;
5883 const me = matrix.elements;
5885 for ( let i = 0; i < 16; i ++ ) {
5887 if ( te[ i ] !== me[ i ] ) return false;
5895 fromArray( array, offset = 0 ) {
5897 for ( let i = 0; i < 16; i ++ ) {
5899 this.elements[ i ] = array[ i + offset ];
5907 toArray( array = [], offset = 0 ) {
5909 const te = this.elements;
5911 array[ offset ] = te[ 0 ];
5912 array[ offset + 1 ] = te[ 1 ];
5913 array[ offset + 2 ] = te[ 2 ];
5914 array[ offset + 3 ] = te[ 3 ];
5916 array[ offset + 4 ] = te[ 4 ];
5917 array[ offset + 5 ] = te[ 5 ];
5918 array[ offset + 6 ] = te[ 6 ];
5919 array[ offset + 7 ] = te[ 7 ];
5921 array[ offset + 8 ] = te[ 8 ];
5922 array[ offset + 9 ] = te[ 9 ];
5923 array[ offset + 10 ] = te[ 10 ];
5924 array[ offset + 11 ] = te[ 11 ];
5926 array[ offset + 12 ] = te[ 12 ];
5927 array[ offset + 13 ] = te[ 13 ];
5928 array[ offset + 14 ] = te[ 14 ];
5929 array[ offset + 15 ] = te[ 15 ];
5937 const _v1$1 = /*@__PURE__*/ new Vector3();
5938 const _m1 = /*@__PURE__*/ new Matrix4();
5939 const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
5940 const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
5941 const _x = /*@__PURE__*/ new Vector3();
5942 const _y = /*@__PURE__*/ new Vector3();
5943 const _z = /*@__PURE__*/ new Vector3();
5947 constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) {
5949 Object.defineProperty( this, 'isEuler', { value: true } );
5954 this._order = order;
5967 this._onChangeCallback();
5980 this._onChangeCallback();
5993 this._onChangeCallback();
6003 set order( value ) {
6005 this._order = value;
6006 this._onChangeCallback();
6010 set( x, y, z, order ) {
6015 this._order = order || this._order;
6017 this._onChangeCallback();
6025 return new this.constructor( this._x, this._y, this._z, this._order );
6034 this._order = euler._order;
6036 this._onChangeCallback();
6042 setFromRotationMatrix( m, order, update ) {
6044 const clamp = MathUtils.clamp;
6046 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6048 const te = m.elements;
6049 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
6050 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
6051 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6053 order = order || this._order;
6059 this._y = Math.asin( clamp( m13, - 1, 1 ) );
6061 if ( Math.abs( m13 ) < 0.9999999 ) {
6063 this._x = Math.atan2( - m23, m33 );
6064 this._z = Math.atan2( - m12, m11 );
6068 this._x = Math.atan2( m32, m22 );
6077 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
6079 if ( Math.abs( m23 ) < 0.9999999 ) {
6081 this._y = Math.atan2( m13, m33 );
6082 this._z = Math.atan2( m21, m22 );
6086 this._y = Math.atan2( - m31, m11 );
6095 this._x = Math.asin( clamp( m32, - 1, 1 ) );
6097 if ( Math.abs( m32 ) < 0.9999999 ) {
6099 this._y = Math.atan2( - m31, m33 );
6100 this._z = Math.atan2( - m12, m22 );
6105 this._z = Math.atan2( m21, m11 );
6113 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
6115 if ( Math.abs( m31 ) < 0.9999999 ) {
6117 this._x = Math.atan2( m32, m33 );
6118 this._z = Math.atan2( m21, m11 );
6123 this._z = Math.atan2( - m12, m22 );
6131 this._z = Math.asin( clamp( m21, - 1, 1 ) );
6133 if ( Math.abs( m21 ) < 0.9999999 ) {
6135 this._x = Math.atan2( - m23, m22 );
6136 this._y = Math.atan2( - m31, m11 );
6141 this._y = Math.atan2( m13, m33 );
6149 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
6151 if ( Math.abs( m12 ) < 0.9999999 ) {
6153 this._x = Math.atan2( m32, m22 );
6154 this._y = Math.atan2( m13, m11 );
6158 this._x = Math.atan2( - m23, m33 );
6167 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
6171 this._order = order;
6173 if ( update !== false ) this._onChangeCallback();
6179 setFromQuaternion( q, order, update ) {
6181 _matrix.makeRotationFromQuaternion( q );
6183 return this.setFromRotationMatrix( _matrix, order, update );
6187 setFromVector3( v, order ) {
6189 return this.set( v.x, v.y, v.z, order || this._order );
6193 reorder( newOrder ) {
6195 // WARNING: this discards revolution information -bhouston
6197 _quaternion$1.setFromEuler( this );
6199 return this.setFromQuaternion( _quaternion$1, newOrder );
6205 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
6209 fromArray( array ) {
6211 this._x = array[ 0 ];
6212 this._y = array[ 1 ];
6213 this._z = array[ 2 ];
6214 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
6216 this._onChangeCallback();
6222 toArray( array = [], offset = 0 ) {
6224 array[ offset ] = this._x;
6225 array[ offset + 1 ] = this._y;
6226 array[ offset + 2 ] = this._z;
6227 array[ offset + 3 ] = this._order;
6233 toVector3( optionalResult ) {
6235 if ( optionalResult ) {
6237 return optionalResult.set( this._x, this._y, this._z );
6241 return new Vector3( this._x, this._y, this._z );
6247 _onChange( callback ) {
6249 this._onChangeCallback = callback;
6255 _onChangeCallback() {}
6259 Euler.DefaultOrder = 'XYZ';
6260 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
6262 const _matrix = /*@__PURE__*/ new Matrix4();
6263 const _quaternion$1 = /*@__PURE__*/ new Quaternion();
6275 this.mask = 1 << channel | 0;
6281 this.mask |= 1 << channel | 0;
6287 this.mask = 0xffffffff | 0;
6293 this.mask ^= 1 << channel | 0;
6297 disable( channel ) {
6299 this.mask &= ~ ( 1 << channel | 0 );
6311 return ( this.mask & layers.mask ) !== 0;
6317 let _object3DId = 0;
6319 const _v1$2 = new Vector3();
6320 const _q1 = new Quaternion();
6321 const _m1$1 = new Matrix4();
6322 const _target = new Vector3();
6324 const _position = new Vector3();
6325 const _scale = new Vector3();
6326 const _quaternion$2 = new Quaternion();
6328 const _xAxis = new Vector3( 1, 0, 0 );
6329 const _yAxis = new Vector3( 0, 1, 0 );
6330 const _zAxis = new Vector3( 0, 0, 1 );
6332 const _addedEvent = { type: 'added' };
6333 const _removedEvent = { type: 'removed' };
6335 function Object3D() {
6337 Object.defineProperty( this, 'id', { value: _object3DId ++ } );
6339 this.uuid = MathUtils.generateUUID();
6342 this.type = 'Object3D';
6347 this.up = Object3D.DefaultUp.clone();
6349 const position = new Vector3();
6350 const rotation = new Euler();
6351 const quaternion = new Quaternion();
6352 const scale = new Vector3( 1, 1, 1 );
6354 function onRotationChange() {
6356 quaternion.setFromEuler( rotation, false );
6360 function onQuaternionChange() {
6362 rotation.setFromQuaternion( quaternion, undefined, false );
6366 rotation._onChange( onRotationChange );
6367 quaternion._onChange( onQuaternionChange );
6369 Object.defineProperties( this, {
6391 value: new Matrix4()
6394 value: new Matrix3()
6398 this.matrix = new Matrix4();
6399 this.matrixWorld = new Matrix4();
6401 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
6402 this.matrixWorldNeedsUpdate = false;
6404 this.layers = new Layers();
6405 this.visible = true;
6407 this.castShadow = false;
6408 this.receiveShadow = false;
6410 this.frustumCulled = true;
6411 this.renderOrder = 0;
6413 this.animations = [];
6419 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
6420 Object3D.DefaultMatrixAutoUpdate = true;
6422 Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
6424 constructor: Object3D,
6428 onBeforeRender: function () {},
6429 onAfterRender: function () {},
6431 applyMatrix4: function ( matrix ) {
6433 if ( this.matrixAutoUpdate ) this.updateMatrix();
6435 this.matrix.premultiply( matrix );
6437 this.matrix.decompose( this.position, this.quaternion, this.scale );
6441 applyQuaternion: function ( q ) {
6443 this.quaternion.premultiply( q );
6449 setRotationFromAxisAngle: function ( axis, angle ) {
6451 // assumes axis is normalized
6453 this.quaternion.setFromAxisAngle( axis, angle );
6457 setRotationFromEuler: function ( euler ) {
6459 this.quaternion.setFromEuler( euler, true );
6463 setRotationFromMatrix: function ( m ) {
6465 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6467 this.quaternion.setFromRotationMatrix( m );
6471 setRotationFromQuaternion: function ( q ) {
6473 // assumes q is normalized
6475 this.quaternion.copy( q );
6479 rotateOnAxis: function ( axis, angle ) {
6481 // rotate object on axis in object space
6482 // axis is assumed to be normalized
6484 _q1.setFromAxisAngle( axis, angle );
6486 this.quaternion.multiply( _q1 );
6492 rotateOnWorldAxis: function ( axis, angle ) {
6494 // rotate object on axis in world space
6495 // axis is assumed to be normalized
6496 // method assumes no rotated parent
6498 _q1.setFromAxisAngle( axis, angle );
6500 this.quaternion.premultiply( _q1 );
6506 rotateX: function ( angle ) {
6508 return this.rotateOnAxis( _xAxis, angle );
6512 rotateY: function ( angle ) {
6514 return this.rotateOnAxis( _yAxis, angle );
6518 rotateZ: function ( angle ) {
6520 return this.rotateOnAxis( _zAxis, angle );
6524 translateOnAxis: function ( axis, distance ) {
6526 // translate object by distance along axis in object space
6527 // axis is assumed to be normalized
6529 _v1$2.copy( axis ).applyQuaternion( this.quaternion );
6531 this.position.add( _v1$2.multiplyScalar( distance ) );
6537 translateX: function ( distance ) {
6539 return this.translateOnAxis( _xAxis, distance );
6543 translateY: function ( distance ) {
6545 return this.translateOnAxis( _yAxis, distance );
6549 translateZ: function ( distance ) {
6551 return this.translateOnAxis( _zAxis, distance );
6555 localToWorld: function ( vector ) {
6557 return vector.applyMatrix4( this.matrixWorld );
6561 worldToLocal: function ( vector ) {
6563 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
6567 lookAt: function ( x, y, z ) {
6569 // This method does not support objects having non-uniformly-scaled parent(s)
6571 if ( x.isVector3 ) {
6577 _target.set( x, y, z );
6581 const parent = this.parent;
6583 this.updateWorldMatrix( true, false );
6585 _position.setFromMatrixPosition( this.matrixWorld );
6587 if ( this.isCamera || this.isLight ) {
6589 _m1$1.lookAt( _position, _target, this.up );
6593 _m1$1.lookAt( _target, _position, this.up );
6597 this.quaternion.setFromRotationMatrix( _m1$1 );
6601 _m1$1.extractRotation( parent.matrixWorld );
6602 _q1.setFromRotationMatrix( _m1$1 );
6603 this.quaternion.premultiply( _q1.invert() );
6609 add: function ( object ) {
6611 if ( arguments.length > 1 ) {
6613 for ( let i = 0; i < arguments.length; i ++ ) {
6615 this.add( arguments[ i ] );
6623 if ( object === this ) {
6625 console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
6630 if ( ( object && object.isObject3D ) ) {
6632 if ( object.parent !== null ) {
6634 object.parent.remove( object );
6638 object.parent = this;
6639 this.children.push( object );
6641 object.dispatchEvent( _addedEvent );
6645 console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
6653 remove: function ( object ) {
6655 if ( arguments.length > 1 ) {
6657 for ( let i = 0; i < arguments.length; i ++ ) {
6659 this.remove( arguments[ i ] );
6667 const index = this.children.indexOf( object );
6669 if ( index !== - 1 ) {
6671 object.parent = null;
6672 this.children.splice( index, 1 );
6674 object.dispatchEvent( _removedEvent );
6682 clear: function () {
6684 for ( let i = 0; i < this.children.length; i ++ ) {
6686 const object = this.children[ i ];
6688 object.parent = null;
6690 object.dispatchEvent( _removedEvent );
6694 this.children.length = 0;
6701 attach: function ( object ) {
6703 // adds object as a child of this, while maintaining the object's world transform
6705 this.updateWorldMatrix( true, false );
6707 _m1$1.copy( this.matrixWorld ).invert();
6709 if ( object.parent !== null ) {
6711 object.parent.updateWorldMatrix( true, false );
6713 _m1$1.multiply( object.parent.matrixWorld );
6717 object.applyMatrix4( _m1$1 );
6719 object.updateWorldMatrix( false, false );
6727 getObjectById: function ( id ) {
6729 return this.getObjectByProperty( 'id', id );
6733 getObjectByName: function ( name ) {
6735 return this.getObjectByProperty( 'name', name );
6739 getObjectByProperty: function ( name, value ) {
6741 if ( this[ name ] === value ) return this;
6743 for ( let i = 0, l = this.children.length; i < l; i ++ ) {
6745 const child = this.children[ i ];
6746 const object = child.getObjectByProperty( name, value );
6748 if ( object !== undefined ) {
6760 getWorldPosition: function ( target ) {
6762 if ( target === undefined ) {
6764 console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
6765 target = new Vector3();
6769 this.updateWorldMatrix( true, false );
6771 return target.setFromMatrixPosition( this.matrixWorld );
6775 getWorldQuaternion: function ( target ) {
6777 if ( target === undefined ) {
6779 console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
6780 target = new Quaternion();
6784 this.updateWorldMatrix( true, false );
6786 this.matrixWorld.decompose( _position, target, _scale );
6792 getWorldScale: function ( target ) {
6794 if ( target === undefined ) {
6796 console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
6797 target = new Vector3();
6801 this.updateWorldMatrix( true, false );
6803 this.matrixWorld.decompose( _position, _quaternion$2, target );
6809 getWorldDirection: function ( target ) {
6811 if ( target === undefined ) {
6813 console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' );
6814 target = new Vector3();
6818 this.updateWorldMatrix( true, false );
6820 const e = this.matrixWorld.elements;
6822 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
6826 raycast: function () {},
6828 traverse: function ( callback ) {
6832 const children = this.children;
6834 for ( let i = 0, l = children.length; i < l; i ++ ) {
6836 children[ i ].traverse( callback );
6842 traverseVisible: function ( callback ) {
6844 if ( this.visible === false ) return;
6848 const children = this.children;
6850 for ( let i = 0, l = children.length; i < l; i ++ ) {
6852 children[ i ].traverseVisible( callback );
6858 traverseAncestors: function ( callback ) {
6860 const parent = this.parent;
6862 if ( parent !== null ) {
6866 parent.traverseAncestors( callback );
6872 updateMatrix: function () {
6874 this.matrix.compose( this.position, this.quaternion, this.scale );
6876 this.matrixWorldNeedsUpdate = true;
6880 updateMatrixWorld: function ( force ) {
6882 if ( this.matrixAutoUpdate ) this.updateMatrix();
6884 if ( this.matrixWorldNeedsUpdate || force ) {
6886 if ( this.parent === null ) {
6888 this.matrixWorld.copy( this.matrix );
6892 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
6896 this.matrixWorldNeedsUpdate = false;
6904 const children = this.children;
6906 for ( let i = 0, l = children.length; i < l; i ++ ) {
6908 children[ i ].updateMatrixWorld( force );
6914 updateWorldMatrix: function ( updateParents, updateChildren ) {
6916 const parent = this.parent;
6918 if ( updateParents === true && parent !== null ) {
6920 parent.updateWorldMatrix( true, false );
6924 if ( this.matrixAutoUpdate ) this.updateMatrix();
6926 if ( this.parent === null ) {
6928 this.matrixWorld.copy( this.matrix );
6932 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
6938 if ( updateChildren === true ) {
6940 const children = this.children;
6942 for ( let i = 0, l = children.length; i < l; i ++ ) {
6944 children[ i ].updateWorldMatrix( false, true );
6952 toJSON: function ( meta ) {
6954 // meta is a string when called from JSON.stringify
6955 const isRootObject = ( meta === undefined || typeof meta === 'string' );
6959 // meta is a hash used to collect geometries, materials.
6960 // not providing it implies that this is the root object
6961 // being serialized.
6962 if ( isRootObject ) {
6964 // initialize meta obj
6978 generator: 'Object3D.toJSON'
6983 // standard Object3D serialization
6987 object.uuid = this.uuid;
6988 object.type = this.type;
6990 if ( this.name !== '' ) object.name = this.name;
6991 if ( this.castShadow === true ) object.castShadow = true;
6992 if ( this.receiveShadow === true ) object.receiveShadow = true;
6993 if ( this.visible === false ) object.visible = false;
6994 if ( this.frustumCulled === false ) object.frustumCulled = false;
6995 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
6996 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
6998 object.layers = this.layers.mask;
6999 object.matrix = this.matrix.toArray();
7001 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
7003 // object specific properties
7005 if ( this.isInstancedMesh ) {
7007 object.type = 'InstancedMesh';
7008 object.count = this.count;
7009 object.instanceMatrix = this.instanceMatrix.toJSON();
7015 function serialize( library, element ) {
7017 if ( library[ element.uuid ] === undefined ) {
7019 library[ element.uuid ] = element.toJSON( meta );
7023 return element.uuid;
7027 if ( this.isMesh || this.isLine || this.isPoints ) {
7029 object.geometry = serialize( meta.geometries, this.geometry );
7031 const parameters = this.geometry.parameters;
7033 if ( parameters !== undefined && parameters.shapes !== undefined ) {
7035 const shapes = parameters.shapes;
7037 if ( Array.isArray( shapes ) ) {
7039 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
7041 const shape = shapes[ i ];
7043 serialize( meta.shapes, shape );
7049 serialize( meta.shapes, shapes );
7057 if ( this.isSkinnedMesh ) {
7059 object.bindMode = this.bindMode;
7060 object.bindMatrix = this.bindMatrix.toArray();
7062 if ( this.skeleton !== undefined ) {
7064 serialize( meta.skeletons, this.skeleton );
7066 object.skeleton = this.skeleton.uuid;
7072 if ( this.material !== undefined ) {
7074 if ( Array.isArray( this.material ) ) {
7078 for ( let i = 0, l = this.material.length; i < l; i ++ ) {
7080 uuids.push( serialize( meta.materials, this.material[ i ] ) );
7084 object.material = uuids;
7088 object.material = serialize( meta.materials, this.material );
7096 if ( this.children.length > 0 ) {
7098 object.children = [];
7100 for ( let i = 0; i < this.children.length; i ++ ) {
7102 object.children.push( this.children[ i ].toJSON( meta ).object );
7110 if ( this.animations.length > 0 ) {
7112 object.animations = [];
7114 for ( let i = 0; i < this.animations.length; i ++ ) {
7116 const animation = this.animations[ i ];
7118 object.animations.push( serialize( meta.animations, animation ) );
7124 if ( isRootObject ) {
7126 const geometries = extractFromCache( meta.geometries );
7127 const materials = extractFromCache( meta.materials );
7128 const textures = extractFromCache( meta.textures );
7129 const images = extractFromCache( meta.images );
7130 const shapes = extractFromCache( meta.shapes );
7131 const skeletons = extractFromCache( meta.skeletons );
7132 const animations = extractFromCache( meta.animations );
7134 if ( geometries.length > 0 ) output.geometries = geometries;
7135 if ( materials.length > 0 ) output.materials = materials;
7136 if ( textures.length > 0 ) output.textures = textures;
7137 if ( images.length > 0 ) output.images = images;
7138 if ( shapes.length > 0 ) output.shapes = shapes;
7139 if ( skeletons.length > 0 ) output.skeletons = skeletons;
7140 if ( animations.length > 0 ) output.animations = animations;
7144 output.object = object;
7148 // extract data from the cache hash
7149 // remove metadata on each item
7150 // and return as array
7151 function extractFromCache( cache ) {
7154 for ( const key in cache ) {
7156 const data = cache[ key ];
7157 delete data.metadata;
7158 values.push( data );
7168 clone: function ( recursive ) {
7170 return new this.constructor().copy( this, recursive );
7174 copy: function ( source, recursive = true ) {
7176 this.name = source.name;
7178 this.up.copy( source.up );
7180 this.position.copy( source.position );
7181 this.rotation.order = source.rotation.order;
7182 this.quaternion.copy( source.quaternion );
7183 this.scale.copy( source.scale );
7185 this.matrix.copy( source.matrix );
7186 this.matrixWorld.copy( source.matrixWorld );
7188 this.matrixAutoUpdate = source.matrixAutoUpdate;
7189 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
7191 this.layers.mask = source.layers.mask;
7192 this.visible = source.visible;
7194 this.castShadow = source.castShadow;
7195 this.receiveShadow = source.receiveShadow;
7197 this.frustumCulled = source.frustumCulled;
7198 this.renderOrder = source.renderOrder;
7200 this.userData = JSON.parse( JSON.stringify( source.userData ) );
7202 if ( recursive === true ) {
7204 for ( let i = 0; i < source.children.length; i ++ ) {
7206 const child = source.children[ i ];
7207 this.add( child.clone() );
7219 const _vector1 = /*@__PURE__*/ new Vector3();
7220 const _vector2 = /*@__PURE__*/ new Vector3();
7221 const _normalMatrix = /*@__PURE__*/ new Matrix3();
7225 constructor( normal, constant ) {
7227 Object.defineProperty( this, 'isPlane', { value: true } );
7229 // normal is assumed to be normalized
7231 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
7232 this.constant = ( constant !== undefined ) ? constant : 0;
7236 set( normal, constant ) {
7238 this.normal.copy( normal );
7239 this.constant = constant;
7245 setComponents( x, y, z, w ) {
7247 this.normal.set( x, y, z );
7254 setFromNormalAndCoplanarPoint( normal, point ) {
7256 this.normal.copy( normal );
7257 this.constant = - point.dot( this.normal );
7263 setFromCoplanarPoints( a, b, c ) {
7265 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
7267 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
7269 this.setFromNormalAndCoplanarPoint( normal, a );
7277 return new this.constructor().copy( this );
7283 this.normal.copy( plane.normal );
7284 this.constant = plane.constant;
7292 // Note: will lead to a divide by zero if the plane is invalid.
7294 const inverseNormalLength = 1.0 / this.normal.length();
7295 this.normal.multiplyScalar( inverseNormalLength );
7296 this.constant *= inverseNormalLength;
7304 this.constant *= - 1;
7305 this.normal.negate();
7311 distanceToPoint( point ) {
7313 return this.normal.dot( point ) + this.constant;
7317 distanceToSphere( sphere ) {
7319 return this.distanceToPoint( sphere.center ) - sphere.radius;
7323 projectPoint( point, target ) {
7325 if ( target === undefined ) {
7327 console.warn( 'THREE.Plane: .projectPoint() target is now required' );
7328 target = new Vector3();
7332 return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
7336 intersectLine( line, target ) {
7338 if ( target === undefined ) {
7340 console.warn( 'THREE.Plane: .intersectLine() target is now required' );
7341 target = new Vector3();
7345 const direction = line.delta( _vector1 );
7347 const denominator = this.normal.dot( direction );
7349 if ( denominator === 0 ) {
7351 // line is coplanar, return origin
7352 if ( this.distanceToPoint( line.start ) === 0 ) {
7354 return target.copy( line.start );
7358 // Unsure if this is the correct method to handle this case.
7363 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
7365 if ( t < 0 || t > 1 ) {
7371 return target.copy( direction ).multiplyScalar( t ).add( line.start );
7375 intersectsLine( line ) {
7377 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
7379 const startSign = this.distanceToPoint( line.start );
7380 const endSign = this.distanceToPoint( line.end );
7382 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
7386 intersectsBox( box ) {
7388 return box.intersectsPlane( this );
7392 intersectsSphere( sphere ) {
7394 return sphere.intersectsPlane( this );
7398 coplanarPoint( target ) {
7400 if ( target === undefined ) {
7402 console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
7403 target = new Vector3();
7407 return target.copy( this.normal ).multiplyScalar( - this.constant );
7411 applyMatrix4( matrix, optionalNormalMatrix ) {
7413 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
7415 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
7417 const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
7419 this.constant = - referencePoint.dot( normal );
7425 translate( offset ) {
7427 this.constant -= offset.dot( this.normal );
7435 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
7441 const _v0$1 = /*@__PURE__*/ new Vector3();
7442 const _v1$3 = /*@__PURE__*/ new Vector3();
7443 const _v2$1 = /*@__PURE__*/ new Vector3();
7444 const _v3 = /*@__PURE__*/ new Vector3();
7446 const _vab = /*@__PURE__*/ new Vector3();
7447 const _vac = /*@__PURE__*/ new Vector3();
7448 const _vbc = /*@__PURE__*/ new Vector3();
7449 const _vap = /*@__PURE__*/ new Vector3();
7450 const _vbp = /*@__PURE__*/ new Vector3();
7451 const _vcp = /*@__PURE__*/ new Vector3();
7455 constructor( a, b, c ) {
7457 this.a = ( a !== undefined ) ? a : new Vector3();
7458 this.b = ( b !== undefined ) ? b : new Vector3();
7459 this.c = ( c !== undefined ) ? c : new Vector3();
7463 static getNormal( a, b, c, target ) {
7465 if ( target === undefined ) {
7467 console.warn( 'THREE.Triangle: .getNormal() target is now required' );
7468 target = new Vector3();
7472 target.subVectors( c, b );
7473 _v0$1.subVectors( a, b );
7474 target.cross( _v0$1 );
7476 const targetLengthSq = target.lengthSq();
7477 if ( targetLengthSq > 0 ) {
7479 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
7483 return target.set( 0, 0, 0 );
7487 // static/instance method to calculate barycentric coordinates
7488 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
7489 static getBarycoord( point, a, b, c, target ) {
7491 _v0$1.subVectors( c, a );
7492 _v1$3.subVectors( b, a );
7493 _v2$1.subVectors( point, a );
7495 const dot00 = _v0$1.dot( _v0$1 );
7496 const dot01 = _v0$1.dot( _v1$3 );
7497 const dot02 = _v0$1.dot( _v2$1 );
7498 const dot11 = _v1$3.dot( _v1$3 );
7499 const dot12 = _v1$3.dot( _v2$1 );
7501 const denom = ( dot00 * dot11 - dot01 * dot01 );
7503 if ( target === undefined ) {
7505 console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
7506 target = new Vector3();
7510 // collinear or singular triangle
7511 if ( denom === 0 ) {
7513 // arbitrary location outside of triangle?
7514 // not sure if this is the best idea, maybe should be returning undefined
7515 return target.set( - 2, - 1, - 1 );
7519 const invDenom = 1 / denom;
7520 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
7521 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
7523 // barycentric coordinates must always sum to 1
7524 return target.set( 1 - u - v, v, u );
7528 static containsPoint( point, a, b, c ) {
7530 this.getBarycoord( point, a, b, c, _v3 );
7532 return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
7536 static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
7538 this.getBarycoord( point, p1, p2, p3, _v3 );
7541 target.addScaledVector( uv1, _v3.x );
7542 target.addScaledVector( uv2, _v3.y );
7543 target.addScaledVector( uv3, _v3.z );
7549 static isFrontFacing( a, b, c, direction ) {
7551 _v0$1.subVectors( c, b );
7552 _v1$3.subVectors( a, b );
7554 // strictly front facing
7555 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
7569 setFromPointsAndIndices( points, i0, i1, i2 ) {
7571 this.a.copy( points[ i0 ] );
7572 this.b.copy( points[ i1 ] );
7573 this.c.copy( points[ i2 ] );
7581 return new this.constructor().copy( this );
7587 this.a.copy( triangle.a );
7588 this.b.copy( triangle.b );
7589 this.c.copy( triangle.c );
7597 _v0$1.subVectors( this.c, this.b );
7598 _v1$3.subVectors( this.a, this.b );
7600 return _v0$1.cross( _v1$3 ).length() * 0.5;
7604 getMidpoint( target ) {
7606 if ( target === undefined ) {
7608 console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
7609 target = new Vector3();
7613 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
7617 getNormal( target ) {
7619 return Triangle.getNormal( this.a, this.b, this.c, target );
7623 getPlane( target ) {
7625 if ( target === undefined ) {
7627 console.warn( 'THREE.Triangle: .getPlane() target is now required' );
7628 target = new Plane();
7632 return target.setFromCoplanarPoints( this.a, this.b, this.c );
7636 getBarycoord( point, target ) {
7638 return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
7642 getUV( point, uv1, uv2, uv3, target ) {
7644 return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
7648 containsPoint( point ) {
7650 return Triangle.containsPoint( point, this.a, this.b, this.c );
7654 isFrontFacing( direction ) {
7656 return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
7660 intersectsBox( box ) {
7662 return box.intersectsTriangle( this );
7666 closestPointToPoint( p, target ) {
7668 if ( target === undefined ) {
7670 console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
7671 target = new Vector3();
7675 const a = this.a, b = this.b, c = this.c;
7678 // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
7679 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
7680 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
7681 // basically, we're distinguishing which of the voronoi regions of the triangle
7682 // the point lies in with the minimum amount of redundant computation.
7684 _vab.subVectors( b, a );
7685 _vac.subVectors( c, a );
7686 _vap.subVectors( p, a );
7687 const d1 = _vab.dot( _vap );
7688 const d2 = _vac.dot( _vap );
7689 if ( d1 <= 0 && d2 <= 0 ) {
7691 // vertex region of A; barycentric coords (1, 0, 0)
7692 return target.copy( a );
7696 _vbp.subVectors( p, b );
7697 const d3 = _vab.dot( _vbp );
7698 const d4 = _vac.dot( _vbp );
7699 if ( d3 >= 0 && d4 <= d3 ) {
7701 // vertex region of B; barycentric coords (0, 1, 0)
7702 return target.copy( b );
7706 const vc = d1 * d4 - d3 * d2;
7707 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
7709 v = d1 / ( d1 - d3 );
7710 // edge region of AB; barycentric coords (1-v, v, 0)
7711 return target.copy( a ).addScaledVector( _vab, v );
7715 _vcp.subVectors( p, c );
7716 const d5 = _vab.dot( _vcp );
7717 const d6 = _vac.dot( _vcp );
7718 if ( d6 >= 0 && d5 <= d6 ) {
7720 // vertex region of C; barycentric coords (0, 0, 1)
7721 return target.copy( c );
7725 const vb = d5 * d2 - d1 * d6;
7726 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
7728 w = d2 / ( d2 - d6 );
7729 // edge region of AC; barycentric coords (1-w, 0, w)
7730 return target.copy( a ).addScaledVector( _vac, w );
7734 const va = d3 * d6 - d5 * d4;
7735 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
7737 _vbc.subVectors( c, b );
7738 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
7739 // edge region of BC; barycentric coords (0, 1-w, w)
7740 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
7745 const denom = 1 / ( va + vb + vc );
7750 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
7754 equals( triangle ) {
7756 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
7762 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
7763 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
7764 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
7765 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
7766 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
7767 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
7768 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
7769 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
7770 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
7771 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
7772 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
7773 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
7774 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
7775 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
7776 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
7777 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
7778 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
7779 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
7780 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
7781 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
7782 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
7783 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
7784 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
7785 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
7787 const _hslA = { h: 0, s: 0, l: 0 };
7788 const _hslB = { h: 0, s: 0, l: 0 };
7790 function hue2rgb( p, q, t ) {
7792 if ( t < 0 ) t += 1;
7793 if ( t > 1 ) t -= 1;
7794 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
7795 if ( t < 1 / 2 ) return q;
7796 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
7801 function SRGBToLinear( c ) {
7803 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
7807 function LinearToSRGB( c ) {
7809 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
7815 constructor( r, g, b ) {
7817 Object.defineProperty( this, 'isColor', { value: true } );
7819 if ( g === undefined && b === undefined ) {
7821 // r is THREE.Color, hex or string
7822 return this.set( r );
7826 return this.setRGB( r, g, b );
7832 if ( value && value.isColor ) {
7836 } else if ( typeof value === 'number' ) {
7838 this.setHex( value );
7840 } else if ( typeof value === 'string' ) {
7842 this.setStyle( value );
7850 setScalar( scalar ) {
7862 hex = Math.floor( hex );
7864 this.r = ( hex >> 16 & 255 ) / 255;
7865 this.g = ( hex >> 8 & 255 ) / 255;
7866 this.b = ( hex & 255 ) / 255;
7884 // h,s,l ranges are in 0.0 - 1.0
7885 h = MathUtils.euclideanModulo( h, 1 );
7886 s = MathUtils.clamp( s, 0, 1 );
7887 l = MathUtils.clamp( l, 0, 1 );
7891 this.r = this.g = this.b = l;
7895 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
7896 const q = ( 2 * l ) - p;
7898 this.r = hue2rgb( q, p, h + 1 / 3 );
7899 this.g = hue2rgb( q, p, h );
7900 this.b = hue2rgb( q, p, h - 1 / 3 );
7910 function handleAlpha( string ) {
7912 if ( string === undefined ) return;
7914 if ( parseFloat( string ) < 1 ) {
7916 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
7925 if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
7930 const name = m[ 1 ];
7931 const components = m[ 2 ];
7938 if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7940 // rgb(255,0,0) rgba(255,0,0,0.5)
7941 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
7942 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
7943 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
7945 handleAlpha( color[ 5 ] );
7951 if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7953 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
7954 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
7955 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
7956 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
7958 handleAlpha( color[ 5 ] );
7969 if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7971 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
7972 const h = parseFloat( color[ 1 ] ) / 360;
7973 const s = parseInt( color[ 2 ], 10 ) / 100;
7974 const l = parseInt( color[ 3 ], 10 ) / 100;
7976 handleAlpha( color[ 5 ] );
7978 return this.setHSL( h, s, l );
7986 } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
7991 const size = hex.length;
7996 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
7997 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
7998 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
8002 } else if ( size === 6 ) {
8005 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
8006 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
8007 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
8015 if ( style && style.length > 0 ) {
8017 return this.setColorName( style );
8025 setColorName( style ) {
8028 const hex = _colorKeywords[ style ];
8030 if ( hex !== undefined ) {
8038 console.warn( 'THREE.Color: Unknown color ' + style );
8048 return new this.constructor( this.r, this.g, this.b );
8062 copyGammaToLinear( color, gammaFactor = 2.0 ) {
8064 this.r = Math.pow( color.r, gammaFactor );
8065 this.g = Math.pow( color.g, gammaFactor );
8066 this.b = Math.pow( color.b, gammaFactor );
8072 copyLinearToGamma( color, gammaFactor = 2.0 ) {
8074 const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
8076 this.r = Math.pow( color.r, safeInverse );
8077 this.g = Math.pow( color.g, safeInverse );
8078 this.b = Math.pow( color.b, safeInverse );
8084 convertGammaToLinear( gammaFactor ) {
8086 this.copyGammaToLinear( this, gammaFactor );
8092 convertLinearToGamma( gammaFactor ) {
8094 this.copyLinearToGamma( this, gammaFactor );
8100 copySRGBToLinear( color ) {
8102 this.r = SRGBToLinear( color.r );
8103 this.g = SRGBToLinear( color.g );
8104 this.b = SRGBToLinear( color.b );
8110 copyLinearToSRGB( color ) {
8112 this.r = LinearToSRGB( color.r );
8113 this.g = LinearToSRGB( color.g );
8114 this.b = LinearToSRGB( color.b );
8120 convertSRGBToLinear() {
8122 this.copySRGBToLinear( this );
8128 convertLinearToSRGB() {
8130 this.copyLinearToSRGB( this );
8138 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
8144 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
8150 // h,s,l ranges are in 0.0 - 1.0
8152 if ( target === undefined ) {
8154 console.warn( 'THREE.Color: .getHSL() target is now required' );
8155 target = { h: 0, s: 0, l: 0 };
8159 const r = this.r, g = this.g, b = this.b;
8161 const max = Math.max( r, g, b );
8162 const min = Math.min( r, g, b );
8164 let hue, saturation;
8165 const lightness = ( min + max ) / 2.0;
8167 if ( min === max ) {
8174 const delta = max - min;
8176 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
8180 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
8181 case g: hue = ( b - r ) / delta + 2; break;
8182 case b: hue = ( r - g ) / delta + 4; break;
8191 target.s = saturation;
8192 target.l = lightness;
8200 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
8204 offsetHSL( h, s, l ) {
8206 this.getHSL( _hslA );
8208 _hslA.h += h; _hslA.s += s; _hslA.l += l;
8210 this.setHSL( _hslA.h, _hslA.s, _hslA.l );
8226 addColors( color1, color2 ) {
8228 this.r = color1.r + color2.r;
8229 this.g = color1.g + color2.g;
8230 this.b = color1.b + color2.b;
8248 this.r = Math.max( 0, this.r - color.r );
8249 this.g = Math.max( 0, this.g - color.g );
8250 this.b = Math.max( 0, this.b - color.b );
8266 multiplyScalar( s ) {
8276 lerp( color, alpha ) {
8278 this.r += ( color.r - this.r ) * alpha;
8279 this.g += ( color.g - this.g ) * alpha;
8280 this.b += ( color.b - this.b ) * alpha;
8286 lerpHSL( color, alpha ) {
8288 this.getHSL( _hslA );
8289 color.getHSL( _hslB );
8291 const h = MathUtils.lerp( _hslA.h, _hslB.h, alpha );
8292 const s = MathUtils.lerp( _hslA.s, _hslB.s, alpha );
8293 const l = MathUtils.lerp( _hslA.l, _hslB.l, alpha );
8295 this.setHSL( h, s, l );
8303 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
8307 fromArray( array, offset = 0 ) {
8309 this.r = array[ offset ];
8310 this.g = array[ offset + 1 ];
8311 this.b = array[ offset + 2 ];
8317 toArray( array = [], offset = 0 ) {
8319 array[ offset ] = this.r;
8320 array[ offset + 1 ] = this.g;
8321 array[ offset + 2 ] = this.b;
8327 fromBufferAttribute( attribute, index ) {
8329 this.r = attribute.getX( index );
8330 this.g = attribute.getY( index );
8331 this.b = attribute.getZ( index );
8333 if ( attribute.normalized === true ) {
8335 // assuming Uint8Array
8349 return this.getHex();
8355 Color.NAMES = _colorKeywords;
8356 Color.prototype.r = 1;
8357 Color.prototype.g = 1;
8358 Color.prototype.b = 1;
8362 constructor( a, b, c, normal, color, materialIndex = 0 ) {
8368 this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
8369 this.vertexNormals = Array.isArray( normal ) ? normal : [];
8371 this.color = ( color && color.isColor ) ? color : new Color();
8372 this.vertexColors = Array.isArray( color ) ? color : [];
8374 this.materialIndex = materialIndex;
8380 return new this.constructor().copy( this );
8390 this.normal.copy( source.normal );
8391 this.color.copy( source.color );
8393 this.materialIndex = source.materialIndex;
8395 for ( let i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
8397 this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
8401 for ( let i = 0, il = source.vertexColors.length; i < il; i ++ ) {
8403 this.vertexColors[ i ] = source.vertexColors[ i ].clone();
8415 function Material() {
8417 Object.defineProperty( this, 'id', { value: materialId ++ } );
8419 this.uuid = MathUtils.generateUUID();
8422 this.type = 'Material';
8426 this.blending = NormalBlending;
8427 this.side = FrontSide;
8428 this.flatShading = false;
8429 this.vertexColors = false;
8432 this.transparent = false;
8434 this.blendSrc = SrcAlphaFactor;
8435 this.blendDst = OneMinusSrcAlphaFactor;
8436 this.blendEquation = AddEquation;
8437 this.blendSrcAlpha = null;
8438 this.blendDstAlpha = null;
8439 this.blendEquationAlpha = null;
8441 this.depthFunc = LessEqualDepth;
8442 this.depthTest = true;
8443 this.depthWrite = true;
8445 this.stencilWriteMask = 0xff;
8446 this.stencilFunc = AlwaysStencilFunc;
8447 this.stencilRef = 0;
8448 this.stencilFuncMask = 0xff;
8449 this.stencilFail = KeepStencilOp;
8450 this.stencilZFail = KeepStencilOp;
8451 this.stencilZPass = KeepStencilOp;
8452 this.stencilWrite = false;
8454 this.clippingPlanes = null;
8455 this.clipIntersection = false;
8456 this.clipShadows = false;
8458 this.shadowSide = null;
8460 this.colorWrite = true;
8462 this.precision = null; // override the renderer's default precision for this material
8464 this.polygonOffset = false;
8465 this.polygonOffsetFactor = 0;
8466 this.polygonOffsetUnits = 0;
8468 this.dithering = false;
8471 this.premultipliedAlpha = false;
8473 this.visible = true;
8475 this.toneMapped = true;
8483 Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
8485 constructor: Material,
8489 onBeforeCompile: function ( /* shaderobject, renderer */ ) {},
8491 customProgramCacheKey: function () {
8493 return this.onBeforeCompile.toString();
8497 setValues: function ( values ) {
8499 if ( values === undefined ) return;
8501 for ( const key in values ) {
8503 const newValue = values[ key ];
8505 if ( newValue === undefined ) {
8507 console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
8512 // for backward compatability if shading is set in the constructor
8513 if ( key === 'shading' ) {
8515 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
8516 this.flatShading = ( newValue === FlatShading ) ? true : false;
8521 const currentValue = this[ key ];
8523 if ( currentValue === undefined ) {
8525 console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
8530 if ( currentValue && currentValue.isColor ) {
8532 currentValue.set( newValue );
8534 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
8536 currentValue.copy( newValue );
8540 this[ key ] = newValue;
8548 toJSON: function ( meta ) {
8550 const isRoot = ( meta === undefined || typeof meta === 'string' );
8565 generator: 'Material.toJSON'
8569 // standard Material serialization
8570 data.uuid = this.uuid;
8571 data.type = this.type;
8573 if ( this.name !== '' ) data.name = this.name;
8575 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
8577 if ( this.roughness !== undefined ) data.roughness = this.roughness;
8578 if ( this.metalness !== undefined ) data.metalness = this.metalness;
8580 if ( this.sheen && this.sheen.isColor ) data.sheen = this.sheen.getHex();
8581 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
8582 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
8584 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
8585 if ( this.shininess !== undefined ) data.shininess = this.shininess;
8586 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
8587 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
8589 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
8591 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
8595 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
8597 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
8601 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
8603 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
8604 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
8608 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
8609 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
8610 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
8611 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
8613 if ( this.aoMap && this.aoMap.isTexture ) {
8615 data.aoMap = this.aoMap.toJSON( meta ).uuid;
8616 data.aoMapIntensity = this.aoMapIntensity;
8620 if ( this.bumpMap && this.bumpMap.isTexture ) {
8622 data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
8623 data.bumpScale = this.bumpScale;
8627 if ( this.normalMap && this.normalMap.isTexture ) {
8629 data.normalMap = this.normalMap.toJSON( meta ).uuid;
8630 data.normalMapType = this.normalMapType;
8631 data.normalScale = this.normalScale.toArray();
8635 if ( this.displacementMap && this.displacementMap.isTexture ) {
8637 data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
8638 data.displacementScale = this.displacementScale;
8639 data.displacementBias = this.displacementBias;
8643 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
8644 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
8646 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
8647 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
8649 if ( this.envMap && this.envMap.isTexture ) {
8651 data.envMap = this.envMap.toJSON( meta ).uuid;
8652 data.reflectivity = this.reflectivity; // Scale behind envMap
8653 data.refractionRatio = this.refractionRatio;
8655 if ( this.combine !== undefined ) data.combine = this.combine;
8656 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
8660 if ( this.gradientMap && this.gradientMap.isTexture ) {
8662 data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
8666 if ( this.size !== undefined ) data.size = this.size;
8667 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
8669 if ( this.blending !== NormalBlending ) data.blending = this.blending;
8670 if ( this.flatShading === true ) data.flatShading = this.flatShading;
8671 if ( this.side !== FrontSide ) data.side = this.side;
8672 if ( this.vertexColors ) data.vertexColors = true;
8674 if ( this.opacity < 1 ) data.opacity = this.opacity;
8675 if ( this.transparent === true ) data.transparent = this.transparent;
8677 data.depthFunc = this.depthFunc;
8678 data.depthTest = this.depthTest;
8679 data.depthWrite = this.depthWrite;
8681 data.stencilWrite = this.stencilWrite;
8682 data.stencilWriteMask = this.stencilWriteMask;
8683 data.stencilFunc = this.stencilFunc;
8684 data.stencilRef = this.stencilRef;
8685 data.stencilFuncMask = this.stencilFuncMask;
8686 data.stencilFail = this.stencilFail;
8687 data.stencilZFail = this.stencilZFail;
8688 data.stencilZPass = this.stencilZPass;
8690 // rotation (SpriteMaterial)
8691 if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation;
8693 if ( this.polygonOffset === true ) data.polygonOffset = true;
8694 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
8695 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
8697 if ( this.linewidth && this.linewidth !== 1 ) data.linewidth = this.linewidth;
8698 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
8699 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
8700 if ( this.scale !== undefined ) data.scale = this.scale;
8702 if ( this.dithering === true ) data.dithering = true;
8704 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
8705 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
8707 if ( this.wireframe === true ) data.wireframe = this.wireframe;
8708 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
8709 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
8710 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
8712 if ( this.morphTargets === true ) data.morphTargets = true;
8713 if ( this.morphNormals === true ) data.morphNormals = true;
8714 if ( this.skinning === true ) data.skinning = true;
8716 if ( this.visible === false ) data.visible = false;
8718 if ( this.toneMapped === false ) data.toneMapped = false;
8720 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
8722 // TODO: Copied from Object3D.toJSON
8724 function extractFromCache( cache ) {
8728 for ( const key in cache ) {
8730 const data = cache[ key ];
8731 delete data.metadata;
8732 values.push( data );
8742 const textures = extractFromCache( meta.textures );
8743 const images = extractFromCache( meta.images );
8745 if ( textures.length > 0 ) data.textures = textures;
8746 if ( images.length > 0 ) data.images = images;
8754 clone: function () {
8756 return new this.constructor().copy( this );
8760 copy: function ( source ) {
8762 this.name = source.name;
8764 this.fog = source.fog;
8766 this.blending = source.blending;
8767 this.side = source.side;
8768 this.flatShading = source.flatShading;
8769 this.vertexColors = source.vertexColors;
8771 this.opacity = source.opacity;
8772 this.transparent = source.transparent;
8774 this.blendSrc = source.blendSrc;
8775 this.blendDst = source.blendDst;
8776 this.blendEquation = source.blendEquation;
8777 this.blendSrcAlpha = source.blendSrcAlpha;
8778 this.blendDstAlpha = source.blendDstAlpha;
8779 this.blendEquationAlpha = source.blendEquationAlpha;
8781 this.depthFunc = source.depthFunc;
8782 this.depthTest = source.depthTest;
8783 this.depthWrite = source.depthWrite;
8785 this.stencilWriteMask = source.stencilWriteMask;
8786 this.stencilFunc = source.stencilFunc;
8787 this.stencilRef = source.stencilRef;
8788 this.stencilFuncMask = source.stencilFuncMask;
8789 this.stencilFail = source.stencilFail;
8790 this.stencilZFail = source.stencilZFail;
8791 this.stencilZPass = source.stencilZPass;
8792 this.stencilWrite = source.stencilWrite;
8794 const srcPlanes = source.clippingPlanes;
8795 let dstPlanes = null;
8797 if ( srcPlanes !== null ) {
8799 const n = srcPlanes.length;
8800 dstPlanes = new Array( n );
8802 for ( let i = 0; i !== n; ++ i ) {
8804 dstPlanes[ i ] = srcPlanes[ i ].clone();
8810 this.clippingPlanes = dstPlanes;
8811 this.clipIntersection = source.clipIntersection;
8812 this.clipShadows = source.clipShadows;
8814 this.shadowSide = source.shadowSide;
8816 this.colorWrite = source.colorWrite;
8818 this.precision = source.precision;
8820 this.polygonOffset = source.polygonOffset;
8821 this.polygonOffsetFactor = source.polygonOffsetFactor;
8822 this.polygonOffsetUnits = source.polygonOffsetUnits;
8824 this.dithering = source.dithering;
8826 this.alphaTest = source.alphaTest;
8827 this.premultipliedAlpha = source.premultipliedAlpha;
8829 this.visible = source.visible;
8831 this.toneMapped = source.toneMapped;
8833 this.userData = JSON.parse( JSON.stringify( source.userData ) );
8839 dispose: function () {
8841 this.dispatchEvent( { type: 'dispose' } );
8847 Object.defineProperty( Material.prototype, 'needsUpdate', {
8849 set: function ( value ) {
8851 if ( value === true ) this.version ++;
8861 * map: new THREE.Texture( <Image> ),
8863 * lightMap: new THREE.Texture( <Image> ),
8864 * lightMapIntensity: <float>
8866 * aoMap: new THREE.Texture( <Image> ),
8867 * aoMapIntensity: <float>
8869 * specularMap: new THREE.Texture( <Image> ),
8871 * alphaMap: new THREE.Texture( <Image> ),
8873 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
8874 * combine: THREE.Multiply,
8875 * reflectivity: <float>,
8876 * refractionRatio: <float>,
8878 * depthTest: <bool>,
8879 * depthWrite: <bool>,
8881 * wireframe: <boolean>,
8882 * wireframeLinewidth: <float>,
8885 * morphTargets: <bool>
8889 function MeshBasicMaterial( parameters ) {
8891 Material.call( this );
8893 this.type = 'MeshBasicMaterial';
8895 this.color = new Color( 0xffffff ); // emissive
8899 this.lightMap = null;
8900 this.lightMapIntensity = 1.0;
8903 this.aoMapIntensity = 1.0;
8905 this.specularMap = null;
8907 this.alphaMap = null;
8910 this.combine = MultiplyOperation;
8911 this.reflectivity = 1;
8912 this.refractionRatio = 0.98;
8914 this.wireframe = false;
8915 this.wireframeLinewidth = 1;
8916 this.wireframeLinecap = 'round';
8917 this.wireframeLinejoin = 'round';
8919 this.skinning = false;
8920 this.morphTargets = false;
8922 this.setValues( parameters );
8926 MeshBasicMaterial.prototype = Object.create( Material.prototype );
8927 MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
8929 MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
8931 MeshBasicMaterial.prototype.copy = function ( source ) {
8933 Material.prototype.copy.call( this, source );
8935 this.color.copy( source.color );
8937 this.map = source.map;
8939 this.lightMap = source.lightMap;
8940 this.lightMapIntensity = source.lightMapIntensity;
8942 this.aoMap = source.aoMap;
8943 this.aoMapIntensity = source.aoMapIntensity;
8945 this.specularMap = source.specularMap;
8947 this.alphaMap = source.alphaMap;
8949 this.envMap = source.envMap;
8950 this.combine = source.combine;
8951 this.reflectivity = source.reflectivity;
8952 this.refractionRatio = source.refractionRatio;
8954 this.wireframe = source.wireframe;
8955 this.wireframeLinewidth = source.wireframeLinewidth;
8956 this.wireframeLinecap = source.wireframeLinecap;
8957 this.wireframeLinejoin = source.wireframeLinejoin;
8959 this.skinning = source.skinning;
8960 this.morphTargets = source.morphTargets;
8966 const _vector$3 = new Vector3();
8967 const _vector2$1 = new Vector2();
8969 function BufferAttribute( array, itemSize, normalized ) {
8971 if ( Array.isArray( array ) ) {
8973 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
8980 this.itemSize = itemSize;
8981 this.count = array !== undefined ? array.length / itemSize : 0;
8982 this.normalized = normalized === true;
8984 this.usage = StaticDrawUsage;
8985 this.updateRange = { offset: 0, count: - 1 };
8991 Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
8993 set: function ( value ) {
8995 if ( value === true ) this.version ++;
9001 Object.assign( BufferAttribute.prototype, {
9003 isBufferAttribute: true,
9005 onUploadCallback: function () {},
9007 setUsage: function ( value ) {
9015 copy: function ( source ) {
9017 this.name = source.name;
9018 this.array = new source.array.constructor( source.array );
9019 this.itemSize = source.itemSize;
9020 this.count = source.count;
9021 this.normalized = source.normalized;
9023 this.usage = source.usage;
9029 copyAt: function ( index1, attribute, index2 ) {
9031 index1 *= this.itemSize;
9032 index2 *= attribute.itemSize;
9034 for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
9036 this.array[ index1 + i ] = attribute.array[ index2 + i ];
9044 copyArray: function ( array ) {
9046 this.array.set( array );
9052 copyColorsArray: function ( colors ) {
9054 const array = this.array;
9057 for ( let i = 0, l = colors.length; i < l; i ++ ) {
9059 let color = colors[ i ];
9061 if ( color === undefined ) {
9063 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
9064 color = new Color();
9068 array[ offset ++ ] = color.r;
9069 array[ offset ++ ] = color.g;
9070 array[ offset ++ ] = color.b;
9078 copyVector2sArray: function ( vectors ) {
9080 const array = this.array;
9083 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9085 let vector = vectors[ i ];
9087 if ( vector === undefined ) {
9089 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
9090 vector = new Vector2();
9094 array[ offset ++ ] = vector.x;
9095 array[ offset ++ ] = vector.y;
9103 copyVector3sArray: function ( vectors ) {
9105 const array = this.array;
9108 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9110 let vector = vectors[ i ];
9112 if ( vector === undefined ) {
9114 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
9115 vector = new Vector3();
9119 array[ offset ++ ] = vector.x;
9120 array[ offset ++ ] = vector.y;
9121 array[ offset ++ ] = vector.z;
9129 copyVector4sArray: function ( vectors ) {
9131 const array = this.array;
9134 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
9136 let vector = vectors[ i ];
9138 if ( vector === undefined ) {
9140 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
9141 vector = new Vector4();
9145 array[ offset ++ ] = vector.x;
9146 array[ offset ++ ] = vector.y;
9147 array[ offset ++ ] = vector.z;
9148 array[ offset ++ ] = vector.w;
9156 applyMatrix3: function ( m ) {
9158 if ( this.itemSize === 2 ) {
9160 for ( let i = 0, l = this.count; i < l; i ++ ) {
9162 _vector2$1.fromBufferAttribute( this, i );
9163 _vector2$1.applyMatrix3( m );
9165 this.setXY( i, _vector2$1.x, _vector2$1.y );
9169 } else if ( this.itemSize === 3 ) {
9171 for ( let i = 0, l = this.count; i < l; i ++ ) {
9173 _vector$3.fromBufferAttribute( this, i );
9174 _vector$3.applyMatrix3( m );
9176 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9186 applyMatrix4: function ( m ) {
9188 for ( let i = 0, l = this.count; i < l; i ++ ) {
9190 _vector$3.x = this.getX( i );
9191 _vector$3.y = this.getY( i );
9192 _vector$3.z = this.getZ( i );
9194 _vector$3.applyMatrix4( m );
9196 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9204 applyNormalMatrix: function ( m ) {
9206 for ( let i = 0, l = this.count; i < l; i ++ ) {
9208 _vector$3.x = this.getX( i );
9209 _vector$3.y = this.getY( i );
9210 _vector$3.z = this.getZ( i );
9212 _vector$3.applyNormalMatrix( m );
9214 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9222 transformDirection: function ( m ) {
9224 for ( let i = 0, l = this.count; i < l; i ++ ) {
9226 _vector$3.x = this.getX( i );
9227 _vector$3.y = this.getY( i );
9228 _vector$3.z = this.getZ( i );
9230 _vector$3.transformDirection( m );
9232 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
9240 set: function ( value, offset = 0 ) {
9242 this.array.set( value, offset );
9248 getX: function ( index ) {
9250 return this.array[ index * this.itemSize ];
9254 setX: function ( index, x ) {
9256 this.array[ index * this.itemSize ] = x;
9262 getY: function ( index ) {
9264 return this.array[ index * this.itemSize + 1 ];
9268 setY: function ( index, y ) {
9270 this.array[ index * this.itemSize + 1 ] = y;
9276 getZ: function ( index ) {
9278 return this.array[ index * this.itemSize + 2 ];
9282 setZ: function ( index, z ) {
9284 this.array[ index * this.itemSize + 2 ] = z;
9290 getW: function ( index ) {
9292 return this.array[ index * this.itemSize + 3 ];
9296 setW: function ( index, w ) {
9298 this.array[ index * this.itemSize + 3 ] = w;
9304 setXY: function ( index, x, y ) {
9306 index *= this.itemSize;
9308 this.array[ index + 0 ] = x;
9309 this.array[ index + 1 ] = y;
9315 setXYZ: function ( index, x, y, z ) {
9317 index *= this.itemSize;
9319 this.array[ index + 0 ] = x;
9320 this.array[ index + 1 ] = y;
9321 this.array[ index + 2 ] = z;
9327 setXYZW: function ( index, x, y, z, w ) {
9329 index *= this.itemSize;
9331 this.array[ index + 0 ] = x;
9332 this.array[ index + 1 ] = y;
9333 this.array[ index + 2 ] = z;
9334 this.array[ index + 3 ] = w;
9340 onUpload: function ( callback ) {
9342 this.onUploadCallback = callback;
9348 clone: function () {
9350 return new this.constructor( this.array, this.itemSize ).copy( this );
9354 toJSON: function () {
9357 itemSize: this.itemSize,
9358 type: this.array.constructor.name,
9359 array: Array.prototype.slice.call( this.array ),
9360 normalized: this.normalized
9369 function Int8BufferAttribute( array, itemSize, normalized ) {
9371 BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
9375 Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9376 Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
9379 function Uint8BufferAttribute( array, itemSize, normalized ) {
9381 BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
9385 Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9386 Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
9389 function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
9391 BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
9395 Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9396 Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
9399 function Int16BufferAttribute( array, itemSize, normalized ) {
9401 BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
9405 Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9406 Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
9409 function Uint16BufferAttribute( array, itemSize, normalized ) {
9411 BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
9415 Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9416 Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
9419 function Int32BufferAttribute( array, itemSize, normalized ) {
9421 BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
9425 Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9426 Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
9429 function Uint32BufferAttribute( array, itemSize, normalized ) {
9431 BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
9435 Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9436 Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
9438 function Float16BufferAttribute( array, itemSize, normalized ) {
9440 BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
9444 Float16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9445 Float16BufferAttribute.prototype.constructor = Float16BufferAttribute;
9446 Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
9448 function Float32BufferAttribute( array, itemSize, normalized ) {
9450 BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
9454 Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9455 Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
9458 function Float64BufferAttribute( array, itemSize, normalized ) {
9460 BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
9464 Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
9465 Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
9467 class DirectGeometry {
9479 this.morphTargets = {};
9481 this.skinWeights = [];
9482 this.skinIndices = [];
9484 // this.lineDistances = [];
9486 this.boundingBox = null;
9487 this.boundingSphere = null;
9491 this.verticesNeedUpdate = false;
9492 this.normalsNeedUpdate = false;
9493 this.colorsNeedUpdate = false;
9494 this.uvsNeedUpdate = false;
9495 this.groupsNeedUpdate = false;
9499 computeGroups( geometry ) {
9504 let materialIndex = undefined;
9506 const faces = geometry.faces;
9508 for ( i = 0; i < faces.length; i ++ ) {
9510 const face = faces[ i ];
9514 if ( face.materialIndex !== materialIndex ) {
9516 materialIndex = face.materialIndex;
9518 if ( group !== undefined ) {
9520 group.count = ( i * 3 ) - group.start;
9521 groups.push( group );
9527 materialIndex: materialIndex
9534 if ( group !== undefined ) {
9536 group.count = ( i * 3 ) - group.start;
9537 groups.push( group );
9541 this.groups = groups;
9545 fromGeometry( geometry ) {
9547 const faces = geometry.faces;
9548 const vertices = geometry.vertices;
9549 const faceVertexUvs = geometry.faceVertexUvs;
9551 const hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
9552 const hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
9556 const morphTargets = geometry.morphTargets;
9557 const morphTargetsLength = morphTargets.length;
9559 let morphTargetsPosition;
9561 if ( morphTargetsLength > 0 ) {
9563 morphTargetsPosition = [];
9565 for ( let i = 0; i < morphTargetsLength; i ++ ) {
9567 morphTargetsPosition[ i ] = {
9568 name: morphTargets[ i ].name,
9574 this.morphTargets.position = morphTargetsPosition;
9578 const morphNormals = geometry.morphNormals;
9579 const morphNormalsLength = morphNormals.length;
9581 let morphTargetsNormal;
9583 if ( morphNormalsLength > 0 ) {
9585 morphTargetsNormal = [];
9587 for ( let i = 0; i < morphNormalsLength; i ++ ) {
9589 morphTargetsNormal[ i ] = {
9590 name: morphNormals[ i ].name,
9596 this.morphTargets.normal = morphTargetsNormal;
9602 const skinIndices = geometry.skinIndices;
9603 const skinWeights = geometry.skinWeights;
9605 const hasSkinIndices = skinIndices.length === vertices.length;
9606 const hasSkinWeights = skinWeights.length === vertices.length;
9610 if ( vertices.length > 0 && faces.length === 0 ) {
9612 console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' );
9616 for ( let i = 0; i < faces.length; i ++ ) {
9618 const face = faces[ i ];
9620 this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
9622 const vertexNormals = face.vertexNormals;
9624 if ( vertexNormals.length === 3 ) {
9626 this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
9630 const normal = face.normal;
9632 this.normals.push( normal, normal, normal );
9636 const vertexColors = face.vertexColors;
9638 if ( vertexColors.length === 3 ) {
9640 this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
9644 const color = face.color;
9646 this.colors.push( color, color, color );
9650 if ( hasFaceVertexUv === true ) {
9652 const vertexUvs = faceVertexUvs[ 0 ][ i ];
9654 if ( vertexUvs !== undefined ) {
9656 this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
9660 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
9662 this.uvs.push( new Vector2(), new Vector2(), new Vector2() );
9668 if ( hasFaceVertexUv2 === true ) {
9670 const vertexUvs = faceVertexUvs[ 1 ][ i ];
9672 if ( vertexUvs !== undefined ) {
9674 this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
9678 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
9680 this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );
9688 for ( let j = 0; j < morphTargetsLength; j ++ ) {
9690 const morphTarget = morphTargets[ j ].vertices;
9692 morphTargetsPosition[ j ].data.push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
9696 for ( let j = 0; j < morphNormalsLength; j ++ ) {
9698 const morphNormal = morphNormals[ j ].vertexNormals[ i ];
9700 morphTargetsNormal[ j ].data.push( morphNormal.a, morphNormal.b, morphNormal.c );
9706 if ( hasSkinIndices ) {
9708 this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
9712 if ( hasSkinWeights ) {
9714 this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
9720 this.computeGroups( geometry );
9722 this.verticesNeedUpdate = geometry.verticesNeedUpdate;
9723 this.normalsNeedUpdate = geometry.normalsNeedUpdate;
9724 this.colorsNeedUpdate = geometry.colorsNeedUpdate;
9725 this.uvsNeedUpdate = geometry.uvsNeedUpdate;
9726 this.groupsNeedUpdate = geometry.groupsNeedUpdate;
9728 if ( geometry.boundingSphere !== null ) {
9730 this.boundingSphere = geometry.boundingSphere.clone();
9734 if ( geometry.boundingBox !== null ) {
9736 this.boundingBox = geometry.boundingBox.clone();
9746 function arrayMax( array ) {
9748 if ( array.length === 0 ) return - Infinity;
9750 let max = array[ 0 ];
9752 for ( let i = 1, l = array.length; i < l; ++ i ) {
9754 if ( array[ i ] > max ) max = array[ i ];
9762 const TYPED_ARRAYS = {
9763 Int8Array: Int8Array,
9764 Uint8Array: Uint8Array,
9765 // Workaround for IE11 pre KB2929437. See #11440
9766 Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
9767 Int16Array: Int16Array,
9768 Uint16Array: Uint16Array,
9769 Int32Array: Int32Array,
9770 Uint32Array: Uint32Array,
9771 Float32Array: Float32Array,
9772 Float64Array: Float64Array
9775 function getTypedArray( type, buffer ) {
9777 return new TYPED_ARRAYS[ type ]( buffer );
9781 let _bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
9783 const _m1$2 = new Matrix4();
9784 const _obj = new Object3D();
9785 const _offset = new Vector3();
9786 const _box$2 = new Box3();
9787 const _boxMorphTargets = new Box3();
9788 const _vector$4 = new Vector3();
9790 function BufferGeometry() {
9792 Object.defineProperty( this, 'id', { value: _bufferGeometryId += 2 } );
9794 this.uuid = MathUtils.generateUUID();
9797 this.type = 'BufferGeometry';
9800 this.attributes = {};
9802 this.morphAttributes = {};
9803 this.morphTargetsRelative = false;
9807 this.boundingBox = null;
9808 this.boundingSphere = null;
9810 this.drawRange = { start: 0, count: Infinity };
9816 BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
9818 constructor: BufferGeometry,
9820 isBufferGeometry: true,
9822 getIndex: function () {
9828 setIndex: function ( index ) {
9830 if ( Array.isArray( index ) ) {
9832 this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
9844 getAttribute: function ( name ) {
9846 return this.attributes[ name ];
9850 setAttribute: function ( name, attribute ) {
9852 this.attributes[ name ] = attribute;
9858 deleteAttribute: function ( name ) {
9860 delete this.attributes[ name ];
9866 hasAttribute: function ( name ) {
9868 return this.attributes[ name ] !== undefined;
9872 addGroup: function ( start, count, materialIndex = 0 ) {
9878 materialIndex: materialIndex
9884 clearGroups: function () {
9890 setDrawRange: function ( start, count ) {
9892 this.drawRange.start = start;
9893 this.drawRange.count = count;
9897 applyMatrix4: function ( matrix ) {
9899 const position = this.attributes.position;
9901 if ( position !== undefined ) {
9903 position.applyMatrix4( matrix );
9905 position.needsUpdate = true;
9909 const normal = this.attributes.normal;
9911 if ( normal !== undefined ) {
9913 const normalMatrix = new Matrix3().getNormalMatrix( matrix );
9915 normal.applyNormalMatrix( normalMatrix );
9917 normal.needsUpdate = true;
9921 const tangent = this.attributes.tangent;
9923 if ( tangent !== undefined ) {
9925 tangent.transformDirection( matrix );
9927 tangent.needsUpdate = true;
9931 if ( this.boundingBox !== null ) {
9933 this.computeBoundingBox();
9937 if ( this.boundingSphere !== null ) {
9939 this.computeBoundingSphere();
9947 rotateX: function ( angle ) {
9949 // rotate geometry around world x-axis
9951 _m1$2.makeRotationX( angle );
9953 this.applyMatrix4( _m1$2 );
9959 rotateY: function ( angle ) {
9961 // rotate geometry around world y-axis
9963 _m1$2.makeRotationY( angle );
9965 this.applyMatrix4( _m1$2 );
9971 rotateZ: function ( angle ) {
9973 // rotate geometry around world z-axis
9975 _m1$2.makeRotationZ( angle );
9977 this.applyMatrix4( _m1$2 );
9983 translate: function ( x, y, z ) {
9985 // translate geometry
9987 _m1$2.makeTranslation( x, y, z );
9989 this.applyMatrix4( _m1$2 );
9995 scale: function ( x, y, z ) {
9999 _m1$2.makeScale( x, y, z );
10001 this.applyMatrix4( _m1$2 );
10007 lookAt: function ( vector ) {
10009 _obj.lookAt( vector );
10011 _obj.updateMatrix();
10013 this.applyMatrix4( _obj.matrix );
10019 center: function () {
10021 this.computeBoundingBox();
10023 this.boundingBox.getCenter( _offset ).negate();
10025 this.translate( _offset.x, _offset.y, _offset.z );
10031 setFromObject: function ( object ) {
10033 // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
10035 const geometry = object.geometry;
10037 if ( object.isPoints || object.isLine ) {
10039 const positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
10040 const colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
10042 this.setAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
10043 this.setAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
10045 if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
10047 const lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
10049 this.setAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
10053 if ( geometry.boundingSphere !== null ) {
10055 this.boundingSphere = geometry.boundingSphere.clone();
10059 if ( geometry.boundingBox !== null ) {
10061 this.boundingBox = geometry.boundingBox.clone();
10065 } else if ( object.isMesh ) {
10067 if ( geometry && geometry.isGeometry ) {
10069 this.fromGeometry( geometry );
10079 setFromPoints: function ( points ) {
10081 const position = [];
10083 for ( let i = 0, l = points.length; i < l; i ++ ) {
10085 const point = points[ i ];
10086 position.push( point.x, point.y, point.z || 0 );
10090 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
10096 updateFromObject: function ( object ) {
10098 let geometry = object.geometry;
10100 if ( object.isMesh ) {
10102 let direct = geometry.__directGeometry;
10104 if ( geometry.elementsNeedUpdate === true ) {
10106 direct = undefined;
10107 geometry.elementsNeedUpdate = false;
10111 if ( direct === undefined ) {
10113 return this.fromGeometry( geometry );
10117 direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
10118 direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
10119 direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
10120 direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
10121 direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
10123 geometry.verticesNeedUpdate = false;
10124 geometry.normalsNeedUpdate = false;
10125 geometry.colorsNeedUpdate = false;
10126 geometry.uvsNeedUpdate = false;
10127 geometry.groupsNeedUpdate = false;
10133 if ( geometry.verticesNeedUpdate === true ) {
10135 const attribute = this.attributes.position;
10137 if ( attribute !== undefined ) {
10139 attribute.copyVector3sArray( geometry.vertices );
10140 attribute.needsUpdate = true;
10144 geometry.verticesNeedUpdate = false;
10148 if ( geometry.normalsNeedUpdate === true ) {
10150 const attribute = this.attributes.normal;
10152 if ( attribute !== undefined ) {
10154 attribute.copyVector3sArray( geometry.normals );
10155 attribute.needsUpdate = true;
10159 geometry.normalsNeedUpdate = false;
10163 if ( geometry.colorsNeedUpdate === true ) {
10165 const attribute = this.attributes.color;
10167 if ( attribute !== undefined ) {
10169 attribute.copyColorsArray( geometry.colors );
10170 attribute.needsUpdate = true;
10174 geometry.colorsNeedUpdate = false;
10178 if ( geometry.uvsNeedUpdate ) {
10180 const attribute = this.attributes.uv;
10182 if ( attribute !== undefined ) {
10184 attribute.copyVector2sArray( geometry.uvs );
10185 attribute.needsUpdate = true;
10189 geometry.uvsNeedUpdate = false;
10193 if ( geometry.lineDistancesNeedUpdate ) {
10195 const attribute = this.attributes.lineDistance;
10197 if ( attribute !== undefined ) {
10199 attribute.copyArray( geometry.lineDistances );
10200 attribute.needsUpdate = true;
10204 geometry.lineDistancesNeedUpdate = false;
10208 if ( geometry.groupsNeedUpdate ) {
10210 geometry.computeGroups( object.geometry );
10211 this.groups = geometry.groups;
10213 geometry.groupsNeedUpdate = false;
10221 fromGeometry: function ( geometry ) {
10223 geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
10225 return this.fromDirectGeometry( geometry.__directGeometry );
10229 fromDirectGeometry: function ( geometry ) {
10231 const positions = new Float32Array( geometry.vertices.length * 3 );
10232 this.setAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
10234 if ( geometry.normals.length > 0 ) {
10236 const normals = new Float32Array( geometry.normals.length * 3 );
10237 this.setAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
10241 if ( geometry.colors.length > 0 ) {
10243 const colors = new Float32Array( geometry.colors.length * 3 );
10244 this.setAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
10248 if ( geometry.uvs.length > 0 ) {
10250 const uvs = new Float32Array( geometry.uvs.length * 2 );
10251 this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
10255 if ( geometry.uvs2.length > 0 ) {
10257 const uvs2 = new Float32Array( geometry.uvs2.length * 2 );
10258 this.setAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
10264 this.groups = geometry.groups;
10268 for ( const name in geometry.morphTargets ) {
10271 const morphTargets = geometry.morphTargets[ name ];
10273 for ( let i = 0, l = morphTargets.length; i < l; i ++ ) {
10275 const morphTarget = morphTargets[ i ];
10277 const attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 );
10278 attribute.name = morphTarget.name;
10280 array.push( attribute.copyVector3sArray( morphTarget.data ) );
10284 this.morphAttributes[ name ] = array;
10290 if ( geometry.skinIndices.length > 0 ) {
10292 const skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
10293 this.setAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
10297 if ( geometry.skinWeights.length > 0 ) {
10299 const skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
10300 this.setAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
10306 if ( geometry.boundingSphere !== null ) {
10308 this.boundingSphere = geometry.boundingSphere.clone();
10312 if ( geometry.boundingBox !== null ) {
10314 this.boundingBox = geometry.boundingBox.clone();
10322 computeBoundingBox: function () {
10324 if ( this.boundingBox === null ) {
10326 this.boundingBox = new Box3();
10330 const position = this.attributes.position;
10331 const morphAttributesPosition = this.morphAttributes.position;
10333 if ( position && position.isGLBufferAttribute ) {
10335 console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
10337 this.boundingBox.set(
10338 new Vector3( - Infinity, - Infinity, - Infinity ),
10339 new Vector3( + Infinity, + Infinity, + Infinity )
10346 if ( position !== undefined ) {
10348 this.boundingBox.setFromBufferAttribute( position );
10350 // process morph attributes if present
10352 if ( morphAttributesPosition ) {
10354 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10356 const morphAttribute = morphAttributesPosition[ i ];
10357 _box$2.setFromBufferAttribute( morphAttribute );
10359 if ( this.morphTargetsRelative ) {
10361 _vector$4.addVectors( this.boundingBox.min, _box$2.min );
10362 this.boundingBox.expandByPoint( _vector$4 );
10364 _vector$4.addVectors( this.boundingBox.max, _box$2.max );
10365 this.boundingBox.expandByPoint( _vector$4 );
10369 this.boundingBox.expandByPoint( _box$2.min );
10370 this.boundingBox.expandByPoint( _box$2.max );
10380 this.boundingBox.makeEmpty();
10384 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
10386 console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
10392 computeBoundingSphere: function () {
10394 if ( this.boundingSphere === null ) {
10396 this.boundingSphere = new Sphere();
10400 const position = this.attributes.position;
10401 const morphAttributesPosition = this.morphAttributes.position;
10403 if ( position && position.isGLBufferAttribute ) {
10405 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
10407 this.boundingSphere.set( new Vector3(), Infinity );
10415 // first, find the center of the bounding sphere
10417 const center = this.boundingSphere.center;
10419 _box$2.setFromBufferAttribute( position );
10421 // process morph attributes if present
10423 if ( morphAttributesPosition ) {
10425 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10427 const morphAttribute = morphAttributesPosition[ i ];
10428 _boxMorphTargets.setFromBufferAttribute( morphAttribute );
10430 if ( this.morphTargetsRelative ) {
10432 _vector$4.addVectors( _box$2.min, _boxMorphTargets.min );
10433 _box$2.expandByPoint( _vector$4 );
10435 _vector$4.addVectors( _box$2.max, _boxMorphTargets.max );
10436 _box$2.expandByPoint( _vector$4 );
10440 _box$2.expandByPoint( _boxMorphTargets.min );
10441 _box$2.expandByPoint( _boxMorphTargets.max );
10449 _box$2.getCenter( center );
10451 // second, try to find a boundingSphere with a radius smaller than the
10452 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
10454 let maxRadiusSq = 0;
10456 for ( let i = 0, il = position.count; i < il; i ++ ) {
10458 _vector$4.fromBufferAttribute( position, i );
10460 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
10464 // process morph attributes if present
10466 if ( morphAttributesPosition ) {
10468 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10470 const morphAttribute = morphAttributesPosition[ i ];
10471 const morphTargetsRelative = this.morphTargetsRelative;
10473 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
10475 _vector$4.fromBufferAttribute( morphAttribute, j );
10477 if ( morphTargetsRelative ) {
10479 _offset.fromBufferAttribute( position, j );
10480 _vector$4.add( _offset );
10484 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
10492 this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
10494 if ( isNaN( this.boundingSphere.radius ) ) {
10496 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
10504 computeFaceNormals: function () {
10506 // backwards compatibility
10510 computeVertexNormals: function () {
10512 const index = this.index;
10513 const positionAttribute = this.getAttribute( 'position' );
10515 if ( positionAttribute !== undefined ) {
10517 let normalAttribute = this.getAttribute( 'normal' );
10519 if ( normalAttribute === undefined ) {
10521 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
10522 this.setAttribute( 'normal', normalAttribute );
10526 // reset existing normals to zero
10528 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
10530 normalAttribute.setXYZ( i, 0, 0, 0 );
10536 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
10537 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
10538 const cb = new Vector3(), ab = new Vector3();
10540 // indexed elements
10544 for ( let i = 0, il = index.count; i < il; i += 3 ) {
10546 const vA = index.getX( i + 0 );
10547 const vB = index.getX( i + 1 );
10548 const vC = index.getX( i + 2 );
10550 pA.fromBufferAttribute( positionAttribute, vA );
10551 pB.fromBufferAttribute( positionAttribute, vB );
10552 pC.fromBufferAttribute( positionAttribute, vC );
10554 cb.subVectors( pC, pB );
10555 ab.subVectors( pA, pB );
10558 nA.fromBufferAttribute( normalAttribute, vA );
10559 nB.fromBufferAttribute( normalAttribute, vB );
10560 nC.fromBufferAttribute( normalAttribute, vC );
10566 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
10567 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
10568 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
10574 // non-indexed elements (unconnected triangle soup)
10576 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
10578 pA.fromBufferAttribute( positionAttribute, i + 0 );
10579 pB.fromBufferAttribute( positionAttribute, i + 1 );
10580 pC.fromBufferAttribute( positionAttribute, i + 2 );
10582 cb.subVectors( pC, pB );
10583 ab.subVectors( pA, pB );
10586 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
10587 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
10588 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
10594 this.normalizeNormals();
10596 normalAttribute.needsUpdate = true;
10602 merge: function ( geometry, offset ) {
10604 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
10606 console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
10611 if ( offset === undefined ) {
10616 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
10617 + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
10622 const attributes = this.attributes;
10624 for ( const key in attributes ) {
10626 if ( geometry.attributes[ key ] === undefined ) continue;
10628 const attribute1 = attributes[ key ];
10629 const attributeArray1 = attribute1.array;
10631 const attribute2 = geometry.attributes[ key ];
10632 const attributeArray2 = attribute2.array;
10634 const attributeOffset = attribute2.itemSize * offset;
10635 const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
10637 for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
10639 attributeArray1[ j ] = attributeArray2[ i ];
10649 normalizeNormals: function () {
10651 const normals = this.attributes.normal;
10653 for ( let i = 0, il = normals.count; i < il; i ++ ) {
10655 _vector$4.fromBufferAttribute( normals, i );
10657 _vector$4.normalize();
10659 normals.setXYZ( i, _vector$4.x, _vector$4.y, _vector$4.z );
10665 toNonIndexed: function () {
10667 function convertBufferAttribute( attribute, indices ) {
10669 const array = attribute.array;
10670 const itemSize = attribute.itemSize;
10671 const normalized = attribute.normalized;
10673 const array2 = new array.constructor( indices.length * itemSize );
10675 let index = 0, index2 = 0;
10677 for ( let i = 0, l = indices.length; i < l; i ++ ) {
10679 index = indices[ i ] * itemSize;
10681 for ( let j = 0; j < itemSize; j ++ ) {
10683 array2[ index2 ++ ] = array[ index ++ ];
10689 return new BufferAttribute( array2, itemSize, normalized );
10695 if ( this.index === null ) {
10697 console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
10702 const geometry2 = new BufferGeometry();
10704 const indices = this.index.array;
10705 const attributes = this.attributes;
10709 for ( const name in attributes ) {
10711 const attribute = attributes[ name ];
10713 const newAttribute = convertBufferAttribute( attribute, indices );
10715 geometry2.setAttribute( name, newAttribute );
10719 // morph attributes
10721 const morphAttributes = this.morphAttributes;
10723 for ( const name in morphAttributes ) {
10725 const morphArray = [];
10726 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
10728 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
10730 const attribute = morphAttribute[ i ];
10732 const newAttribute = convertBufferAttribute( attribute, indices );
10734 morphArray.push( newAttribute );
10738 geometry2.morphAttributes[ name ] = morphArray;
10742 geometry2.morphTargetsRelative = this.morphTargetsRelative;
10746 const groups = this.groups;
10748 for ( let i = 0, l = groups.length; i < l; i ++ ) {
10750 const group = groups[ i ];
10751 geometry2.addGroup( group.start, group.count, group.materialIndex );
10759 toJSON: function () {
10764 type: 'BufferGeometry',
10765 generator: 'BufferGeometry.toJSON'
10769 // standard BufferGeometry serialization
10771 data.uuid = this.uuid;
10772 data.type = this.type;
10773 if ( this.name !== '' ) data.name = this.name;
10774 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
10776 if ( this.parameters !== undefined ) {
10778 const parameters = this.parameters;
10780 for ( const key in parameters ) {
10782 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
10790 data.data = { attributes: {} };
10792 const index = this.index;
10794 if ( index !== null ) {
10796 data.data.index = {
10797 type: index.array.constructor.name,
10798 array: Array.prototype.slice.call( index.array )
10803 const attributes = this.attributes;
10805 for ( const key in attributes ) {
10807 const attribute = attributes[ key ];
10809 const attributeData = attribute.toJSON( data.data );
10811 if ( attribute.name !== '' ) attributeData.name = attribute.name;
10813 data.data.attributes[ key ] = attributeData;
10817 const morphAttributes = {};
10818 let hasMorphAttributes = false;
10820 for ( const key in this.morphAttributes ) {
10822 const attributeArray = this.morphAttributes[ key ];
10826 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
10828 const attribute = attributeArray[ i ];
10830 const attributeData = attribute.toJSON( data.data );
10832 if ( attribute.name !== '' ) attributeData.name = attribute.name;
10834 array.push( attributeData );
10838 if ( array.length > 0 ) {
10840 morphAttributes[ key ] = array;
10842 hasMorphAttributes = true;
10848 if ( hasMorphAttributes ) {
10850 data.data.morphAttributes = morphAttributes;
10851 data.data.morphTargetsRelative = this.morphTargetsRelative;
10855 const groups = this.groups;
10857 if ( groups.length > 0 ) {
10859 data.data.groups = JSON.parse( JSON.stringify( groups ) );
10863 const boundingSphere = this.boundingSphere;
10865 if ( boundingSphere !== null ) {
10867 data.data.boundingSphere = {
10868 center: boundingSphere.center.toArray(),
10869 radius: boundingSphere.radius
10878 clone: function () {
10881 // Handle primitives
10883 const parameters = this.parameters;
10885 if ( parameters !== undefined ) {
10889 for ( const key in parameters ) {
10891 values.push( parameters[ key ] );
10895 const geometry = Object.create( this.constructor.prototype );
10896 this.constructor.apply( geometry, values );
10901 return new this.constructor().copy( this );
10904 return new BufferGeometry().copy( this );
10908 copy: function ( source ) {
10913 this.attributes = {};
10914 this.morphAttributes = {};
10916 this.boundingBox = null;
10917 this.boundingSphere = null;
10919 // used for storing cloned, shared data
10925 this.name = source.name;
10929 const index = source.index;
10931 if ( index !== null ) {
10933 this.setIndex( index.clone( data ) );
10939 const attributes = source.attributes;
10941 for ( const name in attributes ) {
10943 const attribute = attributes[ name ];
10944 this.setAttribute( name, attribute.clone( data ) );
10948 // morph attributes
10950 const morphAttributes = source.morphAttributes;
10952 for ( const name in morphAttributes ) {
10955 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
10957 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
10959 array.push( morphAttribute[ i ].clone( data ) );
10963 this.morphAttributes[ name ] = array;
10967 this.morphTargetsRelative = source.morphTargetsRelative;
10971 const groups = source.groups;
10973 for ( let i = 0, l = groups.length; i < l; i ++ ) {
10975 const group = groups[ i ];
10976 this.addGroup( group.start, group.count, group.materialIndex );
10982 const boundingBox = source.boundingBox;
10984 if ( boundingBox !== null ) {
10986 this.boundingBox = boundingBox.clone();
10992 const boundingSphere = source.boundingSphere;
10994 if ( boundingSphere !== null ) {
10996 this.boundingSphere = boundingSphere.clone();
11002 this.drawRange.start = source.drawRange.start;
11003 this.drawRange.count = source.drawRange.count;
11007 this.userData = source.userData;
11013 dispose: function () {
11015 this.dispatchEvent( { type: 'dispose' } );
11021 const _inverseMatrix = new Matrix4();
11022 const _ray = new Ray();
11023 const _sphere = new Sphere();
11025 const _vA = new Vector3();
11026 const _vB = new Vector3();
11027 const _vC = new Vector3();
11029 const _tempA = new Vector3();
11030 const _tempB = new Vector3();
11031 const _tempC = new Vector3();
11033 const _morphA = new Vector3();
11034 const _morphB = new Vector3();
11035 const _morphC = new Vector3();
11037 const _uvA = new Vector2();
11038 const _uvB = new Vector2();
11039 const _uvC = new Vector2();
11041 const _intersectionPoint = new Vector3();
11042 const _intersectionPointWorld = new Vector3();
11044 function Mesh( geometry, material ) {
11046 Object3D.call( this );
11048 this.type = 'Mesh';
11050 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
11051 this.material = material !== undefined ? material : new MeshBasicMaterial();
11053 this.updateMorphTargets();
11057 Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
11063 copy: function ( source ) {
11065 Object3D.prototype.copy.call( this, source );
11067 if ( source.morphTargetInfluences !== undefined ) {
11069 this.morphTargetInfluences = source.morphTargetInfluences.slice();
11073 if ( source.morphTargetDictionary !== undefined ) {
11075 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
11079 this.material = source.material;
11080 this.geometry = source.geometry;
11086 updateMorphTargets: function () {
11088 const geometry = this.geometry;
11090 if ( geometry.isBufferGeometry ) {
11092 const morphAttributes = geometry.morphAttributes;
11093 const keys = Object.keys( morphAttributes );
11095 if ( keys.length > 0 ) {
11097 const morphAttribute = morphAttributes[ keys[ 0 ] ];
11099 if ( morphAttribute !== undefined ) {
11101 this.morphTargetInfluences = [];
11102 this.morphTargetDictionary = {};
11104 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
11106 const name = morphAttribute[ m ].name || String( m );
11108 this.morphTargetInfluences.push( 0 );
11109 this.morphTargetDictionary[ name ] = m;
11119 const morphTargets = geometry.morphTargets;
11121 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
11123 console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
11131 raycast: function ( raycaster, intersects ) {
11133 const geometry = this.geometry;
11134 const material = this.material;
11135 const matrixWorld = this.matrixWorld;
11137 if ( material === undefined ) return;
11139 // Checking boundingSphere distance to ray
11141 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
11143 _sphere.copy( geometry.boundingSphere );
11144 _sphere.applyMatrix4( matrixWorld );
11146 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
11150 _inverseMatrix.copy( matrixWorld ).invert();
11151 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
11153 // Check boundingBox before continuing
11155 if ( geometry.boundingBox !== null ) {
11157 if ( _ray.intersectsBox( geometry.boundingBox ) === false ) return;
11163 if ( geometry.isBufferGeometry ) {
11165 const index = geometry.index;
11166 const position = geometry.attributes.position;
11167 const morphPosition = geometry.morphAttributes.position;
11168 const morphTargetsRelative = geometry.morphTargetsRelative;
11169 const uv = geometry.attributes.uv;
11170 const uv2 = geometry.attributes.uv2;
11171 const groups = geometry.groups;
11172 const drawRange = geometry.drawRange;
11174 if ( index !== null ) {
11176 // indexed buffer geometry
11178 if ( Array.isArray( material ) ) {
11180 for ( let i = 0, il = groups.length; i < il; i ++ ) {
11182 const group = groups[ i ];
11183 const groupMaterial = material[ group.materialIndex ];
11185 const start = Math.max( group.start, drawRange.start );
11186 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
11188 for ( let j = start, jl = end; j < jl; j += 3 ) {
11190 const a = index.getX( j );
11191 const b = index.getX( j + 1 );
11192 const c = index.getX( j + 2 );
11194 intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
11196 if ( intersection ) {
11198 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
11199 intersection.face.materialIndex = group.materialIndex;
11200 intersects.push( intersection );
11210 const start = Math.max( 0, drawRange.start );
11211 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
11213 for ( let i = start, il = end; i < il; i += 3 ) {
11215 const a = index.getX( i );
11216 const b = index.getX( i + 1 );
11217 const c = index.getX( i + 2 );
11219 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
11221 if ( intersection ) {
11223 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
11224 intersects.push( intersection );
11232 } else if ( position !== undefined ) {
11234 // non-indexed buffer geometry
11236 if ( Array.isArray( material ) ) {
11238 for ( let i = 0, il = groups.length; i < il; i ++ ) {
11240 const group = groups[ i ];
11241 const groupMaterial = material[ group.materialIndex ];
11243 const start = Math.max( group.start, drawRange.start );
11244 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
11246 for ( let j = start, jl = end; j < jl; j += 3 ) {
11252 intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
11254 if ( intersection ) {
11256 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
11257 intersection.face.materialIndex = group.materialIndex;
11258 intersects.push( intersection );
11268 const start = Math.max( 0, drawRange.start );
11269 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
11271 for ( let i = start, il = end; i < il; i += 3 ) {
11277 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
11279 if ( intersection ) {
11281 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
11282 intersects.push( intersection );
11292 } else if ( geometry.isGeometry ) {
11294 const isMultiMaterial = Array.isArray( material );
11296 const vertices = geometry.vertices;
11297 const faces = geometry.faces;
11300 const faceVertexUvs = geometry.faceVertexUvs[ 0 ];
11301 if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
11303 for ( let f = 0, fl = faces.length; f < fl; f ++ ) {
11305 const face = faces[ f ];
11306 const faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;
11308 if ( faceMaterial === undefined ) continue;
11310 const fvA = vertices[ face.a ];
11311 const fvB = vertices[ face.b ];
11312 const fvC = vertices[ face.c ];
11314 intersection = checkIntersection( this, faceMaterial, raycaster, _ray, fvA, fvB, fvC, _intersectionPoint );
11316 if ( intersection ) {
11318 if ( uvs && uvs[ f ] ) {
11320 const uvs_f = uvs[ f ];
11321 _uvA.copy( uvs_f[ 0 ] );
11322 _uvB.copy( uvs_f[ 1 ] );
11323 _uvC.copy( uvs_f[ 2 ] );
11325 intersection.uv = Triangle.getUV( _intersectionPoint, fvA, fvB, fvC, _uvA, _uvB, _uvC, new Vector2() );
11329 intersection.face = face;
11330 intersection.faceIndex = f;
11331 intersects.push( intersection );
11343 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
11347 if ( material.side === BackSide ) {
11349 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
11353 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
11357 if ( intersect === null ) return null;
11359 _intersectionPointWorld.copy( point );
11360 _intersectionPointWorld.applyMatrix4( object.matrixWorld );
11362 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
11364 if ( distance < raycaster.near || distance > raycaster.far ) return null;
11367 distance: distance,
11368 point: _intersectionPointWorld.clone(),
11374 function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
11376 _vA.fromBufferAttribute( position, a );
11377 _vB.fromBufferAttribute( position, b );
11378 _vC.fromBufferAttribute( position, c );
11380 const morphInfluences = object.morphTargetInfluences;
11382 if ( material.morphTargets && morphPosition && morphInfluences ) {
11384 _morphA.set( 0, 0, 0 );
11385 _morphB.set( 0, 0, 0 );
11386 _morphC.set( 0, 0, 0 );
11388 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
11390 const influence = morphInfluences[ i ];
11391 const morphAttribute = morphPosition[ i ];
11393 if ( influence === 0 ) continue;
11395 _tempA.fromBufferAttribute( morphAttribute, a );
11396 _tempB.fromBufferAttribute( morphAttribute, b );
11397 _tempC.fromBufferAttribute( morphAttribute, c );
11399 if ( morphTargetsRelative ) {
11401 _morphA.addScaledVector( _tempA, influence );
11402 _morphB.addScaledVector( _tempB, influence );
11403 _morphC.addScaledVector( _tempC, influence );
11407 _morphA.addScaledVector( _tempA.sub( _vA ), influence );
11408 _morphB.addScaledVector( _tempB.sub( _vB ), influence );
11409 _morphC.addScaledVector( _tempC.sub( _vC ), influence );
11415 _vA.add( _morphA );
11416 _vB.add( _morphB );
11417 _vC.add( _morphC );
11421 if ( object.isSkinnedMesh ) {
11423 object.boneTransform( a, _vA );
11424 object.boneTransform( b, _vB );
11425 object.boneTransform( c, _vC );
11429 const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
11431 if ( intersection ) {
11435 _uvA.fromBufferAttribute( uv, a );
11436 _uvB.fromBufferAttribute( uv, b );
11437 _uvC.fromBufferAttribute( uv, c );
11439 intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
11445 _uvA.fromBufferAttribute( uv2, a );
11446 _uvB.fromBufferAttribute( uv2, b );
11447 _uvC.fromBufferAttribute( uv2, c );
11449 intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
11453 const face = new Face3( a, b, c );
11454 Triangle.getNormal( _vA, _vB, _vC, face.normal );
11456 intersection.face = face;
11460 return intersection;
11464 class BoxBufferGeometry extends BufferGeometry {
11466 constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
11470 this.type = 'BoxBufferGeometry';
11472 this.parameters = {
11476 widthSegments: widthSegments,
11477 heightSegments: heightSegments,
11478 depthSegments: depthSegments
11481 const scope = this;
11485 widthSegments = Math.floor( widthSegments );
11486 heightSegments = Math.floor( heightSegments );
11487 depthSegments = Math.floor( depthSegments );
11491 const indices = [];
11492 const vertices = [];
11493 const normals = [];
11496 // helper variables
11498 let numberOfVertices = 0;
11499 let groupStart = 0;
11501 // build each side of the box geometry
11503 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
11504 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
11505 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
11506 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
11507 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
11508 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
11512 this.setIndex( indices );
11513 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
11514 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
11515 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
11517 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
11519 const segmentWidth = width / gridX;
11520 const segmentHeight = height / gridY;
11522 const widthHalf = width / 2;
11523 const heightHalf = height / 2;
11524 const depthHalf = depth / 2;
11526 const gridX1 = gridX + 1;
11527 const gridY1 = gridY + 1;
11529 let vertexCounter = 0;
11530 let groupCount = 0;
11532 const vector = new Vector3();
11534 // generate vertices, normals and uvs
11536 for ( let iy = 0; iy < gridY1; iy ++ ) {
11538 const y = iy * segmentHeight - heightHalf;
11540 for ( let ix = 0; ix < gridX1; ix ++ ) {
11542 const x = ix * segmentWidth - widthHalf;
11544 // set values to correct vector component
11546 vector[ u ] = x * udir;
11547 vector[ v ] = y * vdir;
11548 vector[ w ] = depthHalf;
11550 // now apply vector to vertex buffer
11552 vertices.push( vector.x, vector.y, vector.z );
11554 // set values to correct vector component
11558 vector[ w ] = depth > 0 ? 1 : - 1;
11560 // now apply vector to normal buffer
11562 normals.push( vector.x, vector.y, vector.z );
11566 uvs.push( ix / gridX );
11567 uvs.push( 1 - ( iy / gridY ) );
11571 vertexCounter += 1;
11579 // 1. you need three indices to draw a single face
11580 // 2. a single segment consists of two faces
11581 // 3. so we need to generate six (2*3) indices per segment
11583 for ( let iy = 0; iy < gridY; iy ++ ) {
11585 for ( let ix = 0; ix < gridX; ix ++ ) {
11587 const a = numberOfVertices + ix + gridX1 * iy;
11588 const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
11589 const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
11590 const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
11594 indices.push( a, b, d );
11595 indices.push( b, c, d );
11597 // increase counter
11605 // add a group to the geometry. this will ensure multi material support
11607 scope.addGroup( groupStart, groupCount, materialIndex );
11609 // calculate new start value for groups
11611 groupStart += groupCount;
11613 // update total number of vertices
11615 numberOfVertices += vertexCounter;
11624 * Uniform Utilities
11627 function cloneUniforms( src ) {
11631 for ( const u in src ) {
11635 for ( const p in src[ u ] ) {
11637 const property = src[ u ][ p ];
11639 if ( property && ( property.isColor ||
11640 property.isMatrix3 || property.isMatrix4 ||
11641 property.isVector2 || property.isVector3 || property.isVector4 ||
11642 property.isTexture ) ) {
11644 dst[ u ][ p ] = property.clone();
11646 } else if ( Array.isArray( property ) ) {
11648 dst[ u ][ p ] = property.slice();
11652 dst[ u ][ p ] = property;
11664 function mergeUniforms( uniforms ) {
11668 for ( let u = 0; u < uniforms.length; u ++ ) {
11670 const tmp = cloneUniforms( uniforms[ u ] );
11672 for ( const p in tmp ) {
11674 merged[ p ] = tmp[ p ];
11686 const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
11688 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
11690 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
11694 * defines: { "label" : "value" },
11695 * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
11697 * fragmentShader: <string>,
11698 * vertexShader: <string>,
11700 * wireframe: <boolean>,
11701 * wireframeLinewidth: <float>,
11705 * skinning: <bool>,
11706 * morphTargets: <bool>,
11707 * morphNormals: <bool>
11711 function ShaderMaterial( parameters ) {
11713 Material.call( this );
11715 this.type = 'ShaderMaterial';
11718 this.uniforms = {};
11720 this.vertexShader = default_vertex;
11721 this.fragmentShader = default_fragment;
11723 this.linewidth = 1;
11725 this.wireframe = false;
11726 this.wireframeLinewidth = 1;
11728 this.fog = false; // set to use scene fog
11729 this.lights = false; // set to use scene lights
11730 this.clipping = false; // set to use user-defined clipping planes
11732 this.skinning = false; // set to use skinning attribute streams
11733 this.morphTargets = false; // set to use morph targets
11734 this.morphNormals = false; // set to use morph normals
11736 this.extensions = {
11737 derivatives: false, // set to use derivatives
11738 fragDepth: false, // set to use fragment depth values
11739 drawBuffers: false, // set to use draw buffers
11740 shaderTextureLOD: false // set to use shader texture LOD
11743 // When rendered geometry doesn't include these attributes but the material does,
11744 // use these default values in WebGL. This avoids errors when buffer data is missing.
11745 this.defaultAttributeValues = {
11746 'color': [ 1, 1, 1 ],
11751 this.index0AttributeName = undefined;
11752 this.uniformsNeedUpdate = false;
11754 this.glslVersion = null;
11756 if ( parameters !== undefined ) {
11758 if ( parameters.attributes !== undefined ) {
11760 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
11764 this.setValues( parameters );
11770 ShaderMaterial.prototype = Object.create( Material.prototype );
11771 ShaderMaterial.prototype.constructor = ShaderMaterial;
11773 ShaderMaterial.prototype.isShaderMaterial = true;
11775 ShaderMaterial.prototype.copy = function ( source ) {
11777 Material.prototype.copy.call( this, source );
11779 this.fragmentShader = source.fragmentShader;
11780 this.vertexShader = source.vertexShader;
11782 this.uniforms = cloneUniforms( source.uniforms );
11784 this.defines = Object.assign( {}, source.defines );
11786 this.wireframe = source.wireframe;
11787 this.wireframeLinewidth = source.wireframeLinewidth;
11789 this.lights = source.lights;
11790 this.clipping = source.clipping;
11792 this.skinning = source.skinning;
11794 this.morphTargets = source.morphTargets;
11795 this.morphNormals = source.morphNormals;
11797 this.extensions = Object.assign( {}, source.extensions );
11799 this.glslVersion = source.glslVersion;
11805 ShaderMaterial.prototype.toJSON = function ( meta ) {
11807 const data = Material.prototype.toJSON.call( this, meta );
11809 data.glslVersion = this.glslVersion;
11810 data.uniforms = {};
11812 for ( const name in this.uniforms ) {
11814 const uniform = this.uniforms[ name ];
11815 const value = uniform.value;
11817 if ( value && value.isTexture ) {
11819 data.uniforms[ name ] = {
11821 value: value.toJSON( meta ).uuid
11824 } else if ( value && value.isColor ) {
11826 data.uniforms[ name ] = {
11828 value: value.getHex()
11831 } else if ( value && value.isVector2 ) {
11833 data.uniforms[ name ] = {
11835 value: value.toArray()
11838 } else if ( value && value.isVector3 ) {
11840 data.uniforms[ name ] = {
11842 value: value.toArray()
11845 } else if ( value && value.isVector4 ) {
11847 data.uniforms[ name ] = {
11849 value: value.toArray()
11852 } else if ( value && value.isMatrix3 ) {
11854 data.uniforms[ name ] = {
11856 value: value.toArray()
11859 } else if ( value && value.isMatrix4 ) {
11861 data.uniforms[ name ] = {
11863 value: value.toArray()
11868 data.uniforms[ name ] = {
11872 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
11878 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
11880 data.vertexShader = this.vertexShader;
11881 data.fragmentShader = this.fragmentShader;
11883 const extensions = {};
11885 for ( const key in this.extensions ) {
11887 if ( this.extensions[ key ] === true ) extensions[ key ] = true;
11891 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
11897 function Camera() {
11899 Object3D.call( this );
11901 this.type = 'Camera';
11903 this.matrixWorldInverse = new Matrix4();
11905 this.projectionMatrix = new Matrix4();
11906 this.projectionMatrixInverse = new Matrix4();
11910 Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
11912 constructor: Camera,
11916 copy: function ( source, recursive ) {
11918 Object3D.prototype.copy.call( this, source, recursive );
11920 this.matrixWorldInverse.copy( source.matrixWorldInverse );
11922 this.projectionMatrix.copy( source.projectionMatrix );
11923 this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
11929 getWorldDirection: function ( target ) {
11931 if ( target === undefined ) {
11933 console.warn( 'THREE.Camera: .getWorldDirection() target is now required' );
11934 target = new Vector3();
11938 this.updateWorldMatrix( true, false );
11940 const e = this.matrixWorld.elements;
11942 return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize();
11946 updateMatrixWorld: function ( force ) {
11948 Object3D.prototype.updateMatrixWorld.call( this, force );
11950 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
11954 updateWorldMatrix: function ( updateParents, updateChildren ) {
11956 Object3D.prototype.updateWorldMatrix.call( this, updateParents, updateChildren );
11958 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
11962 clone: function () {
11964 return new this.constructor().copy( this );
11970 function PerspectiveCamera( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
11972 Camera.call( this );
11974 this.type = 'PerspectiveCamera';
11983 this.aspect = aspect;
11986 this.filmGauge = 35; // width of the film (default in millimeters)
11987 this.filmOffset = 0; // horizontal film offset (same unit as gauge)
11989 this.updateProjectionMatrix();
11993 PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
11995 constructor: PerspectiveCamera,
11997 isPerspectiveCamera: true,
11999 copy: function ( source, recursive ) {
12001 Camera.prototype.copy.call( this, source, recursive );
12003 this.fov = source.fov;
12004 this.zoom = source.zoom;
12006 this.near = source.near;
12007 this.far = source.far;
12008 this.focus = source.focus;
12010 this.aspect = source.aspect;
12011 this.view = source.view === null ? null : Object.assign( {}, source.view );
12013 this.filmGauge = source.filmGauge;
12014 this.filmOffset = source.filmOffset;
12021 * Sets the FOV by focal length in respect to the current .filmGauge.
12023 * The default film gauge is 35, so that the focal length can be specified for
12024 * a 35mm (full frame) camera.
12026 * Values for focal length and film gauge must have the same unit.
12028 setFocalLength: function ( focalLength ) {
12030 // see http://www.bobatkins.com/photography/technical/field_of_view.html
12031 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
12033 this.fov = MathUtils.RAD2DEG * 2 * Math.atan( vExtentSlope );
12034 this.updateProjectionMatrix();
12039 * Calculates the focal length from the current .fov and .filmGauge.
12041 getFocalLength: function () {
12043 const vExtentSlope = Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov );
12045 return 0.5 * this.getFilmHeight() / vExtentSlope;
12049 getEffectiveFOV: function () {
12051 return MathUtils.RAD2DEG * 2 * Math.atan(
12052 Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom );
12056 getFilmWidth: function () {
12058 // film not completely covered in portrait format (aspect < 1)
12059 return this.filmGauge * Math.min( this.aspect, 1 );
12063 getFilmHeight: function () {
12065 // film not completely covered in landscape format (aspect > 1)
12066 return this.filmGauge / Math.max( this.aspect, 1 );
12071 * Sets an offset in a larger frustum. This is useful for multi-window or
12072 * multi-monitor/multi-machine setups.
12074 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
12075 * the monitors are in grid like this
12083 * then for each monitor you would call it like this
12087 * const fullWidth = w * 3;
12088 * const fullHeight = h * 2;
12091 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
12093 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
12095 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
12097 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
12099 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
12101 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
12103 * Note there is no reason monitors have to be the same size or in a grid.
12105 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
12107 this.aspect = fullWidth / fullHeight;
12109 if ( this.view === null ) {
12123 this.view.enabled = true;
12124 this.view.fullWidth = fullWidth;
12125 this.view.fullHeight = fullHeight;
12126 this.view.offsetX = x;
12127 this.view.offsetY = y;
12128 this.view.width = width;
12129 this.view.height = height;
12131 this.updateProjectionMatrix();
12135 clearViewOffset: function () {
12137 if ( this.view !== null ) {
12139 this.view.enabled = false;
12143 this.updateProjectionMatrix();
12147 updateProjectionMatrix: function () {
12149 const near = this.near;
12150 let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
12151 let height = 2 * top;
12152 let width = this.aspect * height;
12153 let left = - 0.5 * width;
12154 const view = this.view;
12156 if ( this.view !== null && this.view.enabled ) {
12158 const fullWidth = view.fullWidth,
12159 fullHeight = view.fullHeight;
12161 left += view.offsetX * width / fullWidth;
12162 top -= view.offsetY * height / fullHeight;
12163 width *= view.width / fullWidth;
12164 height *= view.height / fullHeight;
12168 const skew = this.filmOffset;
12169 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
12171 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
12173 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
12177 toJSON: function ( meta ) {
12179 const data = Object3D.prototype.toJSON.call( this, meta );
12181 data.object.fov = this.fov;
12182 data.object.zoom = this.zoom;
12184 data.object.near = this.near;
12185 data.object.far = this.far;
12186 data.object.focus = this.focus;
12188 data.object.aspect = this.aspect;
12190 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12192 data.object.filmGauge = this.filmGauge;
12193 data.object.filmOffset = this.filmOffset;
12201 const fov = 90, aspect = 1;
12203 function CubeCamera( near, far, renderTarget ) {
12205 Object3D.call( this );
12207 this.type = 'CubeCamera';
12209 if ( renderTarget.isWebGLCubeRenderTarget !== true ) {
12211 console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' );
12216 this.renderTarget = renderTarget;
12218 const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
12219 cameraPX.layers = this.layers;
12220 cameraPX.up.set( 0, - 1, 0 );
12221 cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
12222 this.add( cameraPX );
12224 const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
12225 cameraNX.layers = this.layers;
12226 cameraNX.up.set( 0, - 1, 0 );
12227 cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
12228 this.add( cameraNX );
12230 const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
12231 cameraPY.layers = this.layers;
12232 cameraPY.up.set( 0, 0, 1 );
12233 cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
12234 this.add( cameraPY );
12236 const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
12237 cameraNY.layers = this.layers;
12238 cameraNY.up.set( 0, 0, - 1 );
12239 cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
12240 this.add( cameraNY );
12242 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
12243 cameraPZ.layers = this.layers;
12244 cameraPZ.up.set( 0, - 1, 0 );
12245 cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
12246 this.add( cameraPZ );
12248 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
12249 cameraNZ.layers = this.layers;
12250 cameraNZ.up.set( 0, - 1, 0 );
12251 cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
12252 this.add( cameraNZ );
12254 this.update = function ( renderer, scene ) {
12256 if ( this.parent === null ) this.updateMatrixWorld();
12258 const currentXrEnabled = renderer.xr.enabled;
12259 const currentRenderTarget = renderer.getRenderTarget();
12261 renderer.xr.enabled = false;
12263 const generateMipmaps = renderTarget.texture.generateMipmaps;
12265 renderTarget.texture.generateMipmaps = false;
12267 renderer.setRenderTarget( renderTarget, 0 );
12268 renderer.render( scene, cameraPX );
12270 renderer.setRenderTarget( renderTarget, 1 );
12271 renderer.render( scene, cameraNX );
12273 renderer.setRenderTarget( renderTarget, 2 );
12274 renderer.render( scene, cameraPY );
12276 renderer.setRenderTarget( renderTarget, 3 );
12277 renderer.render( scene, cameraNY );
12279 renderer.setRenderTarget( renderTarget, 4 );
12280 renderer.render( scene, cameraPZ );
12282 renderTarget.texture.generateMipmaps = generateMipmaps;
12284 renderer.setRenderTarget( renderTarget, 5 );
12285 renderer.render( scene, cameraNZ );
12287 renderer.setRenderTarget( currentRenderTarget );
12289 renderer.xr.enabled = currentXrEnabled;
12295 CubeCamera.prototype = Object.create( Object3D.prototype );
12296 CubeCamera.prototype.constructor = CubeCamera;
12298 function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
12300 images = images !== undefined ? images : [];
12301 mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
12302 format = format !== undefined ? format : RGBFormat;
12304 Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
12306 this.flipY = false;
12308 // Why CubeTexture._needsFlipEnvMap is necessary:
12310 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
12311 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
12312 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
12314 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
12315 // and the flag _needsFlipEnvMap controls this conversion. The flip is not required (and thus _needsFlipEnvMap is set to false)
12316 // when using WebGLCubeRenderTarget.texture as a cube texture.
12318 this._needsFlipEnvMap = true;
12322 CubeTexture.prototype = Object.create( Texture.prototype );
12323 CubeTexture.prototype.constructor = CubeTexture;
12325 CubeTexture.prototype.isCubeTexture = true;
12327 Object.defineProperty( CubeTexture.prototype, 'images', {
12335 set: function ( value ) {
12337 this.image = value;
12343 function WebGLCubeRenderTarget( size, options, dummy ) {
12345 if ( Number.isInteger( options ) ) {
12347 console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' );
12353 WebGLRenderTarget.call( this, size, size, options );
12355 options = options || {};
12357 this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
12359 this.texture._needsFlipEnvMap = false;
12363 WebGLCubeRenderTarget.prototype = Object.create( WebGLRenderTarget.prototype );
12364 WebGLCubeRenderTarget.prototype.constructor = WebGLCubeRenderTarget;
12366 WebGLCubeRenderTarget.prototype.isWebGLCubeRenderTarget = true;
12368 WebGLCubeRenderTarget.prototype.fromEquirectangularTexture = function ( renderer, texture ) {
12370 this.texture.type = texture.type;
12371 this.texture.format = RGBAFormat; // see #18859
12372 this.texture.encoding = texture.encoding;
12374 this.texture.generateMipmaps = texture.generateMipmaps;
12375 this.texture.minFilter = texture.minFilter;
12376 this.texture.magFilter = texture.magFilter;
12381 tEquirect: { value: null },
12384 vertexShader: /* glsl */`
12386 varying vec3 vWorldDirection;
12388 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
12390 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
12396 vWorldDirection = transformDirection( position, modelMatrix );
12398 #include <begin_vertex>
12399 #include <project_vertex>
12404 fragmentShader: /* glsl */`
12406 uniform sampler2D tEquirect;
12408 varying vec3 vWorldDirection;
12414 vec3 direction = normalize( vWorldDirection );
12416 vec2 sampleUV = equirectUv( direction );
12418 gl_FragColor = texture2D( tEquirect, sampleUV );
12424 const geometry = new BoxBufferGeometry( 5, 5, 5 );
12426 const material = new ShaderMaterial( {
12428 name: 'CubemapFromEquirect',
12430 uniforms: cloneUniforms( shader.uniforms ),
12431 vertexShader: shader.vertexShader,
12432 fragmentShader: shader.fragmentShader,
12434 blending: NoBlending
12438 material.uniforms.tEquirect.value = texture;
12440 const mesh = new Mesh( geometry, material );
12442 const currentMinFilter = texture.minFilter;
12444 // Avoid blurred poles
12445 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
12447 const camera = new CubeCamera( 1, 10, this );
12448 camera.update( renderer, mesh );
12450 texture.minFilter = currentMinFilter;
12452 mesh.geometry.dispose();
12453 mesh.material.dispose();
12459 WebGLCubeRenderTarget.prototype.clear = function ( renderer, color, depth, stencil ) {
12461 const currentRenderTarget = renderer.getRenderTarget();
12463 for ( let i = 0; i < 6; i ++ ) {
12465 renderer.setRenderTarget( this, i );
12467 renderer.clear( color, depth, stencil );
12471 renderer.setRenderTarget( currentRenderTarget );
12475 function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
12477 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
12479 this.image = { data: data || null, width: width || 1, height: height || 1 };
12481 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
12482 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
12484 this.generateMipmaps = false;
12485 this.flipY = false;
12486 this.unpackAlignment = 1;
12488 this.needsUpdate = true;
12492 DataTexture.prototype = Object.create( Texture.prototype );
12493 DataTexture.prototype.constructor = DataTexture;
12495 DataTexture.prototype.isDataTexture = true;
12497 const _sphere$1 = /*@__PURE__*/ new Sphere();
12498 const _vector$5 = /*@__PURE__*/ new Vector3();
12502 constructor( p0, p1, p2, p3, p4, p5 ) {
12506 ( p0 !== undefined ) ? p0 : new Plane(),
12507 ( p1 !== undefined ) ? p1 : new Plane(),
12508 ( p2 !== undefined ) ? p2 : new Plane(),
12509 ( p3 !== undefined ) ? p3 : new Plane(),
12510 ( p4 !== undefined ) ? p4 : new Plane(),
12511 ( p5 !== undefined ) ? p5 : new Plane()
12517 set( p0, p1, p2, p3, p4, p5 ) {
12519 const planes = this.planes;
12521 planes[ 0 ].copy( p0 );
12522 planes[ 1 ].copy( p1 );
12523 planes[ 2 ].copy( p2 );
12524 planes[ 3 ].copy( p3 );
12525 planes[ 4 ].copy( p4 );
12526 planes[ 5 ].copy( p5 );
12534 return new this.constructor().copy( this );
12540 const planes = this.planes;
12542 for ( let i = 0; i < 6; i ++ ) {
12544 planes[ i ].copy( frustum.planes[ i ] );
12552 setFromProjectionMatrix( m ) {
12554 const planes = this.planes;
12555 const me = m.elements;
12556 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
12557 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
12558 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
12559 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
12561 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
12562 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
12563 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
12564 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
12565 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
12566 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
12572 intersectsObject( object ) {
12574 const geometry = object.geometry;
12576 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
12578 _sphere$1.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
12580 return this.intersectsSphere( _sphere$1 );
12584 intersectsSprite( sprite ) {
12586 _sphere$1.center.set( 0, 0, 0 );
12587 _sphere$1.radius = 0.7071067811865476;
12588 _sphere$1.applyMatrix4( sprite.matrixWorld );
12590 return this.intersectsSphere( _sphere$1 );
12594 intersectsSphere( sphere ) {
12596 const planes = this.planes;
12597 const center = sphere.center;
12598 const negRadius = - sphere.radius;
12600 for ( let i = 0; i < 6; i ++ ) {
12602 const distance = planes[ i ].distanceToPoint( center );
12604 if ( distance < negRadius ) {
12616 intersectsBox( box ) {
12618 const planes = this.planes;
12620 for ( let i = 0; i < 6; i ++ ) {
12622 const plane = planes[ i ];
12624 // corner at max distance
12626 _vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x;
12627 _vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y;
12628 _vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z;
12630 if ( plane.distanceToPoint( _vector$5 ) < 0 ) {
12642 containsPoint( point ) {
12644 const planes = this.planes;
12646 for ( let i = 0; i < 6; i ++ ) {
12648 if ( planes[ i ].distanceToPoint( point ) < 0 ) {
12662 function WebGLAnimation() {
12664 let context = null;
12665 let isAnimating = false;
12666 let animationLoop = null;
12667 let requestId = null;
12669 function onAnimationFrame( time, frame ) {
12671 animationLoop( time, frame );
12673 requestId = context.requestAnimationFrame( onAnimationFrame );
12679 start: function () {
12681 if ( isAnimating === true ) return;
12682 if ( animationLoop === null ) return;
12684 requestId = context.requestAnimationFrame( onAnimationFrame );
12686 isAnimating = true;
12690 stop: function () {
12692 context.cancelAnimationFrame( requestId );
12694 isAnimating = false;
12698 setAnimationLoop: function ( callback ) {
12700 animationLoop = callback;
12704 setContext: function ( value ) {
12714 function WebGLAttributes( gl, capabilities ) {
12716 const isWebGL2 = capabilities.isWebGL2;
12718 const buffers = new WeakMap();
12720 function createBuffer( attribute, bufferType ) {
12722 const array = attribute.array;
12723 const usage = attribute.usage;
12725 const buffer = gl.createBuffer();
12727 gl.bindBuffer( bufferType, buffer );
12728 gl.bufferData( bufferType, array, usage );
12730 attribute.onUploadCallback();
12734 if ( array instanceof Float32Array ) {
12738 } else if ( array instanceof Float64Array ) {
12740 console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
12742 } else if ( array instanceof Uint16Array ) {
12744 if ( attribute.isFloat16BufferAttribute ) {
12752 console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
12762 } else if ( array instanceof Int16Array ) {
12766 } else if ( array instanceof Uint32Array ) {
12770 } else if ( array instanceof Int32Array ) {
12774 } else if ( array instanceof Int8Array ) {
12778 } else if ( array instanceof Uint8Array ) {
12787 bytesPerElement: array.BYTES_PER_ELEMENT,
12788 version: attribute.version
12793 function updateBuffer( buffer, attribute, bufferType ) {
12795 const array = attribute.array;
12796 const updateRange = attribute.updateRange;
12798 gl.bindBuffer( bufferType, buffer );
12800 if ( updateRange.count === - 1 ) {
12802 // Not using update ranges
12804 gl.bufferSubData( bufferType, 0, array );
12810 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
12811 array, updateRange.offset, updateRange.count );
12815 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
12816 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
12820 updateRange.count = - 1; // reset range
12828 function get( attribute ) {
12830 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12832 return buffers.get( attribute );
12836 function remove( attribute ) {
12838 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12840 const data = buffers.get( attribute );
12844 gl.deleteBuffer( data.buffer );
12846 buffers.delete( attribute );
12852 function update( attribute, bufferType ) {
12854 if ( attribute.isGLBufferAttribute ) {
12856 const cached = buffers.get( attribute );
12858 if ( ! cached || cached.version < attribute.version ) {
12860 buffers.set( attribute, {
12861 buffer: attribute.buffer,
12862 type: attribute.type,
12863 bytesPerElement: attribute.elementSize,
12864 version: attribute.version
12873 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12875 const data = buffers.get( attribute );
12877 if ( data === undefined ) {
12879 buffers.set( attribute, createBuffer( attribute, bufferType ) );
12881 } else if ( data.version < attribute.version ) {
12883 updateBuffer( data.buffer, attribute, bufferType );
12885 data.version = attribute.version;
12901 class PlaneBufferGeometry extends BufferGeometry {
12903 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
12906 this.type = 'PlaneBufferGeometry';
12908 this.parameters = {
12911 widthSegments: widthSegments,
12912 heightSegments: heightSegments
12915 const width_half = width / 2;
12916 const height_half = height / 2;
12918 const gridX = Math.floor( widthSegments );
12919 const gridY = Math.floor( heightSegments );
12921 const gridX1 = gridX + 1;
12922 const gridY1 = gridY + 1;
12924 const segment_width = width / gridX;
12925 const segment_height = height / gridY;
12929 const indices = [];
12930 const vertices = [];
12931 const normals = [];
12934 for ( let iy = 0; iy < gridY1; iy ++ ) {
12936 const y = iy * segment_height - height_half;
12938 for ( let ix = 0; ix < gridX1; ix ++ ) {
12940 const x = ix * segment_width - width_half;
12942 vertices.push( x, - y, 0 );
12944 normals.push( 0, 0, 1 );
12946 uvs.push( ix / gridX );
12947 uvs.push( 1 - ( iy / gridY ) );
12953 for ( let iy = 0; iy < gridY; iy ++ ) {
12955 for ( let ix = 0; ix < gridX; ix ++ ) {
12957 const a = ix + gridX1 * iy;
12958 const b = ix + gridX1 * ( iy + 1 );
12959 const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
12960 const d = ( ix + 1 ) + gridX1 * iy;
12962 indices.push( a, b, d );
12963 indices.push( b, c, d );
12969 this.setIndex( indices );
12970 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
12971 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
12972 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
12978 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
12980 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
12982 var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif";
12984 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";
12986 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
12988 var begin_vertex = "vec3 transformed = vec3( position );";
12990 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
12992 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";
12994 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";
12996 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";
12998 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
13000 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
13002 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
13004 var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
13006 var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
13008 var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
13010 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";
13012 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}";
13014 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";
13016 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";
13018 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
13020 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
13022 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
13024 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
13026 var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
13028 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}";
13030 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";
13032 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";
13034 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";
13036 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";
13038 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";
13040 var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif";
13042 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif";
13044 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";
13046 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";
13048 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}";
13050 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif";
13052 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
13054 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";
13056 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";
13058 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";
13060 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
13062 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)";
13064 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
13066 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)";
13068 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";
13070 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}";
13072 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";
13074 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";
13076 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";
13078 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";
13080 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";
13082 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";
13084 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";
13086 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
13088 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
13090 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";
13092 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";
13094 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
13096 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
13098 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";
13100 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";
13102 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";
13104 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;";
13106 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";
13108 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";
13110 var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
13112 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";
13114 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";
13116 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}";
13118 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
13120 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;";
13122 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
13124 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";
13126 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
13128 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
13130 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";
13132 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";
13134 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";
13136 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}";
13138 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";
13140 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";
13142 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";
13144 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";
13146 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";
13148 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
13150 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
13152 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; }";
13154 var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif";
13156 var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif";
13158 var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
13160 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";
13162 var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
13164 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
13166 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";
13168 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
13170 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";
13172 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}";
13174 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}";
13176 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}";
13178 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}";
13180 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}";
13182 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}";
13184 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}";
13186 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}";
13188 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}";
13190 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}";
13192 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}";
13194 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}";
13196 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}";
13198 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}";
13200 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}";
13202 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}";
13204 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}";
13206 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}";
13208 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}";
13210 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}";
13212 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}";
13214 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}";
13216 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}";
13218 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}";
13220 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}";
13222 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}";
13224 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}";
13226 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}";
13228 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}";
13230 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}";
13232 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}";
13234 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}";
13236 const ShaderChunk = {
13237 alphamap_fragment: alphamap_fragment,
13238 alphamap_pars_fragment: alphamap_pars_fragment,
13239 alphatest_fragment: alphatest_fragment,
13240 aomap_fragment: aomap_fragment,
13241 aomap_pars_fragment: aomap_pars_fragment,
13242 begin_vertex: begin_vertex,
13243 beginnormal_vertex: beginnormal_vertex,
13245 bumpmap_pars_fragment: bumpmap_pars_fragment,
13246 clipping_planes_fragment: clipping_planes_fragment,
13247 clipping_planes_pars_fragment: clipping_planes_pars_fragment,
13248 clipping_planes_pars_vertex: clipping_planes_pars_vertex,
13249 clipping_planes_vertex: clipping_planes_vertex,
13250 color_fragment: color_fragment,
13251 color_pars_fragment: color_pars_fragment,
13252 color_pars_vertex: color_pars_vertex,
13253 color_vertex: color_vertex,
13255 cube_uv_reflection_fragment: cube_uv_reflection_fragment,
13256 defaultnormal_vertex: defaultnormal_vertex,
13257 displacementmap_pars_vertex: displacementmap_pars_vertex,
13258 displacementmap_vertex: displacementmap_vertex,
13259 emissivemap_fragment: emissivemap_fragment,
13260 emissivemap_pars_fragment: emissivemap_pars_fragment,
13261 encodings_fragment: encodings_fragment,
13262 encodings_pars_fragment: encodings_pars_fragment,
13263 envmap_fragment: envmap_fragment,
13264 envmap_common_pars_fragment: envmap_common_pars_fragment,
13265 envmap_pars_fragment: envmap_pars_fragment,
13266 envmap_pars_vertex: envmap_pars_vertex,
13267 envmap_physical_pars_fragment: envmap_physical_pars_fragment,
13268 envmap_vertex: envmap_vertex,
13269 fog_vertex: fog_vertex,
13270 fog_pars_vertex: fog_pars_vertex,
13271 fog_fragment: fog_fragment,
13272 fog_pars_fragment: fog_pars_fragment,
13273 gradientmap_pars_fragment: gradientmap_pars_fragment,
13274 lightmap_fragment: lightmap_fragment,
13275 lightmap_pars_fragment: lightmap_pars_fragment,
13276 lights_lambert_vertex: lights_lambert_vertex,
13277 lights_pars_begin: lights_pars_begin,
13278 lights_toon_fragment: lights_toon_fragment,
13279 lights_toon_pars_fragment: lights_toon_pars_fragment,
13280 lights_phong_fragment: lights_phong_fragment,
13281 lights_phong_pars_fragment: lights_phong_pars_fragment,
13282 lights_physical_fragment: lights_physical_fragment,
13283 lights_physical_pars_fragment: lights_physical_pars_fragment,
13284 lights_fragment_begin: lights_fragment_begin,
13285 lights_fragment_maps: lights_fragment_maps,
13286 lights_fragment_end: lights_fragment_end,
13287 logdepthbuf_fragment: logdepthbuf_fragment,
13288 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
13289 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
13290 logdepthbuf_vertex: logdepthbuf_vertex,
13291 map_fragment: map_fragment,
13292 map_pars_fragment: map_pars_fragment,
13293 map_particle_fragment: map_particle_fragment,
13294 map_particle_pars_fragment: map_particle_pars_fragment,
13295 metalnessmap_fragment: metalnessmap_fragment,
13296 metalnessmap_pars_fragment: metalnessmap_pars_fragment,
13297 morphnormal_vertex: morphnormal_vertex,
13298 morphtarget_pars_vertex: morphtarget_pars_vertex,
13299 morphtarget_vertex: morphtarget_vertex,
13300 normal_fragment_begin: normal_fragment_begin,
13301 normal_fragment_maps: normal_fragment_maps,
13302 normalmap_pars_fragment: normalmap_pars_fragment,
13303 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
13304 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
13305 clearcoat_pars_fragment: clearcoat_pars_fragment,
13307 premultiplied_alpha_fragment: premultiplied_alpha_fragment,
13308 project_vertex: project_vertex,
13309 dithering_fragment: dithering_fragment,
13310 dithering_pars_fragment: dithering_pars_fragment,
13311 roughnessmap_fragment: roughnessmap_fragment,
13312 roughnessmap_pars_fragment: roughnessmap_pars_fragment,
13313 shadowmap_pars_fragment: shadowmap_pars_fragment,
13314 shadowmap_pars_vertex: shadowmap_pars_vertex,
13315 shadowmap_vertex: shadowmap_vertex,
13316 shadowmask_pars_fragment: shadowmask_pars_fragment,
13317 skinbase_vertex: skinbase_vertex,
13318 skinning_pars_vertex: skinning_pars_vertex,
13319 skinning_vertex: skinning_vertex,
13320 skinnormal_vertex: skinnormal_vertex,
13321 specularmap_fragment: specularmap_fragment,
13322 specularmap_pars_fragment: specularmap_pars_fragment,
13323 tonemapping_fragment: tonemapping_fragment,
13324 tonemapping_pars_fragment: tonemapping_pars_fragment,
13325 transmissionmap_fragment: transmissionmap_fragment,
13326 transmissionmap_pars_fragment: transmissionmap_pars_fragment,
13327 uv_pars_fragment: uv_pars_fragment,
13328 uv_pars_vertex: uv_pars_vertex,
13329 uv_vertex: uv_vertex,
13330 uv2_pars_fragment: uv2_pars_fragment,
13331 uv2_pars_vertex: uv2_pars_vertex,
13332 uv2_vertex: uv2_vertex,
13333 worldpos_vertex: worldpos_vertex,
13335 background_frag: background_frag,
13336 background_vert: background_vert,
13337 cube_frag: cube_frag,
13338 cube_vert: cube_vert,
13339 depth_frag: depth_frag,
13340 depth_vert: depth_vert,
13341 distanceRGBA_frag: distanceRGBA_frag,
13342 distanceRGBA_vert: distanceRGBA_vert,
13343 equirect_frag: equirect_frag,
13344 equirect_vert: equirect_vert,
13345 linedashed_frag: linedashed_frag,
13346 linedashed_vert: linedashed_vert,
13347 meshbasic_frag: meshbasic_frag,
13348 meshbasic_vert: meshbasic_vert,
13349 meshlambert_frag: meshlambert_frag,
13350 meshlambert_vert: meshlambert_vert,
13351 meshmatcap_frag: meshmatcap_frag,
13352 meshmatcap_vert: meshmatcap_vert,
13353 meshtoon_frag: meshtoon_frag,
13354 meshtoon_vert: meshtoon_vert,
13355 meshphong_frag: meshphong_frag,
13356 meshphong_vert: meshphong_vert,
13357 meshphysical_frag: meshphysical_frag,
13358 meshphysical_vert: meshphysical_vert,
13359 normal_frag: normal_frag,
13360 normal_vert: normal_vert,
13361 points_frag: points_frag,
13362 points_vert: points_vert,
13363 shadow_frag: shadow_frag,
13364 shadow_vert: shadow_vert,
13365 sprite_frag: sprite_frag,
13366 sprite_vert: sprite_vert
13370 * Uniforms library for shared webgl shaders
13373 const UniformsLib = {
13377 diffuse: { value: new Color( 0xeeeeee ) },
13378 opacity: { value: 1.0 },
13380 map: { value: null },
13381 uvTransform: { value: new Matrix3() },
13382 uv2Transform: { value: new Matrix3() },
13384 alphaMap: { value: null },
13390 specularMap: { value: null },
13396 envMap: { value: null },
13397 flipEnvMap: { value: - 1 },
13398 reflectivity: { value: 1.0 },
13399 refractionRatio: { value: 0.98 },
13400 maxMipLevel: { value: 0 }
13406 aoMap: { value: null },
13407 aoMapIntensity: { value: 1 }
13413 lightMap: { value: null },
13414 lightMapIntensity: { value: 1 }
13420 emissiveMap: { value: null }
13426 bumpMap: { value: null },
13427 bumpScale: { value: 1 }
13433 normalMap: { value: null },
13434 normalScale: { value: new Vector2( 1, 1 ) }
13440 displacementMap: { value: null },
13441 displacementScale: { value: 1 },
13442 displacementBias: { value: 0 }
13448 roughnessMap: { value: null }
13454 metalnessMap: { value: null }
13460 gradientMap: { value: null }
13466 fogDensity: { value: 0.00025 },
13467 fogNear: { value: 1 },
13468 fogFar: { value: 2000 },
13469 fogColor: { value: new Color( 0xffffff ) }
13475 ambientLightColor: { value: [] },
13477 lightProbe: { value: [] },
13479 directionalLights: { value: [], properties: {
13484 directionalLightShadows: { value: [], properties: {
13486 shadowNormalBias: {},
13491 directionalShadowMap: { value: [] },
13492 directionalShadowMatrix: { value: [] },
13494 spotLights: { value: [], properties: {
13504 spotLightShadows: { value: [], properties: {
13506 shadowNormalBias: {},
13511 spotShadowMap: { value: [] },
13512 spotShadowMatrix: { value: [] },
13514 pointLights: { value: [], properties: {
13521 pointLightShadows: { value: [], properties: {
13523 shadowNormalBias: {},
13526 shadowCameraNear: {},
13527 shadowCameraFar: {}
13530 pointShadowMap: { value: [] },
13531 pointShadowMatrix: { value: [] },
13533 hemisphereLights: { value: [], properties: {
13539 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
13540 rectAreaLights: { value: [], properties: {
13547 ltc_1: { value: null },
13548 ltc_2: { value: null }
13554 diffuse: { value: new Color( 0xeeeeee ) },
13555 opacity: { value: 1.0 },
13556 size: { value: 1.0 },
13557 scale: { value: 1.0 },
13558 map: { value: null },
13559 alphaMap: { value: null },
13560 uvTransform: { value: new Matrix3() }
13566 diffuse: { value: new Color( 0xeeeeee ) },
13567 opacity: { value: 1.0 },
13568 center: { value: new Vector2( 0.5, 0.5 ) },
13569 rotation: { value: 0.0 },
13570 map: { value: null },
13571 alphaMap: { value: null },
13572 uvTransform: { value: new Matrix3() }
13578 const ShaderLib = {
13582 uniforms: mergeUniforms( [
13583 UniformsLib.common,
13584 UniformsLib.specularmap,
13585 UniformsLib.envmap,
13587 UniformsLib.lightmap,
13591 vertexShader: ShaderChunk.meshbasic_vert,
13592 fragmentShader: ShaderChunk.meshbasic_frag
13598 uniforms: mergeUniforms( [
13599 UniformsLib.common,
13600 UniformsLib.specularmap,
13601 UniformsLib.envmap,
13603 UniformsLib.lightmap,
13604 UniformsLib.emissivemap,
13606 UniformsLib.lights,
13608 emissive: { value: new Color( 0x000000 ) }
13612 vertexShader: ShaderChunk.meshlambert_vert,
13613 fragmentShader: ShaderChunk.meshlambert_frag
13619 uniforms: mergeUniforms( [
13620 UniformsLib.common,
13621 UniformsLib.specularmap,
13622 UniformsLib.envmap,
13624 UniformsLib.lightmap,
13625 UniformsLib.emissivemap,
13626 UniformsLib.bumpmap,
13627 UniformsLib.normalmap,
13628 UniformsLib.displacementmap,
13630 UniformsLib.lights,
13632 emissive: { value: new Color( 0x000000 ) },
13633 specular: { value: new Color( 0x111111 ) },
13634 shininess: { value: 30 }
13638 vertexShader: ShaderChunk.meshphong_vert,
13639 fragmentShader: ShaderChunk.meshphong_frag
13645 uniforms: mergeUniforms( [
13646 UniformsLib.common,
13647 UniformsLib.envmap,
13649 UniformsLib.lightmap,
13650 UniformsLib.emissivemap,
13651 UniformsLib.bumpmap,
13652 UniformsLib.normalmap,
13653 UniformsLib.displacementmap,
13654 UniformsLib.roughnessmap,
13655 UniformsLib.metalnessmap,
13657 UniformsLib.lights,
13659 emissive: { value: new Color( 0x000000 ) },
13660 roughness: { value: 1.0 },
13661 metalness: { value: 0.0 },
13662 envMapIntensity: { value: 1 } // temporary
13666 vertexShader: ShaderChunk.meshphysical_vert,
13667 fragmentShader: ShaderChunk.meshphysical_frag
13673 uniforms: mergeUniforms( [
13674 UniformsLib.common,
13676 UniformsLib.lightmap,
13677 UniformsLib.emissivemap,
13678 UniformsLib.bumpmap,
13679 UniformsLib.normalmap,
13680 UniformsLib.displacementmap,
13681 UniformsLib.gradientmap,
13683 UniformsLib.lights,
13685 emissive: { value: new Color( 0x000000 ) }
13689 vertexShader: ShaderChunk.meshtoon_vert,
13690 fragmentShader: ShaderChunk.meshtoon_frag
13696 uniforms: mergeUniforms( [
13697 UniformsLib.common,
13698 UniformsLib.bumpmap,
13699 UniformsLib.normalmap,
13700 UniformsLib.displacementmap,
13703 matcap: { value: null }
13707 vertexShader: ShaderChunk.meshmatcap_vert,
13708 fragmentShader: ShaderChunk.meshmatcap_frag
13714 uniforms: mergeUniforms( [
13715 UniformsLib.points,
13719 vertexShader: ShaderChunk.points_vert,
13720 fragmentShader: ShaderChunk.points_frag
13726 uniforms: mergeUniforms( [
13727 UniformsLib.common,
13730 scale: { value: 1 },
13731 dashSize: { value: 1 },
13732 totalSize: { value: 2 }
13736 vertexShader: ShaderChunk.linedashed_vert,
13737 fragmentShader: ShaderChunk.linedashed_frag
13743 uniforms: mergeUniforms( [
13744 UniformsLib.common,
13745 UniformsLib.displacementmap
13748 vertexShader: ShaderChunk.depth_vert,
13749 fragmentShader: ShaderChunk.depth_frag
13755 uniforms: mergeUniforms( [
13756 UniformsLib.common,
13757 UniformsLib.bumpmap,
13758 UniformsLib.normalmap,
13759 UniformsLib.displacementmap,
13761 opacity: { value: 1.0 }
13765 vertexShader: ShaderChunk.normal_vert,
13766 fragmentShader: ShaderChunk.normal_frag
13772 uniforms: mergeUniforms( [
13773 UniformsLib.sprite,
13777 vertexShader: ShaderChunk.sprite_vert,
13778 fragmentShader: ShaderChunk.sprite_frag
13785 uvTransform: { value: new Matrix3() },
13786 t2D: { value: null },
13789 vertexShader: ShaderChunk.background_vert,
13790 fragmentShader: ShaderChunk.background_frag
13793 /* -------------------------------------------------------------------------
13795 ------------------------------------------------------------------------- */
13799 uniforms: mergeUniforms( [
13800 UniformsLib.envmap,
13802 opacity: { value: 1.0 }
13806 vertexShader: ShaderChunk.cube_vert,
13807 fragmentShader: ShaderChunk.cube_frag
13814 tEquirect: { value: null },
13817 vertexShader: ShaderChunk.equirect_vert,
13818 fragmentShader: ShaderChunk.equirect_frag
13824 uniforms: mergeUniforms( [
13825 UniformsLib.common,
13826 UniformsLib.displacementmap,
13828 referencePosition: { value: new Vector3() },
13829 nearDistance: { value: 1 },
13830 farDistance: { value: 1000 }
13834 vertexShader: ShaderChunk.distanceRGBA_vert,
13835 fragmentShader: ShaderChunk.distanceRGBA_frag
13841 uniforms: mergeUniforms( [
13842 UniformsLib.lights,
13845 color: { value: new Color( 0x00000 ) },
13846 opacity: { value: 1.0 }
13850 vertexShader: ShaderChunk.shadow_vert,
13851 fragmentShader: ShaderChunk.shadow_frag
13857 ShaderLib.physical = {
13859 uniforms: mergeUniforms( [
13860 ShaderLib.standard.uniforms,
13862 clearcoat: { value: 0 },
13863 clearcoatMap: { value: null },
13864 clearcoatRoughness: { value: 0 },
13865 clearcoatRoughnessMap: { value: null },
13866 clearcoatNormalScale: { value: new Vector2( 1, 1 ) },
13867 clearcoatNormalMap: { value: null },
13868 sheen: { value: new Color( 0x000000 ) },
13869 transmission: { value: 0 },
13870 transmissionMap: { value: null },
13874 vertexShader: ShaderChunk.meshphysical_vert,
13875 fragmentShader: ShaderChunk.meshphysical_frag
13879 function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
13881 const clearColor = new Color( 0x000000 );
13882 let clearAlpha = 0;
13887 let currentBackground = null;
13888 let currentBackgroundVersion = 0;
13889 let currentTonemapping = null;
13891 function render( renderList, scene, camera, forceClear ) {
13893 let background = scene.isScene === true ? scene.background : null;
13895 if ( background && background.isTexture ) {
13897 background = cubemaps.get( background );
13901 // Ignore background in AR
13902 // TODO: Reconsider this.
13904 const xr = renderer.xr;
13905 const session = xr.getSession && xr.getSession();
13907 if ( session && session.environmentBlendMode === 'additive' ) {
13913 if ( background === null ) {
13915 setClear( clearColor, clearAlpha );
13917 } else if ( background && background.isColor ) {
13919 setClear( background, 1 );
13924 if ( renderer.autoClear || forceClear ) {
13926 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
13930 if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) {
13932 if ( boxMesh === undefined ) {
13934 boxMesh = new Mesh(
13935 new BoxBufferGeometry( 1, 1, 1 ),
13936 new ShaderMaterial( {
13937 name: 'BackgroundCubeMaterial',
13938 uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
13939 vertexShader: ShaderLib.cube.vertexShader,
13940 fragmentShader: ShaderLib.cube.fragmentShader,
13948 boxMesh.geometry.deleteAttribute( 'normal' );
13949 boxMesh.geometry.deleteAttribute( 'uv' );
13951 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
13953 this.matrixWorld.copyPosition( camera.matrixWorld );
13957 // enable code injection for non-built-in material
13958 Object.defineProperty( boxMesh.material, 'envMap', {
13962 return this.uniforms.envMap.value;
13968 objects.update( boxMesh );
13972 if ( background.isWebGLCubeRenderTarget ) {
13976 background = background.texture;
13980 boxMesh.material.uniforms.envMap.value = background;
13981 boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background._needsFlipEnvMap ) ? - 1 : 1;
13983 if ( currentBackground !== background ||
13984 currentBackgroundVersion !== background.version ||
13985 currentTonemapping !== renderer.toneMapping ) {
13987 boxMesh.material.needsUpdate = true;
13989 currentBackground = background;
13990 currentBackgroundVersion = background.version;
13991 currentTonemapping = renderer.toneMapping;
13995 // push to the pre-sorted opaque render list
13996 renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
13998 } else if ( background && background.isTexture ) {
14000 if ( planeMesh === undefined ) {
14002 planeMesh = new Mesh(
14003 new PlaneBufferGeometry( 2, 2 ),
14004 new ShaderMaterial( {
14005 name: 'BackgroundMaterial',
14006 uniforms: cloneUniforms( ShaderLib.background.uniforms ),
14007 vertexShader: ShaderLib.background.vertexShader,
14008 fragmentShader: ShaderLib.background.fragmentShader,
14016 planeMesh.geometry.deleteAttribute( 'normal' );
14018 // enable code injection for non-built-in material
14019 Object.defineProperty( planeMesh.material, 'map', {
14023 return this.uniforms.t2D.value;
14029 objects.update( planeMesh );
14033 planeMesh.material.uniforms.t2D.value = background;
14035 if ( background.matrixAutoUpdate === true ) {
14037 background.updateMatrix();
14041 planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
14043 if ( currentBackground !== background ||
14044 currentBackgroundVersion !== background.version ||
14045 currentTonemapping !== renderer.toneMapping ) {
14047 planeMesh.material.needsUpdate = true;
14049 currentBackground = background;
14050 currentBackgroundVersion = background.version;
14051 currentTonemapping = renderer.toneMapping;
14056 // push to the pre-sorted opaque render list
14057 renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
14063 function setClear( color, alpha ) {
14065 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
14071 getClearColor: function () {
14076 setClearColor: function ( color, alpha = 1 ) {
14078 clearColor.set( color );
14079 clearAlpha = alpha;
14080 setClear( clearColor, clearAlpha );
14083 getClearAlpha: function () {
14088 setClearAlpha: function ( alpha ) {
14090 clearAlpha = alpha;
14091 setClear( clearColor, clearAlpha );
14100 function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
14102 const maxVertexAttributes = gl.getParameter( 34921 );
14104 const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
14105 const vaoAvailable = capabilities.isWebGL2 || extension !== null;
14107 const bindingStates = {};
14109 const defaultState = createBindingState( null );
14110 let currentState = defaultState;
14112 function setup( object, material, program, geometry, index ) {
14114 let updateBuffers = false;
14116 if ( vaoAvailable ) {
14118 const state = getBindingState( geometry, program, material );
14120 if ( currentState !== state ) {
14122 currentState = state;
14123 bindVertexArrayObject( currentState.object );
14127 updateBuffers = needsUpdate( geometry, index );
14129 if ( updateBuffers ) saveCache( geometry, index );
14133 const wireframe = ( material.wireframe === true );
14135 if ( currentState.geometry !== geometry.id ||
14136 currentState.program !== program.id ||
14137 currentState.wireframe !== wireframe ) {
14139 currentState.geometry = geometry.id;
14140 currentState.program = program.id;
14141 currentState.wireframe = wireframe;
14143 updateBuffers = true;
14149 if ( object.isInstancedMesh === true ) {
14151 updateBuffers = true;
14155 if ( index !== null ) {
14157 attributes.update( index, 34963 );
14161 if ( updateBuffers ) {
14163 setupVertexAttributes( object, material, program, geometry );
14165 if ( index !== null ) {
14167 gl.bindBuffer( 34963, attributes.get( index ).buffer );
14175 function createVertexArrayObject() {
14177 if ( capabilities.isWebGL2 ) return gl.createVertexArray();
14179 return extension.createVertexArrayOES();
14183 function bindVertexArrayObject( vao ) {
14185 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
14187 return extension.bindVertexArrayOES( vao );
14191 function deleteVertexArrayObject( vao ) {
14193 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
14195 return extension.deleteVertexArrayOES( vao );
14199 function getBindingState( geometry, program, material ) {
14201 const wireframe = ( material.wireframe === true );
14203 let programMap = bindingStates[ geometry.id ];
14205 if ( programMap === undefined ) {
14208 bindingStates[ geometry.id ] = programMap;
14212 let stateMap = programMap[ program.id ];
14214 if ( stateMap === undefined ) {
14217 programMap[ program.id ] = stateMap;
14221 let state = stateMap[ wireframe ];
14223 if ( state === undefined ) {
14225 state = createBindingState( createVertexArrayObject() );
14226 stateMap[ wireframe ] = state;
14234 function createBindingState( vao ) {
14236 const newAttributes = [];
14237 const enabledAttributes = [];
14238 const attributeDivisors = [];
14240 for ( let i = 0; i < maxVertexAttributes; i ++ ) {
14242 newAttributes[ i ] = 0;
14243 enabledAttributes[ i ] = 0;
14244 attributeDivisors[ i ] = 0;
14250 // for backward compatibility on non-VAO support browser
14255 newAttributes: newAttributes,
14256 enabledAttributes: enabledAttributes,
14257 attributeDivisors: attributeDivisors,
14266 function needsUpdate( geometry, index ) {
14268 const cachedAttributes = currentState.attributes;
14269 const geometryAttributes = geometry.attributes;
14271 let attributesNum = 0;
14273 for ( const key in geometryAttributes ) {
14275 const cachedAttribute = cachedAttributes[ key ];
14276 const geometryAttribute = geometryAttributes[ key ];
14278 if ( cachedAttribute === undefined ) return true;
14280 if ( cachedAttribute.attribute !== geometryAttribute ) return true;
14282 if ( cachedAttribute.data !== geometryAttribute.data ) return true;
14288 if ( currentState.attributesNum !== attributesNum ) return true;
14290 if ( currentState.index !== index ) return true;
14296 function saveCache( geometry, index ) {
14299 const attributes = geometry.attributes;
14300 let attributesNum = 0;
14302 for ( const key in attributes ) {
14304 const attribute = attributes[ key ];
14307 data.attribute = attribute;
14309 if ( attribute.data ) {
14311 data.data = attribute.data;
14315 cache[ key ] = data;
14321 currentState.attributes = cache;
14322 currentState.attributesNum = attributesNum;
14324 currentState.index = index;
14328 function initAttributes() {
14330 const newAttributes = currentState.newAttributes;
14332 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
14334 newAttributes[ i ] = 0;
14340 function enableAttribute( attribute ) {
14342 enableAttributeAndDivisor( attribute, 0 );
14346 function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
14348 const newAttributes = currentState.newAttributes;
14349 const enabledAttributes = currentState.enabledAttributes;
14350 const attributeDivisors = currentState.attributeDivisors;
14352 newAttributes[ attribute ] = 1;
14354 if ( enabledAttributes[ attribute ] === 0 ) {
14356 gl.enableVertexAttribArray( attribute );
14357 enabledAttributes[ attribute ] = 1;
14361 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
14363 const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
14365 extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
14366 attributeDivisors[ attribute ] = meshPerAttribute;
14372 function disableUnusedAttributes() {
14374 const newAttributes = currentState.newAttributes;
14375 const enabledAttributes = currentState.enabledAttributes;
14377 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
14379 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
14381 gl.disableVertexAttribArray( i );
14382 enabledAttributes[ i ] = 0;
14390 function vertexAttribPointer( index, size, type, normalized, stride, offset ) {
14392 if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) {
14394 gl.vertexAttribIPointer( index, size, type, stride, offset );
14398 gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
14404 function setupVertexAttributes( object, material, program, geometry ) {
14406 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
14408 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
14414 const geometryAttributes = geometry.attributes;
14416 const programAttributes = program.getAttributes();
14418 const materialDefaultAttributeValues = material.defaultAttributeValues;
14420 for ( const name in programAttributes ) {
14422 const programAttribute = programAttributes[ name ];
14424 if ( programAttribute >= 0 ) {
14426 const geometryAttribute = geometryAttributes[ name ];
14428 if ( geometryAttribute !== undefined ) {
14430 const normalized = geometryAttribute.normalized;
14431 const size = geometryAttribute.itemSize;
14433 const attribute = attributes.get( geometryAttribute );
14435 // TODO Attribute may not be available on context restore
14437 if ( attribute === undefined ) continue;
14439 const buffer = attribute.buffer;
14440 const type = attribute.type;
14441 const bytesPerElement = attribute.bytesPerElement;
14443 if ( geometryAttribute.isInterleavedBufferAttribute ) {
14445 const data = geometryAttribute.data;
14446 const stride = data.stride;
14447 const offset = geometryAttribute.offset;
14449 if ( data && data.isInstancedInterleavedBuffer ) {
14451 enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
14453 if ( geometry._maxInstanceCount === undefined ) {
14455 geometry._maxInstanceCount = data.meshPerAttribute * data.count;
14461 enableAttribute( programAttribute );
14465 gl.bindBuffer( 34962, buffer );
14466 vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement );
14470 if ( geometryAttribute.isInstancedBufferAttribute ) {
14472 enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
14474 if ( geometry._maxInstanceCount === undefined ) {
14476 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
14482 enableAttribute( programAttribute );
14486 gl.bindBuffer( 34962, buffer );
14487 vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 );
14491 } else if ( name === 'instanceMatrix' ) {
14493 const attribute = attributes.get( object.instanceMatrix );
14495 // TODO Attribute may not be available on context restore
14497 if ( attribute === undefined ) continue;
14499 const buffer = attribute.buffer;
14500 const type = attribute.type;
14502 enableAttributeAndDivisor( programAttribute + 0, 1 );
14503 enableAttributeAndDivisor( programAttribute + 1, 1 );
14504 enableAttributeAndDivisor( programAttribute + 2, 1 );
14505 enableAttributeAndDivisor( programAttribute + 3, 1 );
14507 gl.bindBuffer( 34962, buffer );
14509 gl.vertexAttribPointer( programAttribute + 0, 4, type, false, 64, 0 );
14510 gl.vertexAttribPointer( programAttribute + 1, 4, type, false, 64, 16 );
14511 gl.vertexAttribPointer( programAttribute + 2, 4, type, false, 64, 32 );
14512 gl.vertexAttribPointer( programAttribute + 3, 4, type, false, 64, 48 );
14514 } else if ( name === 'instanceColor' ) {
14516 const attribute = attributes.get( object.instanceColor );
14518 // TODO Attribute may not be available on context restore
14520 if ( attribute === undefined ) continue;
14522 const buffer = attribute.buffer;
14523 const type = attribute.type;
14525 enableAttributeAndDivisor( programAttribute, 1 );
14527 gl.bindBuffer( 34962, buffer );
14529 gl.vertexAttribPointer( programAttribute, 3, type, false, 12, 0 );
14531 } else if ( materialDefaultAttributeValues !== undefined ) {
14533 const value = materialDefaultAttributeValues[ name ];
14535 if ( value !== undefined ) {
14537 switch ( value.length ) {
14540 gl.vertexAttrib2fv( programAttribute, value );
14544 gl.vertexAttrib3fv( programAttribute, value );
14548 gl.vertexAttrib4fv( programAttribute, value );
14552 gl.vertexAttrib1fv( programAttribute, value );
14564 disableUnusedAttributes();
14568 function dispose() {
14572 for ( const geometryId in bindingStates ) {
14574 const programMap = bindingStates[ geometryId ];
14576 for ( const programId in programMap ) {
14578 const stateMap = programMap[ programId ];
14580 for ( const wireframe in stateMap ) {
14582 deleteVertexArrayObject( stateMap[ wireframe ].object );
14584 delete stateMap[ wireframe ];
14588 delete programMap[ programId ];
14592 delete bindingStates[ geometryId ];
14598 function releaseStatesOfGeometry( geometry ) {
14600 if ( bindingStates[ geometry.id ] === undefined ) return;
14602 const programMap = bindingStates[ geometry.id ];
14604 for ( const programId in programMap ) {
14606 const stateMap = programMap[ programId ];
14608 for ( const wireframe in stateMap ) {
14610 deleteVertexArrayObject( stateMap[ wireframe ].object );
14612 delete stateMap[ wireframe ];
14616 delete programMap[ programId ];
14620 delete bindingStates[ geometry.id ];
14624 function releaseStatesOfProgram( program ) {
14626 for ( const geometryId in bindingStates ) {
14628 const programMap = bindingStates[ geometryId ];
14630 if ( programMap[ program.id ] === undefined ) continue;
14632 const stateMap = programMap[ program.id ];
14634 for ( const wireframe in stateMap ) {
14636 deleteVertexArrayObject( stateMap[ wireframe ].object );
14638 delete stateMap[ wireframe ];
14642 delete programMap[ program.id ];
14650 resetDefaultState();
14652 if ( currentState === defaultState ) return;
14654 currentState = defaultState;
14655 bindVertexArrayObject( currentState.object );
14659 // for backward-compatilibity
14661 function resetDefaultState() {
14663 defaultState.geometry = null;
14664 defaultState.program = null;
14665 defaultState.wireframe = false;
14673 resetDefaultState: resetDefaultState,
14675 releaseStatesOfGeometry: releaseStatesOfGeometry,
14676 releaseStatesOfProgram: releaseStatesOfProgram,
14678 initAttributes: initAttributes,
14679 enableAttribute: enableAttribute,
14680 disableUnusedAttributes: disableUnusedAttributes
14686 function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
14688 const isWebGL2 = capabilities.isWebGL2;
14692 function setMode( value ) {
14698 function render( start, count ) {
14700 gl.drawArrays( mode, start, count );
14702 info.update( count, mode, 1 );
14706 function renderInstances( start, count, primcount ) {
14708 if ( primcount === 0 ) return;
14710 let extension, methodName;
14715 methodName = 'drawArraysInstanced';
14719 extension = extensions.get( 'ANGLE_instanced_arrays' );
14720 methodName = 'drawArraysInstancedANGLE';
14722 if ( extension === null ) {
14724 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
14731 extension[ methodName ]( mode, start, count, primcount );
14733 info.update( count, mode, primcount );
14739 this.setMode = setMode;
14740 this.render = render;
14741 this.renderInstances = renderInstances;
14745 function WebGLCapabilities( gl, extensions, parameters ) {
14749 function getMaxAnisotropy() {
14751 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
14753 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
14755 if ( extension !== null ) {
14757 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
14765 return maxAnisotropy;
14769 function getMaxPrecision( precision ) {
14771 if ( precision === 'highp' ) {
14773 if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 &&
14774 gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) {
14780 precision = 'mediump';
14784 if ( precision === 'mediump' ) {
14786 if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 &&
14787 gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) {
14799 /* eslint-disable no-undef */
14800 const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) ||
14801 ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext );
14802 /* eslint-enable no-undef */
14804 let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
14805 const maxPrecision = getMaxPrecision( precision );
14807 if ( maxPrecision !== precision ) {
14809 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
14810 precision = maxPrecision;
14814 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
14816 const maxTextures = gl.getParameter( 34930 );
14817 const maxVertexTextures = gl.getParameter( 35660 );
14818 const maxTextureSize = gl.getParameter( 3379 );
14819 const maxCubemapSize = gl.getParameter( 34076 );
14821 const maxAttributes = gl.getParameter( 34921 );
14822 const maxVertexUniforms = gl.getParameter( 36347 );
14823 const maxVaryings = gl.getParameter( 36348 );
14824 const maxFragmentUniforms = gl.getParameter( 36349 );
14826 const vertexTextures = maxVertexTextures > 0;
14827 const floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
14828 const floatVertexTextures = vertexTextures && floatFragmentTextures;
14830 const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
14834 isWebGL2: isWebGL2,
14836 getMaxAnisotropy: getMaxAnisotropy,
14837 getMaxPrecision: getMaxPrecision,
14839 precision: precision,
14840 logarithmicDepthBuffer: logarithmicDepthBuffer,
14842 maxTextures: maxTextures,
14843 maxVertexTextures: maxVertexTextures,
14844 maxTextureSize: maxTextureSize,
14845 maxCubemapSize: maxCubemapSize,
14847 maxAttributes: maxAttributes,
14848 maxVertexUniforms: maxVertexUniforms,
14849 maxVaryings: maxVaryings,
14850 maxFragmentUniforms: maxFragmentUniforms,
14852 vertexTextures: vertexTextures,
14853 floatFragmentTextures: floatFragmentTextures,
14854 floatVertexTextures: floatVertexTextures,
14856 maxSamples: maxSamples
14862 function WebGLClipping( properties ) {
14864 const scope = this;
14866 let globalState = null,
14867 numGlobalPlanes = 0,
14868 localClippingEnabled = false,
14869 renderingShadows = false;
14871 const plane = new Plane(),
14872 viewNormalMatrix = new Matrix3(),
14874 uniform = { value: null, needsUpdate: false };
14876 this.uniform = uniform;
14877 this.numPlanes = 0;
14878 this.numIntersection = 0;
14880 this.init = function ( planes, enableLocalClipping, camera ) {
14883 planes.length !== 0 ||
14884 enableLocalClipping ||
14885 // enable state of previous frame - the clipping code has to
14886 // run another frame in order to reset the state:
14887 numGlobalPlanes !== 0 ||
14888 localClippingEnabled;
14890 localClippingEnabled = enableLocalClipping;
14892 globalState = projectPlanes( planes, camera, 0 );
14893 numGlobalPlanes = planes.length;
14899 this.beginShadows = function () {
14901 renderingShadows = true;
14902 projectPlanes( null );
14906 this.endShadows = function () {
14908 renderingShadows = false;
14909 resetGlobalState();
14913 this.setState = function ( material, camera, useCache ) {
14915 const planes = material.clippingPlanes,
14916 clipIntersection = material.clipIntersection,
14917 clipShadows = material.clipShadows;
14919 const materialProperties = properties.get( material );
14921 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
14923 // there's no local clipping
14925 if ( renderingShadows ) {
14927 // there's no global clipping
14929 projectPlanes( null );
14933 resetGlobalState();
14939 const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
14940 lGlobal = nGlobal * 4;
14942 let dstArray = materialProperties.clippingState || null;
14944 uniform.value = dstArray; // ensure unique state
14946 dstArray = projectPlanes( planes, camera, lGlobal, useCache );
14948 for ( let i = 0; i !== lGlobal; ++ i ) {
14950 dstArray[ i ] = globalState[ i ];
14954 materialProperties.clippingState = dstArray;
14955 this.numIntersection = clipIntersection ? this.numPlanes : 0;
14956 this.numPlanes += nGlobal;
14963 function resetGlobalState() {
14965 if ( uniform.value !== globalState ) {
14967 uniform.value = globalState;
14968 uniform.needsUpdate = numGlobalPlanes > 0;
14972 scope.numPlanes = numGlobalPlanes;
14973 scope.numIntersection = 0;
14977 function projectPlanes( planes, camera, dstOffset, skipTransform ) {
14979 const nPlanes = planes !== null ? planes.length : 0;
14980 let dstArray = null;
14982 if ( nPlanes !== 0 ) {
14984 dstArray = uniform.value;
14986 if ( skipTransform !== true || dstArray === null ) {
14988 const flatSize = dstOffset + nPlanes * 4,
14989 viewMatrix = camera.matrixWorldInverse;
14991 viewNormalMatrix.getNormalMatrix( viewMatrix );
14993 if ( dstArray === null || dstArray.length < flatSize ) {
14995 dstArray = new Float32Array( flatSize );
14999 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
15001 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
15003 plane.normal.toArray( dstArray, i4 );
15004 dstArray[ i4 + 3 ] = plane.constant;
15010 uniform.value = dstArray;
15011 uniform.needsUpdate = true;
15015 scope.numPlanes = nPlanes;
15016 scope.numIntersection = 0;
15024 function WebGLCubeMaps( renderer ) {
15026 let cubemaps = new WeakMap();
15028 function mapTextureMapping( texture, mapping ) {
15030 if ( mapping === EquirectangularReflectionMapping ) {
15032 texture.mapping = CubeReflectionMapping;
15034 } else if ( mapping === EquirectangularRefractionMapping ) {
15036 texture.mapping = CubeRefractionMapping;
15044 function get( texture ) {
15046 if ( texture && texture.isTexture ) {
15048 const mapping = texture.mapping;
15050 if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
15052 if ( cubemaps.has( texture ) ) {
15054 const cubemap = cubemaps.get( texture ).texture;
15055 return mapTextureMapping( cubemap, texture.mapping );
15059 const image = texture.image;
15061 if ( image && image.height > 0 ) {
15063 const currentRenderList = renderer.getRenderList();
15064 const currentRenderTarget = renderer.getRenderTarget();
15065 const currentRenderState = renderer.getRenderState();
15067 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
15068 renderTarget.fromEquirectangularTexture( renderer, texture );
15069 cubemaps.set( texture, renderTarget );
15071 renderer.setRenderTarget( currentRenderTarget );
15072 renderer.setRenderList( currentRenderList );
15073 renderer.setRenderState( currentRenderState );
15075 texture.addEventListener( 'dispose', onTextureDispose );
15077 return mapTextureMapping( renderTarget.texture, texture.mapping );
15081 // image not yet ready. try the conversion next frame
15097 function onTextureDispose( event ) {
15099 const texture = event.target;
15101 texture.removeEventListener( 'dispose', onTextureDispose );
15103 const cubemap = cubemaps.get( texture );
15105 if ( cubemap !== undefined ) {
15107 cubemaps.delete( texture );
15114 function dispose() {
15116 cubemaps = new WeakMap();
15127 function WebGLExtensions( gl ) {
15129 const extensions = {};
15133 has: function ( name ) {
15135 if ( extensions[ name ] !== undefined ) {
15137 return extensions[ name ] !== null;
15145 case 'WEBGL_depth_texture':
15146 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
15149 case 'EXT_texture_filter_anisotropic':
15150 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
15153 case 'WEBGL_compressed_texture_s3tc':
15154 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
15157 case 'WEBGL_compressed_texture_pvrtc':
15158 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
15162 extension = gl.getExtension( name );
15166 extensions[ name ] = extension;
15168 return extension !== null;
15172 get: function ( name ) {
15174 if ( ! this.has( name ) ) {
15176 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
15180 return extensions[ name ];
15188 function WebGLGeometries( gl, attributes, info, bindingStates ) {
15190 const geometries = new WeakMap();
15191 const wireframeAttributes = new WeakMap();
15193 function onGeometryDispose( event ) {
15195 const geometry = event.target;
15196 const buffergeometry = geometries.get( geometry );
15198 if ( buffergeometry.index !== null ) {
15200 attributes.remove( buffergeometry.index );
15204 for ( const name in buffergeometry.attributes ) {
15206 attributes.remove( buffergeometry.attributes[ name ] );
15210 geometry.removeEventListener( 'dispose', onGeometryDispose );
15212 geometries.delete( geometry );
15214 const attribute = wireframeAttributes.get( buffergeometry );
15218 attributes.remove( attribute );
15219 wireframeAttributes.delete( buffergeometry );
15223 bindingStates.releaseStatesOfGeometry( buffergeometry );
15225 if ( geometry.isInstancedBufferGeometry === true ) {
15227 delete geometry._maxInstanceCount;
15233 info.memory.geometries --;
15237 function get( object, geometry ) {
15239 let buffergeometry = geometries.get( geometry );
15241 if ( buffergeometry ) return buffergeometry;
15243 geometry.addEventListener( 'dispose', onGeometryDispose );
15245 if ( geometry.isBufferGeometry ) {
15247 buffergeometry = geometry;
15249 } else if ( geometry.isGeometry ) {
15251 if ( geometry._bufferGeometry === undefined ) {
15253 geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
15257 buffergeometry = geometry._bufferGeometry;
15261 geometries.set( geometry, buffergeometry );
15263 info.memory.geometries ++;
15265 return buffergeometry;
15269 function update( geometry ) {
15271 const geometryAttributes = geometry.attributes;
15273 // Updating index buffer in VAO now. See WebGLBindingStates.
15275 for ( const name in geometryAttributes ) {
15277 attributes.update( geometryAttributes[ name ], 34962 );
15283 const morphAttributes = geometry.morphAttributes;
15285 for ( const name in morphAttributes ) {
15287 const array = morphAttributes[ name ];
15289 for ( let i = 0, l = array.length; i < l; i ++ ) {
15291 attributes.update( array[ i ], 34962 );
15299 function updateWireframeAttribute( geometry ) {
15301 const indices = [];
15303 const geometryIndex = geometry.index;
15304 const geometryPosition = geometry.attributes.position;
15307 if ( geometryIndex !== null ) {
15309 const array = geometryIndex.array;
15310 version = geometryIndex.version;
15312 for ( let i = 0, l = array.length; i < l; i += 3 ) {
15314 const a = array[ i + 0 ];
15315 const b = array[ i + 1 ];
15316 const c = array[ i + 2 ];
15318 indices.push( a, b, b, c, c, a );
15324 const array = geometryPosition.array;
15325 version = geometryPosition.version;
15327 for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
15333 indices.push( a, b, b, c, c, a );
15339 const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
15340 attribute.version = version;
15342 // Updating index buffer in VAO now. See WebGLBindingStates
15346 const previousAttribute = wireframeAttributes.get( geometry );
15348 if ( previousAttribute ) attributes.remove( previousAttribute );
15352 wireframeAttributes.set( geometry, attribute );
15356 function getWireframeAttribute( geometry ) {
15358 const currentAttribute = wireframeAttributes.get( geometry );
15360 if ( currentAttribute ) {
15362 const geometryIndex = geometry.index;
15364 if ( geometryIndex !== null ) {
15366 // if the attribute is obsolete, create a new one
15368 if ( currentAttribute.version < geometryIndex.version ) {
15370 updateWireframeAttribute( geometry );
15378 updateWireframeAttribute( geometry );
15382 return wireframeAttributes.get( geometry );
15391 getWireframeAttribute: getWireframeAttribute
15397 function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
15399 const isWebGL2 = capabilities.isWebGL2;
15403 function setMode( value ) {
15409 let type, bytesPerElement;
15411 function setIndex( value ) {
15414 bytesPerElement = value.bytesPerElement;
15418 function render( start, count ) {
15420 gl.drawElements( mode, count, type, start * bytesPerElement );
15422 info.update( count, mode, 1 );
15426 function renderInstances( start, count, primcount ) {
15428 if ( primcount === 0 ) return;
15430 let extension, methodName;
15435 methodName = 'drawElementsInstanced';
15439 extension = extensions.get( 'ANGLE_instanced_arrays' );
15440 methodName = 'drawElementsInstancedANGLE';
15442 if ( extension === null ) {
15444 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
15451 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
15453 info.update( count, mode, primcount );
15459 this.setMode = setMode;
15460 this.setIndex = setIndex;
15461 this.render = render;
15462 this.renderInstances = renderInstances;
15466 function WebGLInfo( gl ) {
15481 function update( count, mode, instanceCount ) {
15488 render.triangles += instanceCount * ( count / 3 );
15492 render.lines += instanceCount * ( count / 2 );
15496 render.lines += instanceCount * ( count - 1 );
15500 render.lines += instanceCount * count;
15504 render.points += instanceCount * count;
15508 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
15519 render.triangles = 0;
15536 function numericalSort( a, b ) {
15538 return a[ 0 ] - b[ 0 ];
15542 function absNumericalSort( a, b ) {
15544 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
15548 function WebGLMorphtargets( gl ) {
15550 const influencesList = {};
15551 const morphInfluences = new Float32Array( 8 );
15553 const workInfluences = [];
15555 for ( let i = 0; i < 8; i ++ ) {
15557 workInfluences[ i ] = [ i, 0 ];
15561 function update( object, geometry, material, program ) {
15563 const objectInfluences = object.morphTargetInfluences;
15565 // When object doesn't have morph target influences defined, we treat it as a 0-length array
15566 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
15568 const length = objectInfluences === undefined ? 0 : objectInfluences.length;
15570 let influences = influencesList[ geometry.id ];
15572 if ( influences === undefined ) {
15578 for ( let i = 0; i < length; i ++ ) {
15580 influences[ i ] = [ i, 0 ];
15584 influencesList[ geometry.id ] = influences;
15588 // Collect influences
15590 for ( let i = 0; i < length; i ++ ) {
15592 const influence = influences[ i ];
15594 influence[ 0 ] = i;
15595 influence[ 1 ] = objectInfluences[ i ];
15599 influences.sort( absNumericalSort );
15601 for ( let i = 0; i < 8; i ++ ) {
15603 if ( i < length && influences[ i ][ 1 ] ) {
15605 workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
15606 workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
15610 workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
15611 workInfluences[ i ][ 1 ] = 0;
15617 workInfluences.sort( numericalSort );
15619 const morphTargets = material.morphTargets && geometry.morphAttributes.position;
15620 const morphNormals = material.morphNormals && geometry.morphAttributes.normal;
15622 let morphInfluencesSum = 0;
15624 for ( let i = 0; i < 8; i ++ ) {
15626 const influence = workInfluences[ i ];
15627 const index = influence[ 0 ];
15628 const value = influence[ 1 ];
15630 if ( index !== Number.MAX_SAFE_INTEGER && value ) {
15632 if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
15634 geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
15638 if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
15640 geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
15644 morphInfluences[ i ] = value;
15645 morphInfluencesSum += value;
15649 if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
15651 geometry.deleteAttribute( 'morphTarget' + i );
15655 if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
15657 geometry.deleteAttribute( 'morphNormal' + i );
15661 morphInfluences[ i ] = 0;
15667 // GLSL shader uses formula baseinfluence * base + sum(target * influence)
15668 // This allows us to switch between absolute morphs and relative morphs without changing shader code
15669 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
15670 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
15672 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
15673 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
15685 function WebGLObjects( gl, geometries, attributes, info ) {
15687 let updateMap = new WeakMap();
15689 function update( object ) {
15691 const frame = info.render.frame;
15693 const geometry = object.geometry;
15694 const buffergeometry = geometries.get( object, geometry );
15696 // Update once per frame
15698 if ( updateMap.get( buffergeometry ) !== frame ) {
15700 if ( geometry.isGeometry ) {
15702 buffergeometry.updateFromObject( object );
15706 geometries.update( buffergeometry );
15708 updateMap.set( buffergeometry, frame );
15712 if ( object.isInstancedMesh ) {
15714 attributes.update( object.instanceMatrix, 34962 );
15716 if ( object.instanceColor !== null ) {
15718 attributes.update( object.instanceColor, 34962 );
15724 return buffergeometry;
15728 function dispose() {
15730 updateMap = new WeakMap();
15743 function DataTexture2DArray( data = null, width = 1, height = 1, depth = 1 ) {
15745 Texture.call( this, null );
15747 this.image = { data, width, height, depth };
15749 this.magFilter = NearestFilter;
15750 this.minFilter = NearestFilter;
15752 this.wrapR = ClampToEdgeWrapping;
15754 this.generateMipmaps = false;
15755 this.flipY = false;
15757 this.needsUpdate = true;
15761 DataTexture2DArray.prototype = Object.create( Texture.prototype );
15762 DataTexture2DArray.prototype.constructor = DataTexture2DArray;
15763 DataTexture2DArray.prototype.isDataTexture2DArray = true;
15765 function DataTexture3D( data = null, width = 1, height = 1, depth = 1 ) {
15767 // We're going to add .setXXX() methods for setting properties later.
15768 // Users can still set in DataTexture3D directly.
15770 // const texture = new THREE.DataTexture3D( data, width, height, depth );
15771 // texture.anisotropy = 16;
15775 Texture.call( this, null );
15777 this.image = { data, width, height, depth };
15779 this.magFilter = NearestFilter;
15780 this.minFilter = NearestFilter;
15782 this.wrapR = ClampToEdgeWrapping;
15784 this.generateMipmaps = false;
15785 this.flipY = false;
15787 this.needsUpdate = true;
15792 DataTexture3D.prototype = Object.create( Texture.prototype );
15793 DataTexture3D.prototype.constructor = DataTexture3D;
15794 DataTexture3D.prototype.isDataTexture3D = true;
15797 * Uniforms of a program.
15798 * Those form a tree structure with a special top-level container for the root,
15799 * which you get by calling 'new WebGLUniforms( gl, program )'.
15802 * Properties of inner nodes including the top-level container:
15804 * .seq - array of nested uniforms
15805 * .map - nested uniforms by name
15808 * Methods of all nodes except the top-level container:
15810 * .setValue( gl, value, [textures] )
15812 * uploads a uniform value(s)
15813 * the 'textures' parameter is needed for sampler uniforms
15816 * Static methods of the top-level container (textures factorizations):
15818 * .upload( gl, seq, values, textures )
15820 * sets uniforms in 'seq' to 'values[id].value'
15822 * .seqWithValue( seq, values ) : filteredSeq
15824 * filters 'seq' entries with corresponding entry in values
15827 * Methods of the top-level container (textures factorizations):
15829 * .setValue( gl, name, value, textures )
15831 * sets uniform with name 'name' to 'value'
15833 * .setOptional( gl, obj, prop )
15835 * like .set for an optional property of the object
15839 const emptyTexture = new Texture();
15840 const emptyTexture2dArray = new DataTexture2DArray();
15841 const emptyTexture3d = new DataTexture3D();
15842 const emptyCubeTexture = new CubeTexture();
15844 // --- Utilities ---
15846 // Array Caches (provide typed arrays for temporary by size)
15848 const arrayCacheF32 = [];
15849 const arrayCacheI32 = [];
15851 // Float32Array caches used for uploading Matrix uniforms
15853 const mat4array = new Float32Array( 16 );
15854 const mat3array = new Float32Array( 9 );
15855 const mat2array = new Float32Array( 4 );
15857 // Flattening for arrays of vectors and matrices
15859 function flatten( array, nBlocks, blockSize ) {
15861 const firstElem = array[ 0 ];
15863 if ( firstElem <= 0 || firstElem > 0 ) return array;
15864 // unoptimized: ! isNaN( firstElem )
15865 // see http://jacksondunstan.com/articles/983
15867 const n = nBlocks * blockSize;
15868 let r = arrayCacheF32[ n ];
15870 if ( r === undefined ) {
15872 r = new Float32Array( n );
15873 arrayCacheF32[ n ] = r;
15877 if ( nBlocks !== 0 ) {
15879 firstElem.toArray( r, 0 );
15881 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
15883 offset += blockSize;
15884 array[ i ].toArray( r, offset );
15894 function arraysEqual( a, b ) {
15896 if ( a.length !== b.length ) return false;
15898 for ( let i = 0, l = a.length; i < l; i ++ ) {
15900 if ( a[ i ] !== b[ i ] ) return false;
15908 function copyArray( a, b ) {
15910 for ( let i = 0, l = b.length; i < l; i ++ ) {
15918 // Texture unit allocation
15920 function allocTexUnits( textures, n ) {
15922 let r = arrayCacheI32[ n ];
15924 if ( r === undefined ) {
15926 r = new Int32Array( n );
15927 arrayCacheI32[ n ] = r;
15931 for ( let i = 0; i !== n; ++ i ) {
15933 r[ i ] = textures.allocateTextureUnit();
15943 // Note: Defining these methods externally, because they come in a bunch
15944 // and this way their names minify.
15948 function setValueV1f( gl, v ) {
15950 const cache = this.cache;
15952 if ( cache[ 0 ] === v ) return;
15954 gl.uniform1f( this.addr, v );
15960 // Single float vector (from flat array or THREE.VectorN)
15962 function setValueV2f( gl, v ) {
15964 const cache = this.cache;
15966 if ( v.x !== undefined ) {
15968 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
15970 gl.uniform2f( this.addr, v.x, v.y );
15979 if ( arraysEqual( cache, v ) ) return;
15981 gl.uniform2fv( this.addr, v );
15983 copyArray( cache, v );
15989 function setValueV3f( gl, v ) {
15991 const cache = this.cache;
15993 if ( v.x !== undefined ) {
15995 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
15997 gl.uniform3f( this.addr, v.x, v.y, v.z );
16005 } else if ( v.r !== undefined ) {
16007 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
16009 gl.uniform3f( this.addr, v.r, v.g, v.b );
16019 if ( arraysEqual( cache, v ) ) return;
16021 gl.uniform3fv( this.addr, v );
16023 copyArray( cache, v );
16029 function setValueV4f( gl, v ) {
16031 const cache = this.cache;
16033 if ( v.x !== undefined ) {
16035 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
16037 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
16048 if ( arraysEqual( cache, v ) ) return;
16050 gl.uniform4fv( this.addr, v );
16052 copyArray( cache, v );
16058 // Single matrix (from flat array or MatrixN)
16060 function setValueM2( gl, v ) {
16062 const cache = this.cache;
16063 const elements = v.elements;
16065 if ( elements === undefined ) {
16067 if ( arraysEqual( cache, v ) ) return;
16069 gl.uniformMatrix2fv( this.addr, false, v );
16071 copyArray( cache, v );
16075 if ( arraysEqual( cache, elements ) ) return;
16077 mat2array.set( elements );
16079 gl.uniformMatrix2fv( this.addr, false, mat2array );
16081 copyArray( cache, elements );
16087 function setValueM3( gl, v ) {
16089 const cache = this.cache;
16090 const elements = v.elements;
16092 if ( elements === undefined ) {
16094 if ( arraysEqual( cache, v ) ) return;
16096 gl.uniformMatrix3fv( this.addr, false, v );
16098 copyArray( cache, v );
16102 if ( arraysEqual( cache, elements ) ) return;
16104 mat3array.set( elements );
16106 gl.uniformMatrix3fv( this.addr, false, mat3array );
16108 copyArray( cache, elements );
16114 function setValueM4( gl, v ) {
16116 const cache = this.cache;
16117 const elements = v.elements;
16119 if ( elements === undefined ) {
16121 if ( arraysEqual( cache, v ) ) return;
16123 gl.uniformMatrix4fv( this.addr, false, v );
16125 copyArray( cache, v );
16129 if ( arraysEqual( cache, elements ) ) return;
16131 mat4array.set( elements );
16133 gl.uniformMatrix4fv( this.addr, false, mat4array );
16135 copyArray( cache, elements );
16141 // Single texture (2D / Cube)
16143 function setValueT1( gl, v, textures ) {
16145 const cache = this.cache;
16146 const unit = textures.allocateTextureUnit();
16148 if ( cache[ 0 ] !== unit ) {
16150 gl.uniform1i( this.addr, unit );
16155 textures.safeSetTexture2D( v || emptyTexture, unit );
16159 function setValueT2DArray1( gl, v, textures ) {
16161 const cache = this.cache;
16162 const unit = textures.allocateTextureUnit();
16164 if ( cache[ 0 ] !== unit ) {
16166 gl.uniform1i( this.addr, unit );
16171 textures.setTexture2DArray( v || emptyTexture2dArray, unit );
16175 function setValueT3D1( gl, v, textures ) {
16177 const cache = this.cache;
16178 const unit = textures.allocateTextureUnit();
16180 if ( cache[ 0 ] !== unit ) {
16182 gl.uniform1i( this.addr, unit );
16187 textures.setTexture3D( v || emptyTexture3d, unit );
16191 function setValueT6( gl, v, textures ) {
16193 const cache = this.cache;
16194 const unit = textures.allocateTextureUnit();
16196 if ( cache[ 0 ] !== unit ) {
16198 gl.uniform1i( this.addr, unit );
16203 textures.safeSetTextureCube( v || emptyCubeTexture, unit );
16207 // Integer / Boolean vectors or arrays thereof (always flat arrays)
16209 function setValueV1i( gl, v ) {
16211 const cache = this.cache;
16213 if ( cache[ 0 ] === v ) return;
16215 gl.uniform1i( this.addr, v );
16221 function setValueV2i( gl, v ) {
16223 const cache = this.cache;
16225 if ( arraysEqual( cache, v ) ) return;
16227 gl.uniform2iv( this.addr, v );
16229 copyArray( cache, v );
16233 function setValueV3i( gl, v ) {
16235 const cache = this.cache;
16237 if ( arraysEqual( cache, v ) ) return;
16239 gl.uniform3iv( this.addr, v );
16241 copyArray( cache, v );
16245 function setValueV4i( gl, v ) {
16247 const cache = this.cache;
16249 if ( arraysEqual( cache, v ) ) return;
16251 gl.uniform4iv( this.addr, v );
16253 copyArray( cache, v );
16259 function setValueV1ui( gl, v ) {
16261 const cache = this.cache;
16263 if ( cache[ 0 ] === v ) return;
16265 gl.uniform1ui( this.addr, v );
16271 // Helper to pick the right setter for the singular case
16273 function getSingularSetter( type ) {
16277 case 0x1406: return setValueV1f; // FLOAT
16278 case 0x8b50: return setValueV2f; // _VEC2
16279 case 0x8b51: return setValueV3f; // _VEC3
16280 case 0x8b52: return setValueV4f; // _VEC4
16282 case 0x8b5a: return setValueM2; // _MAT2
16283 case 0x8b5b: return setValueM3; // _MAT3
16284 case 0x8b5c: return setValueM4; // _MAT4
16286 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
16287 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
16288 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
16289 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
16291 case 0x1405: return setValueV1ui; // UINT
16293 case 0x8b5e: // SAMPLER_2D
16294 case 0x8d66: // SAMPLER_EXTERNAL_OES
16295 case 0x8dca: // INT_SAMPLER_2D
16296 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
16297 case 0x8b62: // SAMPLER_2D_SHADOW
16300 case 0x8b5f: // SAMPLER_3D
16301 case 0x8dcb: // INT_SAMPLER_3D
16302 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
16303 return setValueT3D1;
16305 case 0x8b60: // SAMPLER_CUBE
16306 case 0x8dcc: // INT_SAMPLER_CUBE
16307 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
16308 case 0x8dc5: // SAMPLER_CUBE_SHADOW
16311 case 0x8dc1: // SAMPLER_2D_ARRAY
16312 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
16313 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
16314 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
16315 return setValueT2DArray1;
16321 // Array of scalars
16322 function setValueV1fArray( gl, v ) {
16324 gl.uniform1fv( this.addr, v );
16328 // Integer / Boolean vectors or arrays thereof (always flat arrays)
16329 function setValueV1iArray( gl, v ) {
16331 gl.uniform1iv( this.addr, v );
16335 function setValueV2iArray( gl, v ) {
16337 gl.uniform2iv( this.addr, v );
16341 function setValueV3iArray( gl, v ) {
16343 gl.uniform3iv( this.addr, v );
16347 function setValueV4iArray( gl, v ) {
16349 gl.uniform4iv( this.addr, v );
16354 // Array of vectors (flat or from THREE classes)
16356 function setValueV2fArray( gl, v ) {
16358 const data = flatten( v, this.size, 2 );
16360 gl.uniform2fv( this.addr, data );
16364 function setValueV3fArray( gl, v ) {
16366 const data = flatten( v, this.size, 3 );
16368 gl.uniform3fv( this.addr, data );
16372 function setValueV4fArray( gl, v ) {
16374 const data = flatten( v, this.size, 4 );
16376 gl.uniform4fv( this.addr, data );
16380 // Array of matrices (flat or from THREE clases)
16382 function setValueM2Array( gl, v ) {
16384 const data = flatten( v, this.size, 4 );
16386 gl.uniformMatrix2fv( this.addr, false, data );
16390 function setValueM3Array( gl, v ) {
16392 const data = flatten( v, this.size, 9 );
16394 gl.uniformMatrix3fv( this.addr, false, data );
16398 function setValueM4Array( gl, v ) {
16400 const data = flatten( v, this.size, 16 );
16402 gl.uniformMatrix4fv( this.addr, false, data );
16406 // Array of textures (2D / Cube)
16408 function setValueT1Array( gl, v, textures ) {
16410 const n = v.length;
16412 const units = allocTexUnits( textures, n );
16414 gl.uniform1iv( this.addr, units );
16416 for ( let i = 0; i !== n; ++ i ) {
16418 textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] );
16424 function setValueT6Array( gl, v, textures ) {
16426 const n = v.length;
16428 const units = allocTexUnits( textures, n );
16430 gl.uniform1iv( this.addr, units );
16432 for ( let i = 0; i !== n; ++ i ) {
16434 textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
16440 // Helper to pick the right setter for a pure (bottom-level) array
16442 function getPureArraySetter( type ) {
16446 case 0x1406: return setValueV1fArray; // FLOAT
16447 case 0x8b50: return setValueV2fArray; // _VEC2
16448 case 0x8b51: return setValueV3fArray; // _VEC3
16449 case 0x8b52: return setValueV4fArray; // _VEC4
16451 case 0x8b5a: return setValueM2Array; // _MAT2
16452 case 0x8b5b: return setValueM3Array; // _MAT3
16453 case 0x8b5c: return setValueM4Array; // _MAT4
16455 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
16456 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
16457 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
16458 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
16460 case 0x8b5e: // SAMPLER_2D
16461 case 0x8d66: // SAMPLER_EXTERNAL_OES
16462 case 0x8dca: // INT_SAMPLER_2D
16463 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
16464 case 0x8b62: // SAMPLER_2D_SHADOW
16465 return setValueT1Array;
16467 case 0x8b60: // SAMPLER_CUBE
16468 case 0x8dcc: // INT_SAMPLER_CUBE
16469 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
16470 case 0x8dc5: // SAMPLER_CUBE_SHADOW
16471 return setValueT6Array;
16477 // --- Uniform Classes ---
16479 function SingleUniform( id, activeInfo, addr ) {
16484 this.setValue = getSingularSetter( activeInfo.type );
16486 // this.path = activeInfo.name; // DEBUG
16490 function PureArrayUniform( id, activeInfo, addr ) {
16495 this.size = activeInfo.size;
16496 this.setValue = getPureArraySetter( activeInfo.type );
16498 // this.path = activeInfo.name; // DEBUG
16502 PureArrayUniform.prototype.updateCache = function ( data ) {
16504 const cache = this.cache;
16506 if ( data instanceof Float32Array && cache.length !== data.length ) {
16508 this.cache = new Float32Array( data.length );
16512 copyArray( cache, data );
16516 function StructuredUniform( id ) {
16525 StructuredUniform.prototype.setValue = function ( gl, value, textures ) {
16527 const seq = this.seq;
16529 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16531 const u = seq[ i ];
16532 u.setValue( gl, value[ u.id ], textures );
16538 // --- Top-level ---
16540 // Parser - builds up the property tree from the path strings
16542 const RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
16545 // - the identifier (member name or array index)
16546 // - followed by an optional right bracket (found when array index)
16547 // - followed by an optional left bracket or dot (type of subscript)
16549 // Note: These portions can be read in a non-overlapping fashion and
16550 // allow straightforward parsing of the hierarchy that WebGL encodes
16551 // in the uniform names.
16553 function addUniform( container, uniformObject ) {
16555 container.seq.push( uniformObject );
16556 container.map[ uniformObject.id ] = uniformObject;
16560 function parseUniform( activeInfo, addr, container ) {
16562 const path = activeInfo.name,
16563 pathLength = path.length;
16565 // reset RegExp object, because of the early exit of a previous run
16566 RePathPart.lastIndex = 0;
16570 const match = RePathPart.exec( path ),
16571 matchEnd = RePathPart.lastIndex;
16573 let id = match[ 1 ];
16574 const idIsIndex = match[ 2 ] === ']',
16575 subscript = match[ 3 ];
16577 if ( idIsIndex ) id = id | 0; // convert to integer
16579 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
16581 // bare name or "pure" bottom-level array "[0]" suffix
16583 addUniform( container, subscript === undefined ?
16584 new SingleUniform( id, activeInfo, addr ) :
16585 new PureArrayUniform( id, activeInfo, addr ) );
16591 // step into inner node / create it in case it doesn't exist
16593 const map = container.map;
16594 let next = map[ id ];
16596 if ( next === undefined ) {
16598 next = new StructuredUniform( id );
16599 addUniform( container, next );
16613 function WebGLUniforms( gl, program ) {
16618 const n = gl.getProgramParameter( program, 35718 );
16620 for ( let i = 0; i < n; ++ i ) {
16622 const info = gl.getActiveUniform( program, i ),
16623 addr = gl.getUniformLocation( program, info.name );
16625 parseUniform( info, addr, this );
16631 WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
16633 const u = this.map[ name ];
16635 if ( u !== undefined ) u.setValue( gl, value, textures );
16639 WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
16641 const v = object[ name ];
16643 if ( v !== undefined ) this.setValue( gl, name, v );
16648 // Static interface
16650 WebGLUniforms.upload = function ( gl, seq, values, textures ) {
16652 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16654 const u = seq[ i ],
16655 v = values[ u.id ];
16657 if ( v.needsUpdate !== false ) {
16659 // note: always updating when .needsUpdate is undefined
16660 u.setValue( gl, v.value, textures );
16668 WebGLUniforms.seqWithValue = function ( seq, values ) {
16672 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
16674 const u = seq[ i ];
16675 if ( u.id in values ) r.push( u );
16683 function WebGLShader( gl, type, string ) {
16685 const shader = gl.createShader( type );
16687 gl.shaderSource( shader, string );
16688 gl.compileShader( shader );
16694 let programIdCount = 0;
16696 function addLineNumbers( string ) {
16698 const lines = string.split( '\n' );
16700 for ( let i = 0; i < lines.length; i ++ ) {
16702 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
16706 return lines.join( '\n' );
16710 function getEncodingComponents( encoding ) {
16712 switch ( encoding ) {
16714 case LinearEncoding:
16715 return [ 'Linear', '( value )' ];
16717 return [ 'sRGB', '( value )' ];
16719 return [ 'RGBE', '( value )' ];
16720 case RGBM7Encoding:
16721 return [ 'RGBM', '( value, 7.0 )' ];
16722 case RGBM16Encoding:
16723 return [ 'RGBM', '( value, 16.0 )' ];
16725 return [ 'RGBD', '( value, 256.0 )' ];
16726 case GammaEncoding:
16727 return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
16728 case LogLuvEncoding:
16729 return [ 'LogLuv', '( value )' ];
16731 console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding );
16732 return [ 'Linear', '( value )' ];
16738 function getShaderErrors( gl, shader, type ) {
16740 const status = gl.getShaderParameter( shader, 35713 );
16741 const log = gl.getShaderInfoLog( shader ).trim();
16743 if ( status && log === '' ) return '';
16745 // --enable-privileged-webgl-extension
16746 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
16748 const source = gl.getShaderSource( shader );
16750 return 'THREE.WebGLShader: gl.getShaderInfoLog() ' + type + '\n' + log + addLineNumbers( source );
16754 function getTexelDecodingFunction( functionName, encoding ) {
16756 const components = getEncodingComponents( encoding );
16757 return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
16761 function getTexelEncodingFunction( functionName, encoding ) {
16763 const components = getEncodingComponents( encoding );
16764 return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
16768 function getToneMappingFunction( functionName, toneMapping ) {
16770 let toneMappingName;
16772 switch ( toneMapping ) {
16774 case LinearToneMapping:
16775 toneMappingName = 'Linear';
16778 case ReinhardToneMapping:
16779 toneMappingName = 'Reinhard';
16782 case CineonToneMapping:
16783 toneMappingName = 'OptimizedCineon';
16786 case ACESFilmicToneMapping:
16787 toneMappingName = 'ACESFilmic';
16790 case CustomToneMapping:
16791 toneMappingName = 'Custom';
16795 console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
16796 toneMappingName = 'Linear';
16800 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
16804 function generateExtensions( parameters ) {
16807 ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
16808 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
16809 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
16810 ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
16813 return chunks.filter( filterEmptyLine ).join( '\n' );
16817 function generateDefines( defines ) {
16821 for ( const name in defines ) {
16823 const value = defines[ name ];
16825 if ( value === false ) continue;
16827 chunks.push( '#define ' + name + ' ' + value );
16831 return chunks.join( '\n' );
16835 function fetchAttributeLocations( gl, program ) {
16837 const attributes = {};
16839 const n = gl.getProgramParameter( program, 35721 );
16841 for ( let i = 0; i < n; i ++ ) {
16843 const info = gl.getActiveAttrib( program, i );
16844 const name = info.name;
16846 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
16848 attributes[ name ] = gl.getAttribLocation( program, name );
16856 function filterEmptyLine( string ) {
16858 return string !== '';
16862 function replaceLightNums( string, parameters ) {
16865 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
16866 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
16867 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
16868 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
16869 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
16870 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
16871 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
16872 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
16876 function replaceClippingPlaneNums( string, parameters ) {
16879 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
16880 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
16884 // Resolve Includes
16886 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
16888 function resolveIncludes( string ) {
16890 return string.replace( includePattern, includeReplacer );
16894 function includeReplacer( match, include ) {
16896 const string = ShaderChunk[ include ];
16898 if ( string === undefined ) {
16900 throw new Error( 'Can not resolve #include <' + include + '>' );
16904 return resolveIncludes( string );
16910 const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
16911 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;
16913 function unrollLoops( string ) {
16916 .replace( unrollLoopPattern, loopReplacer )
16917 .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer );
16921 function deprecatedLoopReplacer( match, start, end, snippet ) {
16923 console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' );
16924 return loopReplacer( match, start, end, snippet );
16928 function loopReplacer( match, start, end, snippet ) {
16932 for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
16935 .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
16936 .replace( /UNROLLED_LOOP_INDEX/g, i );
16946 function generatePrecision( parameters ) {
16948 let precisionstring = "precision " + parameters.precision + " float;\nprecision " + parameters.precision + " int;";
16950 if ( parameters.precision === "highp" ) {
16952 precisionstring += "\n#define HIGH_PRECISION";
16954 } else if ( parameters.precision === "mediump" ) {
16956 precisionstring += "\n#define MEDIUM_PRECISION";
16958 } else if ( parameters.precision === "lowp" ) {
16960 precisionstring += "\n#define LOW_PRECISION";
16964 return precisionstring;
16968 function generateShadowMapTypeDefine( parameters ) {
16970 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
16972 if ( parameters.shadowMapType === PCFShadowMap ) {
16974 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
16976 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
16978 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
16980 } else if ( parameters.shadowMapType === VSMShadowMap ) {
16982 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
16986 return shadowMapTypeDefine;
16990 function generateEnvMapTypeDefine( parameters ) {
16992 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
16994 if ( parameters.envMap ) {
16996 switch ( parameters.envMapMode ) {
16998 case CubeReflectionMapping:
16999 case CubeRefractionMapping:
17000 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
17003 case CubeUVReflectionMapping:
17004 case CubeUVRefractionMapping:
17005 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
17012 return envMapTypeDefine;
17016 function generateEnvMapModeDefine( parameters ) {
17018 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
17020 if ( parameters.envMap ) {
17022 switch ( parameters.envMapMode ) {
17024 case CubeRefractionMapping:
17025 case CubeUVRefractionMapping:
17027 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
17034 return envMapModeDefine;
17038 function generateEnvMapBlendingDefine( parameters ) {
17040 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
17042 if ( parameters.envMap ) {
17044 switch ( parameters.combine ) {
17046 case MultiplyOperation:
17047 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
17051 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
17055 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
17062 return envMapBlendingDefine;
17066 function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
17068 const gl = renderer.getContext();
17070 const defines = parameters.defines;
17072 let vertexShader = parameters.vertexShader;
17073 let fragmentShader = parameters.fragmentShader;
17075 const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
17076 const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
17077 const envMapModeDefine = generateEnvMapModeDefine( parameters );
17078 const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
17081 const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
17083 const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
17085 const customDefines = generateDefines( defines );
17087 const program = gl.createProgram();
17089 let prefixVertex, prefixFragment;
17090 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + "\n" : '';
17092 if ( parameters.isRawShaderMaterial ) {
17098 ].filter( filterEmptyLine ).join( '\n' );
17100 if ( prefixVertex.length > 0 ) {
17102 prefixVertex += '\n';
17111 ].filter( filterEmptyLine ).join( '\n' );
17113 if ( prefixFragment.length > 0 ) {
17115 prefixFragment += '\n';
17123 generatePrecision( parameters ),
17125 '#define SHADER_NAME ' + parameters.shaderName,
17129 parameters.instancing ? '#define USE_INSTANCING' : '',
17130 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
17132 parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
17134 '#define GAMMA_FACTOR ' + gammaFactorDefine,
17136 '#define MAX_BONES ' + parameters.maxBones,
17137 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
17138 ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
17140 parameters.map ? '#define USE_MAP' : '',
17141 parameters.envMap ? '#define USE_ENVMAP' : '',
17142 parameters.envMap ? '#define ' + envMapModeDefine : '',
17143 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
17144 parameters.aoMap ? '#define USE_AOMAP' : '',
17145 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
17146 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
17147 parameters.normalMap ? '#define USE_NORMALMAP' : '',
17148 ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
17149 ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
17151 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
17152 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
17153 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
17154 parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
17155 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
17156 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
17157 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
17158 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
17159 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
17161 parameters.vertexTangents ? '#define USE_TANGENT' : '',
17162 parameters.vertexColors ? '#define USE_COLOR' : '',
17163 parameters.vertexUvs ? '#define USE_UV' : '',
17164 parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
17166 parameters.flatShading ? '#define FLAT_SHADED' : '',
17168 parameters.skinning ? '#define USE_SKINNING' : '',
17169 parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
17171 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
17172 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
17173 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
17174 parameters.flipSided ? '#define FLIP_SIDED' : '',
17176 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
17177 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
17179 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
17181 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
17182 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
17184 'uniform mat4 modelMatrix;',
17185 'uniform mat4 modelViewMatrix;',
17186 'uniform mat4 projectionMatrix;',
17187 'uniform mat4 viewMatrix;',
17188 'uniform mat3 normalMatrix;',
17189 'uniform vec3 cameraPosition;',
17190 'uniform bool isOrthographic;',
17192 '#ifdef USE_INSTANCING',
17194 ' attribute mat4 instanceMatrix;',
17198 '#ifdef USE_INSTANCING_COLOR',
17200 ' attribute vec3 instanceColor;',
17204 'attribute vec3 position;',
17205 'attribute vec3 normal;',
17206 'attribute vec2 uv;',
17208 '#ifdef USE_TANGENT',
17210 ' attribute vec4 tangent;',
17214 '#ifdef USE_COLOR',
17216 ' attribute vec3 color;',
17220 '#ifdef USE_MORPHTARGETS',
17222 ' attribute vec3 morphTarget0;',
17223 ' attribute vec3 morphTarget1;',
17224 ' attribute vec3 morphTarget2;',
17225 ' attribute vec3 morphTarget3;',
17227 ' #ifdef USE_MORPHNORMALS',
17229 ' attribute vec3 morphNormal0;',
17230 ' attribute vec3 morphNormal1;',
17231 ' attribute vec3 morphNormal2;',
17232 ' attribute vec3 morphNormal3;',
17236 ' attribute vec3 morphTarget4;',
17237 ' attribute vec3 morphTarget5;',
17238 ' attribute vec3 morphTarget6;',
17239 ' attribute vec3 morphTarget7;',
17245 '#ifdef USE_SKINNING',
17247 ' attribute vec4 skinIndex;',
17248 ' attribute vec4 skinWeight;',
17254 ].filter( filterEmptyLine ).join( '\n' );
17260 generatePrecision( parameters ),
17262 '#define SHADER_NAME ' + parameters.shaderName,
17266 parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
17268 '#define GAMMA_FACTOR ' + gammaFactorDefine,
17270 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
17271 ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
17273 parameters.map ? '#define USE_MAP' : '',
17274 parameters.matcap ? '#define USE_MATCAP' : '',
17275 parameters.envMap ? '#define USE_ENVMAP' : '',
17276 parameters.envMap ? '#define ' + envMapTypeDefine : '',
17277 parameters.envMap ? '#define ' + envMapModeDefine : '',
17278 parameters.envMap ? '#define ' + envMapBlendingDefine : '',
17279 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
17280 parameters.aoMap ? '#define USE_AOMAP' : '',
17281 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
17282 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
17283 parameters.normalMap ? '#define USE_NORMALMAP' : '',
17284 ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
17285 ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
17286 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
17287 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
17288 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
17289 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
17290 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
17291 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
17292 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
17294 parameters.sheen ? '#define USE_SHEEN' : '',
17295 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
17297 parameters.vertexTangents ? '#define USE_TANGENT' : '',
17298 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
17299 parameters.vertexUvs ? '#define USE_UV' : '',
17300 parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
17302 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
17304 parameters.flatShading ? '#define FLAT_SHADED' : '',
17306 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
17307 parameters.flipSided ? '#define FLIP_SIDED' : '',
17309 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
17310 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
17312 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
17314 parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
17316 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
17317 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
17319 ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '',
17321 'uniform mat4 viewMatrix;',
17322 'uniform vec3 cameraPosition;',
17323 'uniform bool isOrthographic;',
17325 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
17326 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
17327 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
17329 parameters.dithering ? '#define DITHERING' : '',
17331 ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
17332 parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
17333 parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
17334 parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
17335 parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
17336 parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
17337 getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
17339 parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
17343 ].filter( filterEmptyLine ).join( '\n' );
17347 vertexShader = resolveIncludes( vertexShader );
17348 vertexShader = replaceLightNums( vertexShader, parameters );
17349 vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
17351 fragmentShader = resolveIncludes( fragmentShader );
17352 fragmentShader = replaceLightNums( fragmentShader, parameters );
17353 fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
17355 vertexShader = unrollLoops( vertexShader );
17356 fragmentShader = unrollLoops( fragmentShader );
17358 if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
17360 // GLSL 3.0 conversion for built-in materials and ShaderMaterial
17362 versionString = '#version 300 es\n';
17365 '#define attribute in',
17366 '#define varying out',
17367 '#define texture2D texture'
17368 ].join( '\n' ) + '\n' + prefixVertex;
17371 '#define varying in',
17372 ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;',
17373 ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
17374 '#define gl_FragDepthEXT gl_FragDepth',
17375 '#define texture2D texture',
17376 '#define textureCube texture',
17377 '#define texture2DProj textureProj',
17378 '#define texture2DLodEXT textureLod',
17379 '#define texture2DProjLodEXT textureProjLod',
17380 '#define textureCubeLodEXT textureLod',
17381 '#define texture2DGradEXT textureGrad',
17382 '#define texture2DProjGradEXT textureProjGrad',
17383 '#define textureCubeGradEXT textureGrad'
17384 ].join( '\n' ) + '\n' + prefixFragment;
17388 const vertexGlsl = versionString + prefixVertex + vertexShader;
17389 const fragmentGlsl = versionString + prefixFragment + fragmentShader;
17391 // console.log( '*VERTEX*', vertexGlsl );
17392 // console.log( '*FRAGMENT*', fragmentGlsl );
17394 const glVertexShader = WebGLShader( gl, 35633, vertexGlsl );
17395 const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl );
17397 gl.attachShader( program, glVertexShader );
17398 gl.attachShader( program, glFragmentShader );
17400 // Force a particular attribute to index 0.
17402 if ( parameters.index0AttributeName !== undefined ) {
17404 gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
17406 } else if ( parameters.morphTargets === true ) {
17408 // programs with morphTargets displace position out of attribute 0
17409 gl.bindAttribLocation( program, 0, 'position' );
17413 gl.linkProgram( program );
17415 // check for link errors
17416 if ( renderer.debug.checkShaderErrors ) {
17418 const programLog = gl.getProgramInfoLog( program ).trim();
17419 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
17420 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
17422 let runnable = true;
17423 let haveDiagnostics = true;
17425 if ( gl.getProgramParameter( program, 35714 ) === false ) {
17429 const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
17430 const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
17432 console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors );
17434 } else if ( programLog !== '' ) {
17436 console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
17438 } else if ( vertexLog === '' || fragmentLog === '' ) {
17440 haveDiagnostics = false;
17444 if ( haveDiagnostics ) {
17446 this.diagnostics = {
17448 runnable: runnable,
17450 programLog: programLog,
17455 prefix: prefixVertex
17462 prefix: prefixFragment
17474 // Crashes in iOS9 and iOS10. #18402
17475 // gl.detachShader( program, glVertexShader );
17476 // gl.detachShader( program, glFragmentShader );
17478 gl.deleteShader( glVertexShader );
17479 gl.deleteShader( glFragmentShader );
17481 // set up caching for uniform locations
17483 let cachedUniforms;
17485 this.getUniforms = function () {
17487 if ( cachedUniforms === undefined ) {
17489 cachedUniforms = new WebGLUniforms( gl, program );
17493 return cachedUniforms;
17497 // set up caching for attribute locations
17499 let cachedAttributes;
17501 this.getAttributes = function () {
17503 if ( cachedAttributes === undefined ) {
17505 cachedAttributes = fetchAttributeLocations( gl, program );
17509 return cachedAttributes;
17515 this.destroy = function () {
17517 bindingStates.releaseStatesOfProgram( this );
17519 gl.deleteProgram( program );
17520 this.program = undefined;
17526 this.name = parameters.shaderName;
17527 this.id = programIdCount ++;
17528 this.cacheKey = cacheKey;
17529 this.usedTimes = 1;
17530 this.program = program;
17531 this.vertexShader = glVertexShader;
17532 this.fragmentShader = glFragmentShader;
17538 function WebGLPrograms( renderer, cubemaps, extensions, capabilities, bindingStates, clipping ) {
17540 const programs = [];
17542 const isWebGL2 = capabilities.isWebGL2;
17543 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
17544 const floatVertexTextures = capabilities.floatVertexTextures;
17545 const maxVertexUniforms = capabilities.maxVertexUniforms;
17546 const vertexTextures = capabilities.vertexTextures;
17548 let precision = capabilities.precision;
17550 const shaderIDs = {
17551 MeshDepthMaterial: 'depth',
17552 MeshDistanceMaterial: 'distanceRGBA',
17553 MeshNormalMaterial: 'normal',
17554 MeshBasicMaterial: 'basic',
17555 MeshLambertMaterial: 'lambert',
17556 MeshPhongMaterial: 'phong',
17557 MeshToonMaterial: 'toon',
17558 MeshStandardMaterial: 'physical',
17559 MeshPhysicalMaterial: 'physical',
17560 MeshMatcapMaterial: 'matcap',
17561 LineBasicMaterial: 'basic',
17562 LineDashedMaterial: 'dashed',
17563 PointsMaterial: 'points',
17564 ShadowMaterial: 'shadow',
17565 SpriteMaterial: 'sprite'
17568 const parameterNames = [
17569 "precision", "isWebGL2", "supportsVertexTextures", "outputEncoding", "instancing", "instancingColor",
17570 "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding", "envMapCubeUV",
17571 "lightMap", "lightMapEncoding", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "tangentSpaceNormalMap", "clearcoatMap", "clearcoatRoughnessMap", "clearcoatNormalMap", "displacementMap", "specularMap",
17572 "roughnessMap", "metalnessMap", "gradientMap",
17573 "alphaMap", "combine", "vertexColors", "vertexTangents", "vertexUvs", "uvsVertexOnly", "fog", "useFog", "fogExp2",
17574 "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
17575 "maxBones", "useVertexTexture", "morphTargets", "morphNormals",
17576 "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
17577 "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
17578 "numDirLightShadows", "numPointLightShadows", "numSpotLightShadows",
17579 "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
17580 "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering",
17581 "sheen", "transmissionMap"
17584 function getMaxBones( object ) {
17586 const skeleton = object.skeleton;
17587 const bones = skeleton.bones;
17589 if ( floatVertexTextures ) {
17595 // default for when object is not specified
17596 // ( for example when prebuilding shader to be used with multiple objects )
17598 // - leave some extra space for other uniforms
17599 // - limit here is ANGLE's 254 max uniform vectors
17600 // (up to 54 should be safe)
17602 const nVertexUniforms = maxVertexUniforms;
17603 const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
17605 const maxBones = Math.min( nVertexMatrices, bones.length );
17607 if ( maxBones < bones.length ) {
17609 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
17620 function getTextureEncodingFromMap( map ) {
17626 encoding = LinearEncoding;
17628 } else if ( map.isTexture ) {
17630 encoding = map.encoding;
17632 } else if ( map.isWebGLRenderTarget ) {
17634 console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
17635 encoding = map.texture.encoding;
17643 function getParameters( material, lights, shadows, scene, object ) {
17645 const fog = scene.fog;
17646 const environment = material.isMeshStandardMaterial ? scene.environment : null;
17648 const envMap = cubemaps.get( material.envMap || environment );
17650 const shaderID = shaderIDs[ material.type ];
17652 // heuristics to create shader parameters according to lights in the scene
17653 // (not to blow over maxLights budget)
17655 const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0;
17657 if ( material.precision !== null ) {
17659 precision = capabilities.getMaxPrecision( material.precision );
17661 if ( precision !== material.precision ) {
17663 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
17669 let vertexShader, fragmentShader;
17673 const shader = ShaderLib[ shaderID ];
17675 vertexShader = shader.vertexShader;
17676 fragmentShader = shader.fragmentShader;
17680 vertexShader = material.vertexShader;
17681 fragmentShader = material.fragmentShader;
17685 const currentRenderTarget = renderer.getRenderTarget();
17687 const parameters = {
17689 isWebGL2: isWebGL2,
17691 shaderID: shaderID,
17692 shaderName: material.type,
17694 vertexShader: vertexShader,
17695 fragmentShader: fragmentShader,
17696 defines: material.defines,
17698 isRawShaderMaterial: material.isRawShaderMaterial === true,
17699 glslVersion: material.glslVersion,
17701 precision: precision,
17703 instancing: object.isInstancedMesh === true,
17704 instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
17706 supportsVertexTextures: vertexTextures,
17707 outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
17708 map: !! material.map,
17709 mapEncoding: getTextureEncodingFromMap( material.map ),
17710 matcap: !! material.matcap,
17711 matcapEncoding: getTextureEncodingFromMap( material.matcap ),
17713 envMapMode: envMap && envMap.mapping,
17714 envMapEncoding: getTextureEncodingFromMap( envMap ),
17715 envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
17716 lightMap: !! material.lightMap,
17717 lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
17718 aoMap: !! material.aoMap,
17719 emissiveMap: !! material.emissiveMap,
17720 emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
17721 bumpMap: !! material.bumpMap,
17722 normalMap: !! material.normalMap,
17723 objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
17724 tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
17725 clearcoatMap: !! material.clearcoatMap,
17726 clearcoatRoughnessMap: !! material.clearcoatRoughnessMap,
17727 clearcoatNormalMap: !! material.clearcoatNormalMap,
17728 displacementMap: !! material.displacementMap,
17729 roughnessMap: !! material.roughnessMap,
17730 metalnessMap: !! material.metalnessMap,
17731 specularMap: !! material.specularMap,
17732 alphaMap: !! material.alphaMap,
17734 gradientMap: !! material.gradientMap,
17736 sheen: !! material.sheen,
17738 transmissionMap: !! material.transmissionMap,
17740 combine: material.combine,
17742 vertexTangents: ( material.normalMap && material.vertexTangents ),
17743 vertexColors: material.vertexColors,
17744 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,
17745 uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.transmissionMap ) && !! material.displacementMap,
17748 useFog: material.fog,
17749 fogExp2: ( fog && fog.isFogExp2 ),
17751 flatShading: material.flatShading,
17753 sizeAttenuation: material.sizeAttenuation,
17754 logarithmicDepthBuffer: logarithmicDepthBuffer,
17756 skinning: material.skinning && maxBones > 0,
17757 maxBones: maxBones,
17758 useVertexTexture: floatVertexTextures,
17760 morphTargets: material.morphTargets,
17761 morphNormals: material.morphNormals,
17762 maxMorphTargets: renderer.maxMorphTargets,
17763 maxMorphNormals: renderer.maxMorphNormals,
17765 numDirLights: lights.directional.length,
17766 numPointLights: lights.point.length,
17767 numSpotLights: lights.spot.length,
17768 numRectAreaLights: lights.rectArea.length,
17769 numHemiLights: lights.hemi.length,
17771 numDirLightShadows: lights.directionalShadowMap.length,
17772 numPointLightShadows: lights.pointShadowMap.length,
17773 numSpotLightShadows: lights.spotShadowMap.length,
17775 numClippingPlanes: clipping.numPlanes,
17776 numClipIntersection: clipping.numIntersection,
17778 dithering: material.dithering,
17780 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
17781 shadowMapType: renderer.shadowMap.type,
17783 toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
17784 physicallyCorrectLights: renderer.physicallyCorrectLights,
17786 premultipliedAlpha: material.premultipliedAlpha,
17788 alphaTest: material.alphaTest,
17789 doubleSided: material.side === DoubleSide,
17790 flipSided: material.side === BackSide,
17792 depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false,
17794 index0AttributeName: material.index0AttributeName,
17796 extensionDerivatives: material.extensions && material.extensions.derivatives,
17797 extensionFragDepth: material.extensions && material.extensions.fragDepth,
17798 extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
17799 extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
17801 rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
17802 rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
17803 rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
17805 customProgramCacheKey: material.customProgramCacheKey()
17813 function getProgramCacheKey( parameters ) {
17817 if ( parameters.shaderID ) {
17819 array.push( parameters.shaderID );
17823 array.push( parameters.fragmentShader );
17824 array.push( parameters.vertexShader );
17828 if ( parameters.defines !== undefined ) {
17830 for ( const name in parameters.defines ) {
17832 array.push( name );
17833 array.push( parameters.defines[ name ] );
17839 if ( parameters.isRawShaderMaterial === false ) {
17841 for ( let i = 0; i < parameterNames.length; i ++ ) {
17843 array.push( parameters[ parameterNames[ i ] ] );
17847 array.push( renderer.outputEncoding );
17848 array.push( renderer.gammaFactor );
17852 array.push( parameters.customProgramCacheKey );
17854 return array.join();
17858 function getUniforms( material ) {
17860 const shaderID = shaderIDs[ material.type ];
17865 const shader = ShaderLib[ shaderID ];
17866 uniforms = UniformsUtils.clone( shader.uniforms );
17870 uniforms = material.uniforms;
17878 function acquireProgram( parameters, cacheKey ) {
17882 // Check if code has been already compiled
17883 for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
17885 const preexistingProgram = programs[ p ];
17887 if ( preexistingProgram.cacheKey === cacheKey ) {
17889 program = preexistingProgram;
17890 ++ program.usedTimes;
17898 if ( program === undefined ) {
17900 program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
17901 programs.push( program );
17909 function releaseProgram( program ) {
17911 if ( -- program.usedTimes === 0 ) {
17913 // Remove from unordered set
17914 const i = programs.indexOf( program );
17915 programs[ i ] = programs[ programs.length - 1 ];
17918 // Free WebGL resources
17926 getParameters: getParameters,
17927 getProgramCacheKey: getProgramCacheKey,
17928 getUniforms: getUniforms,
17929 acquireProgram: acquireProgram,
17930 releaseProgram: releaseProgram,
17931 // Exposed for resource monitoring & error feedback via renderer.info:
17937 function WebGLProperties() {
17939 let properties = new WeakMap();
17941 function get( object ) {
17943 let map = properties.get( object );
17945 if ( map === undefined ) {
17948 properties.set( object, map );
17956 function remove( object ) {
17958 properties.delete( object );
17962 function update( object, key, value ) {
17964 properties.get( object )[ key ] = value;
17968 function dispose() {
17970 properties = new WeakMap();
17983 function painterSortStable( a, b ) {
17985 if ( a.groupOrder !== b.groupOrder ) {
17987 return a.groupOrder - b.groupOrder;
17989 } else if ( a.renderOrder !== b.renderOrder ) {
17991 return a.renderOrder - b.renderOrder;
17993 } else if ( a.program !== b.program ) {
17995 return a.program.id - b.program.id;
17997 } else if ( a.material.id !== b.material.id ) {
17999 return a.material.id - b.material.id;
18001 } else if ( a.z !== b.z ) {
18007 return a.id - b.id;
18013 function reversePainterSortStable( a, b ) {
18015 if ( a.groupOrder !== b.groupOrder ) {
18017 return a.groupOrder - b.groupOrder;
18019 } else if ( a.renderOrder !== b.renderOrder ) {
18021 return a.renderOrder - b.renderOrder;
18023 } else if ( a.z !== b.z ) {
18029 return a.id - b.id;
18036 function WebGLRenderList( properties ) {
18038 const renderItems = [];
18039 let renderItemsIndex = 0;
18042 const transparent = [];
18044 const defaultProgram = { id: - 1 };
18048 renderItemsIndex = 0;
18051 transparent.length = 0;
18055 function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
18057 let renderItem = renderItems[ renderItemsIndex ];
18058 const materialProperties = properties.get( material );
18060 if ( renderItem === undefined ) {
18065 geometry: geometry,
18066 material: material,
18067 program: materialProperties.program || defaultProgram,
18068 groupOrder: groupOrder,
18069 renderOrder: object.renderOrder,
18074 renderItems[ renderItemsIndex ] = renderItem;
18078 renderItem.id = object.id;
18079 renderItem.object = object;
18080 renderItem.geometry = geometry;
18081 renderItem.material = material;
18082 renderItem.program = materialProperties.program || defaultProgram;
18083 renderItem.groupOrder = groupOrder;
18084 renderItem.renderOrder = object.renderOrder;
18086 renderItem.group = group;
18090 renderItemsIndex ++;
18096 function push( object, geometry, material, groupOrder, z, group ) {
18098 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
18100 ( material.transparent === true ? transparent : opaque ).push( renderItem );
18104 function unshift( object, geometry, material, groupOrder, z, group ) {
18106 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
18108 ( material.transparent === true ? transparent : opaque ).unshift( renderItem );
18112 function sort( customOpaqueSort, customTransparentSort ) {
18114 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
18115 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
18119 function finish() {
18121 // Clear references from inactive renderItems in the list
18123 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
18125 const renderItem = renderItems[ i ];
18127 if ( renderItem.id === null ) break;
18129 renderItem.id = null;
18130 renderItem.object = null;
18131 renderItem.geometry = null;
18132 renderItem.material = null;
18133 renderItem.program = null;
18134 renderItem.group = null;
18143 transparent: transparent,
18155 function WebGLRenderLists( properties ) {
18157 let lists = new WeakMap();
18159 function get( scene, camera ) {
18161 const cameras = lists.get( scene );
18164 if ( cameras === undefined ) {
18166 list = new WebGLRenderList( properties );
18167 lists.set( scene, new WeakMap() );
18168 lists.get( scene ).set( camera, list );
18172 list = cameras.get( camera );
18173 if ( list === undefined ) {
18175 list = new WebGLRenderList( properties );
18176 cameras.set( camera, list );
18186 function dispose() {
18188 lists = new WeakMap();
18199 function UniformsCache() {
18205 get: function ( light ) {
18207 if ( lights[ light.id ] !== undefined ) {
18209 return lights[ light.id ];
18215 switch ( light.type ) {
18217 case 'DirectionalLight':
18219 direction: new Vector3(),
18226 position: new Vector3(),
18227 direction: new Vector3(),
18228 color: new Color(),
18238 position: new Vector3(),
18239 color: new Color(),
18245 case 'HemisphereLight':
18247 direction: new Vector3(),
18248 skyColor: new Color(),
18249 groundColor: new Color()
18253 case 'RectAreaLight':
18255 color: new Color(),
18256 position: new Vector3(),
18257 halfWidth: new Vector3(),
18258 halfHeight: new Vector3()
18264 lights[ light.id ] = uniforms;
18274 function ShadowUniformsCache() {
18280 get: function ( light ) {
18282 if ( lights[ light.id ] !== undefined ) {
18284 return lights[ light.id ];
18290 switch ( light.type ) {
18292 case 'DirectionalLight':
18295 shadowNormalBias: 0,
18297 shadowMapSize: new Vector2()
18304 shadowNormalBias: 0,
18306 shadowMapSize: new Vector2()
18313 shadowNormalBias: 0,
18315 shadowMapSize: new Vector2(),
18316 shadowCameraNear: 1,
18317 shadowCameraFar: 1000
18321 // TODO (abelnation): set RectAreaLight shadow uniforms
18325 lights[ light.id ] = uniforms;
18337 let nextVersion = 0;
18339 function shadowCastingLightsFirst( lightA, lightB ) {
18341 return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
18345 function WebGLLights( extensions, capabilities ) {
18347 const cache = new UniformsCache();
18349 const shadowCache = ShadowUniformsCache();
18356 directionalLength: - 1,
18359 rectAreaLength: - 1,
18362 numDirectionalShadows: - 1,
18363 numPointShadows: - 1,
18364 numSpotShadows: - 1
18367 ambient: [ 0, 0, 0 ],
18370 directionalShadow: [],
18371 directionalShadowMap: [],
18372 directionalShadowMatrix: [],
18376 spotShadowMatrix: [],
18378 rectAreaLTC1: null,
18379 rectAreaLTC2: null,
18382 pointShadowMap: [],
18383 pointShadowMatrix: [],
18388 for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
18390 const vector3 = new Vector3();
18391 const matrix4 = new Matrix4();
18392 const matrix42 = new Matrix4();
18394 function setup( lights, shadows, camera ) {
18396 let r = 0, g = 0, b = 0;
18398 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
18400 let directionalLength = 0;
18401 let pointLength = 0;
18402 let spotLength = 0;
18403 let rectAreaLength = 0;
18404 let hemiLength = 0;
18406 let numDirectionalShadows = 0;
18407 let numPointShadows = 0;
18408 let numSpotShadows = 0;
18410 const viewMatrix = camera.matrixWorldInverse;
18412 lights.sort( shadowCastingLightsFirst );
18414 for ( let i = 0, l = lights.length; i < l; i ++ ) {
18416 const light = lights[ i ];
18418 const color = light.color;
18419 const intensity = light.intensity;
18420 const distance = light.distance;
18422 const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
18424 if ( light.isAmbientLight ) {
18426 r += color.r * intensity;
18427 g += color.g * intensity;
18428 b += color.b * intensity;
18430 } else if ( light.isLightProbe ) {
18432 for ( let j = 0; j < 9; j ++ ) {
18434 state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
18438 } else if ( light.isDirectionalLight ) {
18440 const uniforms = cache.get( light );
18442 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18443 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18444 vector3.setFromMatrixPosition( light.target.matrixWorld );
18445 uniforms.direction.sub( vector3 );
18446 uniforms.direction.transformDirection( viewMatrix );
18448 if ( light.castShadow ) {
18450 const shadow = light.shadow;
18452 const shadowUniforms = shadowCache.get( light );
18454 shadowUniforms.shadowBias = shadow.bias;
18455 shadowUniforms.shadowNormalBias = shadow.normalBias;
18456 shadowUniforms.shadowRadius = shadow.radius;
18457 shadowUniforms.shadowMapSize = shadow.mapSize;
18459 state.directionalShadow[ directionalLength ] = shadowUniforms;
18460 state.directionalShadowMap[ directionalLength ] = shadowMap;
18461 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
18463 numDirectionalShadows ++;
18467 state.directional[ directionalLength ] = uniforms;
18469 directionalLength ++;
18471 } else if ( light.isSpotLight ) {
18473 const uniforms = cache.get( light );
18475 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18476 uniforms.position.applyMatrix4( viewMatrix );
18478 uniforms.color.copy( color ).multiplyScalar( intensity );
18479 uniforms.distance = distance;
18481 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18482 vector3.setFromMatrixPosition( light.target.matrixWorld );
18483 uniforms.direction.sub( vector3 );
18484 uniforms.direction.transformDirection( viewMatrix );
18486 uniforms.coneCos = Math.cos( light.angle );
18487 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
18488 uniforms.decay = light.decay;
18490 if ( light.castShadow ) {
18492 const shadow = light.shadow;
18494 const shadowUniforms = shadowCache.get( light );
18496 shadowUniforms.shadowBias = shadow.bias;
18497 shadowUniforms.shadowNormalBias = shadow.normalBias;
18498 shadowUniforms.shadowRadius = shadow.radius;
18499 shadowUniforms.shadowMapSize = shadow.mapSize;
18501 state.spotShadow[ spotLength ] = shadowUniforms;
18502 state.spotShadowMap[ spotLength ] = shadowMap;
18503 state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
18509 state.spot[ spotLength ] = uniforms;
18513 } else if ( light.isRectAreaLight ) {
18515 const uniforms = cache.get( light );
18517 // (a) intensity is the total visible light emitted
18518 //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
18520 // (b) intensity is the brightness of the light
18521 uniforms.color.copy( color ).multiplyScalar( intensity );
18523 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18524 uniforms.position.applyMatrix4( viewMatrix );
18526 // extract local rotation of light to derive width/height half vectors
18527 matrix42.identity();
18528 matrix4.copy( light.matrixWorld );
18529 matrix4.premultiply( viewMatrix );
18530 matrix42.extractRotation( matrix4 );
18532 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
18533 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
18535 uniforms.halfWidth.applyMatrix4( matrix42 );
18536 uniforms.halfHeight.applyMatrix4( matrix42 );
18538 // TODO (abelnation): RectAreaLight distance?
18539 // uniforms.distance = distance;
18541 state.rectArea[ rectAreaLength ] = uniforms;
18545 } else if ( light.isPointLight ) {
18547 const uniforms = cache.get( light );
18549 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18550 uniforms.position.applyMatrix4( viewMatrix );
18552 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18553 uniforms.distance = light.distance;
18554 uniforms.decay = light.decay;
18556 if ( light.castShadow ) {
18558 const shadow = light.shadow;
18560 const shadowUniforms = shadowCache.get( light );
18562 shadowUniforms.shadowBias = shadow.bias;
18563 shadowUniforms.shadowNormalBias = shadow.normalBias;
18564 shadowUniforms.shadowRadius = shadow.radius;
18565 shadowUniforms.shadowMapSize = shadow.mapSize;
18566 shadowUniforms.shadowCameraNear = shadow.camera.near;
18567 shadowUniforms.shadowCameraFar = shadow.camera.far;
18569 state.pointShadow[ pointLength ] = shadowUniforms;
18570 state.pointShadowMap[ pointLength ] = shadowMap;
18571 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
18573 numPointShadows ++;
18577 state.point[ pointLength ] = uniforms;
18581 } else if ( light.isHemisphereLight ) {
18583 const uniforms = cache.get( light );
18585 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18586 uniforms.direction.transformDirection( viewMatrix );
18587 uniforms.direction.normalize();
18589 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
18590 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
18592 state.hemi[ hemiLength ] = uniforms;
18600 if ( rectAreaLength > 0 ) {
18602 if ( capabilities.isWebGL2 ) {
18606 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
18607 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
18613 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
18615 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
18616 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
18618 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
18620 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
18621 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
18625 console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
18633 state.ambient[ 0 ] = r;
18634 state.ambient[ 1 ] = g;
18635 state.ambient[ 2 ] = b;
18637 const hash = state.hash;
18639 if ( hash.directionalLength !== directionalLength ||
18640 hash.pointLength !== pointLength ||
18641 hash.spotLength !== spotLength ||
18642 hash.rectAreaLength !== rectAreaLength ||
18643 hash.hemiLength !== hemiLength ||
18644 hash.numDirectionalShadows !== numDirectionalShadows ||
18645 hash.numPointShadows !== numPointShadows ||
18646 hash.numSpotShadows !== numSpotShadows ) {
18648 state.directional.length = directionalLength;
18649 state.spot.length = spotLength;
18650 state.rectArea.length = rectAreaLength;
18651 state.point.length = pointLength;
18652 state.hemi.length = hemiLength;
18654 state.directionalShadow.length = numDirectionalShadows;
18655 state.directionalShadowMap.length = numDirectionalShadows;
18656 state.pointShadow.length = numPointShadows;
18657 state.pointShadowMap.length = numPointShadows;
18658 state.spotShadow.length = numSpotShadows;
18659 state.spotShadowMap.length = numSpotShadows;
18660 state.directionalShadowMatrix.length = numDirectionalShadows;
18661 state.pointShadowMatrix.length = numPointShadows;
18662 state.spotShadowMatrix.length = numSpotShadows;
18664 hash.directionalLength = directionalLength;
18665 hash.pointLength = pointLength;
18666 hash.spotLength = spotLength;
18667 hash.rectAreaLength = rectAreaLength;
18668 hash.hemiLength = hemiLength;
18670 hash.numDirectionalShadows = numDirectionalShadows;
18671 hash.numPointShadows = numPointShadows;
18672 hash.numSpotShadows = numSpotShadows;
18674 state.version = nextVersion ++;
18687 function WebGLRenderState( extensions, capabilities ) {
18689 const lights = new WebGLLights( extensions, capabilities );
18691 const lightsArray = [];
18692 const shadowsArray = [];
18696 lightsArray.length = 0;
18697 shadowsArray.length = 0;
18701 function pushLight( light ) {
18703 lightsArray.push( light );
18707 function pushShadow( shadowLight ) {
18709 shadowsArray.push( shadowLight );
18713 function setupLights( camera ) {
18715 lights.setup( lightsArray, shadowsArray, camera );
18720 lightsArray: lightsArray,
18721 shadowsArray: shadowsArray,
18729 setupLights: setupLights,
18731 pushLight: pushLight,
18732 pushShadow: pushShadow
18737 function WebGLRenderStates( extensions, capabilities ) {
18739 let renderStates = new WeakMap();
18741 function get( scene, camera ) {
18745 if ( renderStates.has( scene ) === false ) {
18747 renderState = new WebGLRenderState( extensions, capabilities );
18748 renderStates.set( scene, new WeakMap() );
18749 renderStates.get( scene ).set( camera, renderState );
18753 if ( renderStates.get( scene ).has( camera ) === false ) {
18755 renderState = new WebGLRenderState( extensions, capabilities );
18756 renderStates.get( scene ).set( camera, renderState );
18760 renderState = renderStates.get( scene ).get( camera );
18766 return renderState;
18770 function dispose() {
18772 renderStates = new WeakMap();
18786 * opacity: <float>,
18788 * map: new THREE.Texture( <Image> ),
18790 * alphaMap: new THREE.Texture( <Image> ),
18792 * displacementMap: new THREE.Texture( <Image> ),
18793 * displacementScale: <float>,
18794 * displacementBias: <float>,
18796 * wireframe: <boolean>,
18797 * wireframeLinewidth: <float>
18801 function MeshDepthMaterial( parameters ) {
18803 Material.call( this );
18805 this.type = 'MeshDepthMaterial';
18807 this.depthPacking = BasicDepthPacking;
18809 this.skinning = false;
18810 this.morphTargets = false;
18814 this.alphaMap = null;
18816 this.displacementMap = null;
18817 this.displacementScale = 1;
18818 this.displacementBias = 0;
18820 this.wireframe = false;
18821 this.wireframeLinewidth = 1;
18825 this.setValues( parameters );
18829 MeshDepthMaterial.prototype = Object.create( Material.prototype );
18830 MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
18832 MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
18834 MeshDepthMaterial.prototype.copy = function ( source ) {
18836 Material.prototype.copy.call( this, source );
18838 this.depthPacking = source.depthPacking;
18840 this.skinning = source.skinning;
18841 this.morphTargets = source.morphTargets;
18843 this.map = source.map;
18845 this.alphaMap = source.alphaMap;
18847 this.displacementMap = source.displacementMap;
18848 this.displacementScale = source.displacementScale;
18849 this.displacementBias = source.displacementBias;
18851 this.wireframe = source.wireframe;
18852 this.wireframeLinewidth = source.wireframeLinewidth;
18861 * referencePosition: <float>,
18862 * nearDistance: <float>,
18863 * farDistance: <float>,
18865 * skinning: <bool>,
18866 * morphTargets: <bool>,
18868 * map: new THREE.Texture( <Image> ),
18870 * alphaMap: new THREE.Texture( <Image> ),
18872 * displacementMap: new THREE.Texture( <Image> ),
18873 * displacementScale: <float>,
18874 * displacementBias: <float>
18879 function MeshDistanceMaterial( parameters ) {
18881 Material.call( this );
18883 this.type = 'MeshDistanceMaterial';
18885 this.referencePosition = new Vector3();
18886 this.nearDistance = 1;
18887 this.farDistance = 1000;
18889 this.skinning = false;
18890 this.morphTargets = false;
18894 this.alphaMap = null;
18896 this.displacementMap = null;
18897 this.displacementScale = 1;
18898 this.displacementBias = 0;
18902 this.setValues( parameters );
18906 MeshDistanceMaterial.prototype = Object.create( Material.prototype );
18907 MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
18909 MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
18911 MeshDistanceMaterial.prototype.copy = function ( source ) {
18913 Material.prototype.copy.call( this, source );
18915 this.referencePosition.copy( source.referencePosition );
18916 this.nearDistance = source.nearDistance;
18917 this.farDistance = source.farDistance;
18919 this.skinning = source.skinning;
18920 this.morphTargets = source.morphTargets;
18922 this.map = source.map;
18924 this.alphaMap = source.alphaMap;
18926 this.displacementMap = source.displacementMap;
18927 this.displacementScale = source.displacementScale;
18928 this.displacementBias = source.displacementBias;
18934 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 HORIZONAL_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}";
18936 var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
18938 function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
18940 let _frustum = new Frustum();
18942 const _shadowMapSize = new Vector2(),
18943 _viewportSize = new Vector2(),
18945 _viewport = new Vector4(),
18947 _depthMaterials = [],
18948 _distanceMaterials = [],
18950 _materialCache = {};
18952 const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
18954 const shadowMaterialVertical = new ShaderMaterial( {
18957 SAMPLE_RATE: 2.0 / 8.0,
18958 HALF_SAMPLE_RATE: 1.0 / 8.0
18962 shadow_pass: { value: null },
18963 resolution: { value: new Vector2() },
18964 radius: { value: 4.0 }
18967 vertexShader: vsm_vert,
18969 fragmentShader: vsm_frag
18973 const shadowMaterialHorizonal = shadowMaterialVertical.clone();
18974 shadowMaterialHorizonal.defines.HORIZONAL_PASS = 1;
18976 const fullScreenTri = new BufferGeometry();
18977 fullScreenTri.setAttribute(
18979 new BufferAttribute(
18980 new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
18985 const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
18987 const scope = this;
18989 this.enabled = false;
18991 this.autoUpdate = true;
18992 this.needsUpdate = false;
18994 this.type = PCFShadowMap;
18996 this.render = function ( lights, scene, camera ) {
18998 if ( scope.enabled === false ) return;
18999 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
19001 if ( lights.length === 0 ) return;
19003 const currentRenderTarget = _renderer.getRenderTarget();
19004 const activeCubeFace = _renderer.getActiveCubeFace();
19005 const activeMipmapLevel = _renderer.getActiveMipmapLevel();
19007 const _state = _renderer.state;
19009 // Set GL state for depth map.
19010 _state.setBlending( NoBlending );
19011 _state.buffers.color.setClear( 1, 1, 1, 1 );
19012 _state.buffers.depth.setTest( true );
19013 _state.setScissorTest( false );
19015 // render depth map
19017 for ( let i = 0, il = lights.length; i < il; i ++ ) {
19019 const light = lights[ i ];
19020 const shadow = light.shadow;
19022 if ( shadow === undefined ) {
19024 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
19029 if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
19031 _shadowMapSize.copy( shadow.mapSize );
19033 const shadowFrameExtents = shadow.getFrameExtents();
19035 _shadowMapSize.multiply( shadowFrameExtents );
19037 _viewportSize.copy( shadow.mapSize );
19039 if ( _shadowMapSize.x > maxTextureSize || _shadowMapSize.y > maxTextureSize ) {
19041 if ( _shadowMapSize.x > maxTextureSize ) {
19043 _viewportSize.x = Math.floor( maxTextureSize / shadowFrameExtents.x );
19044 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
19045 shadow.mapSize.x = _viewportSize.x;
19049 if ( _shadowMapSize.y > maxTextureSize ) {
19051 _viewportSize.y = Math.floor( maxTextureSize / shadowFrameExtents.y );
19052 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
19053 shadow.mapSize.y = _viewportSize.y;
19059 if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
19061 const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
19063 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
19064 shadow.map.texture.name = light.name + ".shadowMap";
19066 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
19068 shadow.camera.updateProjectionMatrix();
19072 if ( shadow.map === null ) {
19074 const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
19076 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
19077 shadow.map.texture.name = light.name + ".shadowMap";
19079 shadow.camera.updateProjectionMatrix();
19083 _renderer.setRenderTarget( shadow.map );
19086 const viewportCount = shadow.getViewportCount();
19088 for ( let vp = 0; vp < viewportCount; vp ++ ) {
19090 const viewport = shadow.getViewport( vp );
19093 _viewportSize.x * viewport.x,
19094 _viewportSize.y * viewport.y,
19095 _viewportSize.x * viewport.z,
19096 _viewportSize.y * viewport.w
19099 _state.viewport( _viewport );
19101 shadow.updateMatrices( light, vp );
19103 _frustum = shadow.getFrustum();
19105 renderObject( scene, camera, shadow.camera, light, this.type );
19109 // do blur pass for VSM
19111 if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
19113 VSMPass( shadow, camera );
19117 shadow.needsUpdate = false;
19121 scope.needsUpdate = false;
19123 _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
19127 function VSMPass( shadow, camera ) {
19129 const geometry = _objects.update( fullScreenMesh );
19133 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
19134 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
19135 shadowMaterialVertical.uniforms.radius.value = shadow.radius;
19136 _renderer.setRenderTarget( shadow.mapPass );
19138 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
19142 shadowMaterialHorizonal.uniforms.shadow_pass.value = shadow.mapPass.texture;
19143 shadowMaterialHorizonal.uniforms.resolution.value = shadow.mapSize;
19144 shadowMaterialHorizonal.uniforms.radius.value = shadow.radius;
19145 _renderer.setRenderTarget( shadow.map );
19147 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizonal, fullScreenMesh, null );
19151 function getDepthMaterialVariant( useMorphing, useSkinning, useInstancing ) {
19153 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
19155 let material = _depthMaterials[ index ];
19157 if ( material === undefined ) {
19159 material = new MeshDepthMaterial( {
19161 depthPacking: RGBADepthPacking,
19163 morphTargets: useMorphing,
19164 skinning: useSkinning
19168 _depthMaterials[ index ] = material;
19176 function getDistanceMaterialVariant( useMorphing, useSkinning, useInstancing ) {
19178 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
19180 let material = _distanceMaterials[ index ];
19182 if ( material === undefined ) {
19184 material = new MeshDistanceMaterial( {
19186 morphTargets: useMorphing,
19187 skinning: useSkinning
19191 _distanceMaterials[ index ] = material;
19199 function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) {
19203 let getMaterialVariant = getDepthMaterialVariant;
19204 let customMaterial = object.customDepthMaterial;
19206 if ( light.isPointLight === true ) {
19208 getMaterialVariant = getDistanceMaterialVariant;
19209 customMaterial = object.customDistanceMaterial;
19213 if ( customMaterial === undefined ) {
19215 let useMorphing = false;
19217 if ( material.morphTargets === true ) {
19219 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
19223 let useSkinning = false;
19225 if ( object.isSkinnedMesh === true ) {
19227 if ( material.skinning === true ) {
19229 useSkinning = true;
19233 console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
19239 const useInstancing = object.isInstancedMesh === true;
19241 result = getMaterialVariant( useMorphing, useSkinning, useInstancing );
19245 result = customMaterial;
19249 if ( _renderer.localClippingEnabled &&
19250 material.clipShadows === true &&
19251 material.clippingPlanes.length !== 0 ) {
19253 // in this case we need a unique material instance reflecting the
19254 // appropriate state
19256 const keyA = result.uuid, keyB = material.uuid;
19258 let materialsForVariant = _materialCache[ keyA ];
19260 if ( materialsForVariant === undefined ) {
19262 materialsForVariant = {};
19263 _materialCache[ keyA ] = materialsForVariant;
19267 let cachedMaterial = materialsForVariant[ keyB ];
19269 if ( cachedMaterial === undefined ) {
19271 cachedMaterial = result.clone();
19272 materialsForVariant[ keyB ] = cachedMaterial;
19276 result = cachedMaterial;
19280 result.visible = material.visible;
19281 result.wireframe = material.wireframe;
19283 if ( type === VSMShadowMap ) {
19285 result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
19289 result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
19293 result.clipShadows = material.clipShadows;
19294 result.clippingPlanes = material.clippingPlanes;
19295 result.clipIntersection = material.clipIntersection;
19297 result.wireframeLinewidth = material.wireframeLinewidth;
19298 result.linewidth = material.linewidth;
19300 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
19302 result.referencePosition.setFromMatrixPosition( light.matrixWorld );
19303 result.nearDistance = shadowCameraNear;
19304 result.farDistance = shadowCameraFar;
19312 function renderObject( object, camera, shadowCamera, light, type ) {
19314 if ( object.visible === false ) return;
19316 const visible = object.layers.test( camera.layers );
19318 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
19320 if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
19322 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
19324 const geometry = _objects.update( object );
19325 const material = object.material;
19327 if ( Array.isArray( material ) ) {
19329 const groups = geometry.groups;
19331 for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
19333 const group = groups[ k ];
19334 const groupMaterial = material[ group.materialIndex ];
19336 if ( groupMaterial && groupMaterial.visible ) {
19338 const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type );
19340 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
19346 } else if ( material.visible ) {
19348 const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type );
19350 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
19358 const children = object.children;
19360 for ( let i = 0, l = children.length; i < l; i ++ ) {
19362 renderObject( children[ i ], camera, shadowCamera, light, type );
19370 function WebGLState( gl, extensions, capabilities ) {
19372 const isWebGL2 = capabilities.isWebGL2;
19374 function ColorBuffer() {
19376 let locked = false;
19378 const color = new Vector4();
19379 let currentColorMask = null;
19380 const currentColorClear = new Vector4( 0, 0, 0, 0 );
19384 setMask: function ( colorMask ) {
19386 if ( currentColorMask !== colorMask && ! locked ) {
19388 gl.colorMask( colorMask, colorMask, colorMask, colorMask );
19389 currentColorMask = colorMask;
19395 setLocked: function ( lock ) {
19401 setClear: function ( r, g, b, a, premultipliedAlpha ) {
19403 if ( premultipliedAlpha === true ) {
19405 r *= a; g *= a; b *= a;
19409 color.set( r, g, b, a );
19411 if ( currentColorClear.equals( color ) === false ) {
19413 gl.clearColor( r, g, b, a );
19414 currentColorClear.copy( color );
19420 reset: function () {
19424 currentColorMask = null;
19425 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
19433 function DepthBuffer() {
19435 let locked = false;
19437 let currentDepthMask = null;
19438 let currentDepthFunc = null;
19439 let currentDepthClear = null;
19443 setTest: function ( depthTest ) {
19457 setMask: function ( depthMask ) {
19459 if ( currentDepthMask !== depthMask && ! locked ) {
19461 gl.depthMask( depthMask );
19462 currentDepthMask = depthMask;
19468 setFunc: function ( depthFunc ) {
19470 if ( currentDepthFunc !== depthFunc ) {
19474 switch ( depthFunc ) {
19478 gl.depthFunc( 512 );
19483 gl.depthFunc( 519 );
19488 gl.depthFunc( 513 );
19491 case LessEqualDepth:
19493 gl.depthFunc( 515 );
19498 gl.depthFunc( 514 );
19501 case GreaterEqualDepth:
19503 gl.depthFunc( 518 );
19508 gl.depthFunc( 516 );
19511 case NotEqualDepth:
19513 gl.depthFunc( 517 );
19518 gl.depthFunc( 515 );
19524 gl.depthFunc( 515 );
19528 currentDepthFunc = depthFunc;
19534 setLocked: function ( lock ) {
19540 setClear: function ( depth ) {
19542 if ( currentDepthClear !== depth ) {
19544 gl.clearDepth( depth );
19545 currentDepthClear = depth;
19551 reset: function () {
19555 currentDepthMask = null;
19556 currentDepthFunc = null;
19557 currentDepthClear = null;
19565 function StencilBuffer() {
19567 let locked = false;
19569 let currentStencilMask = null;
19570 let currentStencilFunc = null;
19571 let currentStencilRef = null;
19572 let currentStencilFuncMask = null;
19573 let currentStencilFail = null;
19574 let currentStencilZFail = null;
19575 let currentStencilZPass = null;
19576 let currentStencilClear = null;
19580 setTest: function ( stencilTest ) {
19584 if ( stencilTest ) {
19598 setMask: function ( stencilMask ) {
19600 if ( currentStencilMask !== stencilMask && ! locked ) {
19602 gl.stencilMask( stencilMask );
19603 currentStencilMask = stencilMask;
19609 setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
19611 if ( currentStencilFunc !== stencilFunc ||
19612 currentStencilRef !== stencilRef ||
19613 currentStencilFuncMask !== stencilMask ) {
19615 gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
19617 currentStencilFunc = stencilFunc;
19618 currentStencilRef = stencilRef;
19619 currentStencilFuncMask = stencilMask;
19625 setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
19627 if ( currentStencilFail !== stencilFail ||
19628 currentStencilZFail !== stencilZFail ||
19629 currentStencilZPass !== stencilZPass ) {
19631 gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
19633 currentStencilFail = stencilFail;
19634 currentStencilZFail = stencilZFail;
19635 currentStencilZPass = stencilZPass;
19641 setLocked: function ( lock ) {
19647 setClear: function ( stencil ) {
19649 if ( currentStencilClear !== stencil ) {
19651 gl.clearStencil( stencil );
19652 currentStencilClear = stencil;
19658 reset: function () {
19662 currentStencilMask = null;
19663 currentStencilFunc = null;
19664 currentStencilRef = null;
19665 currentStencilFuncMask = null;
19666 currentStencilFail = null;
19667 currentStencilZFail = null;
19668 currentStencilZPass = null;
19669 currentStencilClear = null;
19679 const colorBuffer = new ColorBuffer();
19680 const depthBuffer = new DepthBuffer();
19681 const stencilBuffer = new StencilBuffer();
19683 let enabledCapabilities = {};
19685 let currentProgram = null;
19687 let currentBlendingEnabled = null;
19688 let currentBlending = null;
19689 let currentBlendEquation = null;
19690 let currentBlendSrc = null;
19691 let currentBlendDst = null;
19692 let currentBlendEquationAlpha = null;
19693 let currentBlendSrcAlpha = null;
19694 let currentBlendDstAlpha = null;
19695 let currentPremultipledAlpha = false;
19697 let currentFlipSided = null;
19698 let currentCullFace = null;
19700 let currentLineWidth = null;
19702 let currentPolygonOffsetFactor = null;
19703 let currentPolygonOffsetUnits = null;
19705 const maxTextures = gl.getParameter( 35661 );
19707 let lineWidthAvailable = false;
19709 const glVersion = gl.getParameter( 7938 );
19711 if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
19713 version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] );
19714 lineWidthAvailable = ( version >= 1.0 );
19716 } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
19718 version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] );
19719 lineWidthAvailable = ( version >= 2.0 );
19723 let currentTextureSlot = null;
19724 let currentBoundTextures = {};
19726 const currentScissor = new Vector4();
19727 const currentViewport = new Vector4();
19729 function createTexture( type, target, count ) {
19731 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
19732 const texture = gl.createTexture();
19734 gl.bindTexture( type, texture );
19735 gl.texParameteri( type, 10241, 9728 );
19736 gl.texParameteri( type, 10240, 9728 );
19738 for ( let i = 0; i < count; i ++ ) {
19740 gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data );
19748 const emptyTextures = {};
19749 emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 );
19750 emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 );
19754 colorBuffer.setClear( 0, 0, 0, 1 );
19755 depthBuffer.setClear( 1 );
19756 stencilBuffer.setClear( 0 );
19759 depthBuffer.setFunc( LessEqualDepth );
19761 setFlipSided( false );
19762 setCullFace( CullFaceBack );
19765 setBlending( NoBlending );
19769 function enable( id ) {
19771 if ( enabledCapabilities[ id ] !== true ) {
19774 enabledCapabilities[ id ] = true;
19780 function disable( id ) {
19782 if ( enabledCapabilities[ id ] !== false ) {
19785 enabledCapabilities[ id ] = false;
19791 function useProgram( program ) {
19793 if ( currentProgram !== program ) {
19795 gl.useProgram( program );
19797 currentProgram = program;
19807 const equationToGL = {
19808 [ AddEquation ]: 32774,
19809 [ SubtractEquation ]: 32778,
19810 [ ReverseSubtractEquation ]: 32779
19815 equationToGL[ MinEquation ] = 32775;
19816 equationToGL[ MaxEquation ] = 32776;
19820 const extension = extensions.get( 'EXT_blend_minmax' );
19822 if ( extension !== null ) {
19824 equationToGL[ MinEquation ] = extension.MIN_EXT;
19825 equationToGL[ MaxEquation ] = extension.MAX_EXT;
19831 const factorToGL = {
19834 [ SrcColorFactor ]: 768,
19835 [ SrcAlphaFactor ]: 770,
19836 [ SrcAlphaSaturateFactor ]: 776,
19837 [ DstColorFactor ]: 774,
19838 [ DstAlphaFactor ]: 772,
19839 [ OneMinusSrcColorFactor ]: 769,
19840 [ OneMinusSrcAlphaFactor ]: 771,
19841 [ OneMinusDstColorFactor ]: 775,
19842 [ OneMinusDstAlphaFactor ]: 773
19845 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
19847 if ( blending === NoBlending ) {
19849 if ( currentBlendingEnabled ) {
19852 currentBlendingEnabled = false;
19860 if ( ! currentBlendingEnabled ) {
19863 currentBlendingEnabled = true;
19867 if ( blending !== CustomBlending ) {
19869 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
19871 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
19873 gl.blendEquation( 32774 );
19875 currentBlendEquation = AddEquation;
19876 currentBlendEquationAlpha = AddEquation;
19880 if ( premultipliedAlpha ) {
19882 switch ( blending ) {
19884 case NormalBlending:
19885 gl.blendFuncSeparate( 1, 771, 1, 771 );
19888 case AdditiveBlending:
19889 gl.blendFunc( 1, 1 );
19892 case SubtractiveBlending:
19893 gl.blendFuncSeparate( 0, 0, 769, 771 );
19896 case MultiplyBlending:
19897 gl.blendFuncSeparate( 0, 768, 0, 770 );
19901 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
19908 switch ( blending ) {
19910 case NormalBlending:
19911 gl.blendFuncSeparate( 770, 771, 1, 771 );
19914 case AdditiveBlending:
19915 gl.blendFunc( 770, 1 );
19918 case SubtractiveBlending:
19919 gl.blendFunc( 0, 769 );
19922 case MultiplyBlending:
19923 gl.blendFunc( 0, 768 );
19927 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
19934 currentBlendSrc = null;
19935 currentBlendDst = null;
19936 currentBlendSrcAlpha = null;
19937 currentBlendDstAlpha = null;
19939 currentBlending = blending;
19940 currentPremultipledAlpha = premultipliedAlpha;
19950 blendEquationAlpha = blendEquationAlpha || blendEquation;
19951 blendSrcAlpha = blendSrcAlpha || blendSrc;
19952 blendDstAlpha = blendDstAlpha || blendDst;
19954 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
19956 gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
19958 currentBlendEquation = blendEquation;
19959 currentBlendEquationAlpha = blendEquationAlpha;
19963 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
19965 gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
19967 currentBlendSrc = blendSrc;
19968 currentBlendDst = blendDst;
19969 currentBlendSrcAlpha = blendSrcAlpha;
19970 currentBlendDstAlpha = blendDstAlpha;
19974 currentBlending = blending;
19975 currentPremultipledAlpha = null;
19979 function setMaterial( material, frontFaceCW ) {
19981 material.side === DoubleSide
19985 let flipSided = ( material.side === BackSide );
19986 if ( frontFaceCW ) flipSided = ! flipSided;
19988 setFlipSided( flipSided );
19990 ( material.blending === NormalBlending && material.transparent === false )
19991 ? setBlending( NoBlending )
19992 : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
19994 depthBuffer.setFunc( material.depthFunc );
19995 depthBuffer.setTest( material.depthTest );
19996 depthBuffer.setMask( material.depthWrite );
19997 colorBuffer.setMask( material.colorWrite );
19999 const stencilWrite = material.stencilWrite;
20000 stencilBuffer.setTest( stencilWrite );
20001 if ( stencilWrite ) {
20003 stencilBuffer.setMask( material.stencilWriteMask );
20004 stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
20005 stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
20009 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
20015 function setFlipSided( flipSided ) {
20017 if ( currentFlipSided !== flipSided ) {
20021 gl.frontFace( 2304 );
20025 gl.frontFace( 2305 );
20029 currentFlipSided = flipSided;
20035 function setCullFace( cullFace ) {
20037 if ( cullFace !== CullFaceNone ) {
20041 if ( cullFace !== currentCullFace ) {
20043 if ( cullFace === CullFaceBack ) {
20045 gl.cullFace( 1029 );
20047 } else if ( cullFace === CullFaceFront ) {
20049 gl.cullFace( 1028 );
20053 gl.cullFace( 1032 );
20065 currentCullFace = cullFace;
20069 function setLineWidth( width ) {
20071 if ( width !== currentLineWidth ) {
20073 if ( lineWidthAvailable ) gl.lineWidth( width );
20075 currentLineWidth = width;
20081 function setPolygonOffset( polygonOffset, factor, units ) {
20083 if ( polygonOffset ) {
20087 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
20089 gl.polygonOffset( factor, units );
20091 currentPolygonOffsetFactor = factor;
20092 currentPolygonOffsetUnits = units;
20104 function setScissorTest( scissorTest ) {
20106 if ( scissorTest ) {
20120 function activeTexture( webglSlot ) {
20122 if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1;
20124 if ( currentTextureSlot !== webglSlot ) {
20126 gl.activeTexture( webglSlot );
20127 currentTextureSlot = webglSlot;
20133 function bindTexture( webglType, webglTexture ) {
20135 if ( currentTextureSlot === null ) {
20141 let boundTexture = currentBoundTextures[ currentTextureSlot ];
20143 if ( boundTexture === undefined ) {
20145 boundTexture = { type: undefined, texture: undefined };
20146 currentBoundTextures[ currentTextureSlot ] = boundTexture;
20150 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
20152 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
20154 boundTexture.type = webglType;
20155 boundTexture.texture = webglTexture;
20161 function unbindTexture() {
20163 const boundTexture = currentBoundTextures[ currentTextureSlot ];
20165 if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
20167 gl.bindTexture( boundTexture.type, null );
20169 boundTexture.type = undefined;
20170 boundTexture.texture = undefined;
20176 function compressedTexImage2D() {
20180 gl.compressedTexImage2D.apply( gl, arguments );
20182 } catch ( error ) {
20184 console.error( 'THREE.WebGLState:', error );
20190 function texImage2D() {
20194 gl.texImage2D.apply( gl, arguments );
20196 } catch ( error ) {
20198 console.error( 'THREE.WebGLState:', error );
20204 function texImage3D() {
20208 gl.texImage3D.apply( gl, arguments );
20210 } catch ( error ) {
20212 console.error( 'THREE.WebGLState:', error );
20220 function scissor( scissor ) {
20222 if ( currentScissor.equals( scissor ) === false ) {
20224 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
20225 currentScissor.copy( scissor );
20231 function viewport( viewport ) {
20233 if ( currentViewport.equals( viewport ) === false ) {
20235 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
20236 currentViewport.copy( viewport );
20246 enabledCapabilities = {};
20248 currentTextureSlot = null;
20249 currentBoundTextures = {};
20251 currentProgram = null;
20253 currentBlendingEnabled = null;
20254 currentBlending = null;
20255 currentBlendEquation = null;
20256 currentBlendSrc = null;
20257 currentBlendDst = null;
20258 currentBlendEquationAlpha = null;
20259 currentBlendSrcAlpha = null;
20260 currentBlendDstAlpha = null;
20261 currentPremultipledAlpha = false;
20263 currentFlipSided = null;
20264 currentCullFace = null;
20266 currentLineWidth = null;
20268 currentPolygonOffsetFactor = null;
20269 currentPolygonOffsetUnits = null;
20271 colorBuffer.reset();
20272 depthBuffer.reset();
20273 stencilBuffer.reset();
20280 color: colorBuffer,
20281 depth: depthBuffer,
20282 stencil: stencilBuffer
20288 useProgram: useProgram,
20290 setBlending: setBlending,
20291 setMaterial: setMaterial,
20293 setFlipSided: setFlipSided,
20294 setCullFace: setCullFace,
20296 setLineWidth: setLineWidth,
20297 setPolygonOffset: setPolygonOffset,
20299 setScissorTest: setScissorTest,
20301 activeTexture: activeTexture,
20302 bindTexture: bindTexture,
20303 unbindTexture: unbindTexture,
20304 compressedTexImage2D: compressedTexImage2D,
20305 texImage2D: texImage2D,
20306 texImage3D: texImage3D,
20309 viewport: viewport,
20317 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
20319 const isWebGL2 = capabilities.isWebGL2;
20320 const maxTextures = capabilities.maxTextures;
20321 const maxCubemapSize = capabilities.maxCubemapSize;
20322 const maxTextureSize = capabilities.maxTextureSize;
20323 const maxSamples = capabilities.maxSamples;
20325 const _videoTextures = new WeakMap();
20328 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
20329 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
20330 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
20332 let useOffscreenCanvas = false;
20336 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
20337 && ( new OffscreenCanvas( 1, 1 ).getContext( "2d" ) ) !== null;
20341 // Ignore any errors
20345 function createCanvas( width, height ) {
20347 // Use OffscreenCanvas when available. Specially needed in web workers
20349 return useOffscreenCanvas ?
20350 new OffscreenCanvas( width, height ) :
20351 document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
20355 function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
20359 // handle case if texture exceeds max size
20361 if ( image.width > maxSize || image.height > maxSize ) {
20363 scale = maxSize / Math.max( image.width, image.height );
20367 // only perform resize if necessary
20369 if ( scale < 1 || needsPowerOfTwo === true ) {
20371 // only perform resize for certain image types
20373 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
20374 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
20375 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
20377 const floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor;
20379 const width = floor( scale * image.width );
20380 const height = floor( scale * image.height );
20382 if ( _canvas === undefined ) _canvas = createCanvas( width, height );
20384 // cube textures can't reuse the same canvas
20386 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
20388 canvas.width = width;
20389 canvas.height = height;
20391 const context = canvas.getContext( '2d' );
20392 context.drawImage( image, 0, 0, width, height );
20394 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
20400 if ( 'data' in image ) {
20402 console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
20416 function isPowerOfTwo( image ) {
20418 return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height );
20422 function textureNeedsPowerOfTwo( texture ) {
20424 if ( isWebGL2 ) return false;
20426 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
20427 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
20431 function textureNeedsGenerateMipmaps( texture, supportsMips ) {
20433 return texture.generateMipmaps && supportsMips &&
20434 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
20438 function generateMipmap( target, texture, width, height ) {
20440 _gl.generateMipmap( target );
20442 const textureProperties = properties.get( texture );
20444 // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
20445 textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
20449 function getInternalFormat( internalFormatName, glFormat, glType ) {
20451 if ( isWebGL2 === false ) return glFormat;
20453 if ( internalFormatName !== null ) {
20455 if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
20457 console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
20461 let internalFormat = glFormat;
20463 if ( glFormat === 6403 ) {
20465 if ( glType === 5126 ) internalFormat = 33326;
20466 if ( glType === 5131 ) internalFormat = 33325;
20467 if ( glType === 5121 ) internalFormat = 33321;
20471 if ( glFormat === 6407 ) {
20473 if ( glType === 5126 ) internalFormat = 34837;
20474 if ( glType === 5131 ) internalFormat = 34843;
20475 if ( glType === 5121 ) internalFormat = 32849;
20479 if ( glFormat === 6408 ) {
20481 if ( glType === 5126 ) internalFormat = 34836;
20482 if ( glType === 5131 ) internalFormat = 34842;
20483 if ( glType === 5121 ) internalFormat = 32856;
20487 if ( internalFormat === 33325 || internalFormat === 33326 ||
20488 internalFormat === 34842 || internalFormat === 34836 ) {
20490 extensions.get( 'EXT_color_buffer_float' );
20494 return internalFormat;
20498 // Fallback filters for non-power-of-2 textures
20500 function filterFallback( f ) {
20502 if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
20514 function onTextureDispose( event ) {
20516 const texture = event.target;
20518 texture.removeEventListener( 'dispose', onTextureDispose );
20520 deallocateTexture( texture );
20522 if ( texture.isVideoTexture ) {
20524 _videoTextures.delete( texture );
20528 info.memory.textures --;
20532 function onRenderTargetDispose( event ) {
20534 const renderTarget = event.target;
20536 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
20538 deallocateRenderTarget( renderTarget );
20540 info.memory.textures --;
20546 function deallocateTexture( texture ) {
20548 const textureProperties = properties.get( texture );
20550 if ( textureProperties.__webglInit === undefined ) return;
20552 _gl.deleteTexture( textureProperties.__webglTexture );
20554 properties.remove( texture );
20558 function deallocateRenderTarget( renderTarget ) {
20560 const renderTargetProperties = properties.get( renderTarget );
20561 const textureProperties = properties.get( renderTarget.texture );
20563 if ( ! renderTarget ) return;
20565 if ( textureProperties.__webglTexture !== undefined ) {
20567 _gl.deleteTexture( textureProperties.__webglTexture );
20571 if ( renderTarget.depthTexture ) {
20573 renderTarget.depthTexture.dispose();
20577 if ( renderTarget.isWebGLCubeRenderTarget ) {
20579 for ( let i = 0; i < 6; i ++ ) {
20581 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
20582 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
20588 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
20589 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
20590 if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
20591 if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
20592 if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
20596 properties.remove( renderTarget.texture );
20597 properties.remove( renderTarget );
20603 let textureUnits = 0;
20605 function resetTextureUnits() {
20611 function allocateTextureUnit() {
20613 const textureUnit = textureUnits;
20615 if ( textureUnit >= maxTextures ) {
20617 console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
20623 return textureUnit;
20629 function setTexture2D( texture, slot ) {
20631 const textureProperties = properties.get( texture );
20633 if ( texture.isVideoTexture ) updateVideoTexture( texture );
20635 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20637 const image = texture.image;
20639 if ( image === undefined ) {
20641 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
20643 } else if ( image.complete === false ) {
20645 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
20649 uploadTexture( textureProperties, texture, slot );
20656 state.activeTexture( 33984 + slot );
20657 state.bindTexture( 3553, textureProperties.__webglTexture );
20661 function setTexture2DArray( texture, slot ) {
20663 const textureProperties = properties.get( texture );
20665 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20667 uploadTexture( textureProperties, texture, slot );
20672 state.activeTexture( 33984 + slot );
20673 state.bindTexture( 35866, textureProperties.__webglTexture );
20677 function setTexture3D( texture, slot ) {
20679 const textureProperties = properties.get( texture );
20681 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20683 uploadTexture( textureProperties, texture, slot );
20688 state.activeTexture( 33984 + slot );
20689 state.bindTexture( 32879, textureProperties.__webglTexture );
20693 function setTextureCube( texture, slot ) {
20695 const textureProperties = properties.get( texture );
20697 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20699 uploadCubeTexture( textureProperties, texture, slot );
20704 state.activeTexture( 33984 + slot );
20705 state.bindTexture( 34067, textureProperties.__webglTexture );
20709 const wrappingToGL = {
20710 [ RepeatWrapping ]: 10497,
20711 [ ClampToEdgeWrapping ]: 33071,
20712 [ MirroredRepeatWrapping ]: 33648
20715 const filterToGL = {
20716 [ NearestFilter ]: 9728,
20717 [ NearestMipmapNearestFilter ]: 9984,
20718 [ NearestMipmapLinearFilter ]: 9986,
20720 [ LinearFilter ]: 9729,
20721 [ LinearMipmapNearestFilter ]: 9985,
20722 [ LinearMipmapLinearFilter ]: 9987
20725 function setTextureParameters( textureType, texture, supportsMips ) {
20727 if ( supportsMips ) {
20729 _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
20730 _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
20732 if ( textureType === 32879 || textureType === 35866 ) {
20734 _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
20738 _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
20739 _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
20743 _gl.texParameteri( textureType, 10242, 33071 );
20744 _gl.texParameteri( textureType, 10243, 33071 );
20746 if ( textureType === 32879 || textureType === 35866 ) {
20748 _gl.texParameteri( textureType, 32882, 33071 );
20752 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
20754 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
20758 _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) );
20759 _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) );
20761 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
20763 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
20769 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
20773 if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
20774 if ( texture.type === HalfFloatType && ( isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
20776 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
20778 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
20779 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
20787 function initTexture( textureProperties, texture ) {
20789 if ( textureProperties.__webglInit === undefined ) {
20791 textureProperties.__webglInit = true;
20793 texture.addEventListener( 'dispose', onTextureDispose );
20795 textureProperties.__webglTexture = _gl.createTexture();
20797 info.memory.textures ++;
20803 function uploadTexture( textureProperties, texture, slot ) {
20805 let textureType = 3553;
20807 if ( texture.isDataTexture2DArray ) textureType = 35866;
20808 if ( texture.isDataTexture3D ) textureType = 32879;
20810 initTexture( textureProperties, texture );
20812 state.activeTexture( 33984 + slot );
20813 state.bindTexture( textureType, textureProperties.__webglTexture );
20815 _gl.pixelStorei( 37440, texture.flipY );
20816 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
20817 _gl.pixelStorei( 3317, texture.unpackAlignment );
20819 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
20820 const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
20822 const supportsMips = isPowerOfTwo( image ) || isWebGL2,
20823 glFormat = utils.convert( texture.format );
20825 let glType = utils.convert( texture.type ),
20826 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
20828 setTextureParameters( textureType, texture, supportsMips );
20831 const mipmaps = texture.mipmaps;
20833 if ( texture.isDepthTexture ) {
20835 // populate depth texture with dummy data
20837 glInternalFormat = 6402;
20841 if ( texture.type === FloatType ) {
20843 glInternalFormat = 36012;
20845 } else if ( texture.type === UnsignedIntType ) {
20847 glInternalFormat = 33190;
20849 } else if ( texture.type === UnsignedInt248Type ) {
20851 glInternalFormat = 35056;
20855 glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D
20861 if ( texture.type === FloatType ) {
20863 console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
20869 // validation checks for WebGL 1
20871 if ( texture.format === DepthFormat && glInternalFormat === 6402 ) {
20873 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20874 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
20875 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20876 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
20878 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
20880 texture.type = UnsignedShortType;
20881 glType = utils.convert( texture.type );
20887 if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) {
20889 // Depth stencil textures need the DEPTH_STENCIL internal format
20890 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20891 glInternalFormat = 34041;
20893 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20894 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
20895 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20896 if ( texture.type !== UnsignedInt248Type ) {
20898 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
20900 texture.type = UnsignedInt248Type;
20901 glType = utils.convert( texture.type );
20909 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
20911 } else if ( texture.isDataTexture ) {
20913 // use manually created mipmaps if available
20914 // if there are no manual mipmaps
20915 // set 0 level mipmap and then use GL to generate other mipmap levels
20917 if ( mipmaps.length > 0 && supportsMips ) {
20919 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20921 mipmap = mipmaps[ i ];
20922 state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20926 texture.generateMipmaps = false;
20927 textureProperties.__maxMipLevel = mipmaps.length - 1;
20931 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
20932 textureProperties.__maxMipLevel = 0;
20936 } else if ( texture.isCompressedTexture ) {
20938 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20940 mipmap = mipmaps[ i ];
20942 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
20944 if ( glFormat !== null ) {
20946 state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
20950 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
20956 state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20962 textureProperties.__maxMipLevel = mipmaps.length - 1;
20964 } else if ( texture.isDataTexture2DArray ) {
20966 state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
20967 textureProperties.__maxMipLevel = 0;
20969 } else if ( texture.isDataTexture3D ) {
20971 state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
20972 textureProperties.__maxMipLevel = 0;
20976 // regular Texture (image, video, canvas)
20978 // use manually created mipmaps if available
20979 // if there are no manual mipmaps
20980 // set 0 level mipmap and then use GL to generate other mipmap levels
20982 if ( mipmaps.length > 0 && supportsMips ) {
20984 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
20986 mipmap = mipmaps[ i ];
20987 state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap );
20991 texture.generateMipmaps = false;
20992 textureProperties.__maxMipLevel = mipmaps.length - 1;
20996 state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image );
20997 textureProperties.__maxMipLevel = 0;
21003 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
21005 generateMipmap( textureType, texture, image.width, image.height );
21009 textureProperties.__version = texture.version;
21011 if ( texture.onUpdate ) texture.onUpdate( texture );
21015 function uploadCubeTexture( textureProperties, texture, slot ) {
21017 if ( texture.image.length !== 6 ) return;
21019 initTexture( textureProperties, texture );
21021 state.activeTexture( 33984 + slot );
21022 state.bindTexture( 34067, textureProperties.__webglTexture );
21024 _gl.pixelStorei( 37440, texture.flipY );
21026 const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) );
21027 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
21029 const cubeImage = [];
21031 for ( let i = 0; i < 6; i ++ ) {
21033 if ( ! isCompressed && ! isDataTexture ) {
21035 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
21039 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
21045 const image = cubeImage[ 0 ],
21046 supportsMips = isPowerOfTwo( image ) || isWebGL2,
21047 glFormat = utils.convert( texture.format ),
21048 glType = utils.convert( texture.type ),
21049 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
21051 setTextureParameters( 34067, texture, supportsMips );
21055 if ( isCompressed ) {
21057 for ( let i = 0; i < 6; i ++ ) {
21059 mipmaps = cubeImage[ i ].mipmaps;
21061 for ( let j = 0; j < mipmaps.length; j ++ ) {
21063 const mipmap = mipmaps[ j ];
21065 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
21067 if ( glFormat !== null ) {
21069 state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
21073 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
21079 state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
21087 textureProperties.__maxMipLevel = mipmaps.length - 1;
21091 mipmaps = texture.mipmaps;
21093 for ( let i = 0; i < 6; i ++ ) {
21095 if ( isDataTexture ) {
21097 state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
21099 for ( let j = 0; j < mipmaps.length; j ++ ) {
21101 const mipmap = mipmaps[ j ];
21102 const mipmapImage = mipmap.image[ i ].image;
21104 state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
21110 state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
21112 for ( let j = 0; j < mipmaps.length; j ++ ) {
21114 const mipmap = mipmaps[ j ];
21116 state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
21124 textureProperties.__maxMipLevel = mipmaps.length;
21128 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
21130 // We assume images for cube map have the same size.
21131 generateMipmap( 34067, texture, image.width, image.height );
21135 textureProperties.__version = texture.version;
21137 if ( texture.onUpdate ) texture.onUpdate( texture );
21143 // Setup storage for target texture and bind it to correct framebuffer
21144 function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
21146 const glFormat = utils.convert( renderTarget.texture.format );
21147 const glType = utils.convert( renderTarget.texture.type );
21148 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
21149 state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
21150 _gl.bindFramebuffer( 36160, framebuffer );
21151 _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
21152 _gl.bindFramebuffer( 36160, null );
21156 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
21157 function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
21159 _gl.bindRenderbuffer( 36161, renderbuffer );
21161 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
21163 let glInternalFormat = 33189;
21165 if ( isMultisample ) {
21167 const depthTexture = renderTarget.depthTexture;
21169 if ( depthTexture && depthTexture.isDepthTexture ) {
21171 if ( depthTexture.type === FloatType ) {
21173 glInternalFormat = 36012;
21175 } else if ( depthTexture.type === UnsignedIntType ) {
21177 glInternalFormat = 33190;
21183 const samples = getRenderTargetSamples( renderTarget );
21185 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
21189 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
21193 _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
21195 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
21197 if ( isMultisample ) {
21199 const samples = getRenderTargetSamples( renderTarget );
21201 _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height );
21205 _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
21210 _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
21214 const glFormat = utils.convert( renderTarget.texture.format );
21215 const glType = utils.convert( renderTarget.texture.type );
21216 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
21218 if ( isMultisample ) {
21220 const samples = getRenderTargetSamples( renderTarget );
21222 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
21226 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
21232 _gl.bindRenderbuffer( 36161, null );
21236 // Setup resources for a Depth Texture for a FBO (needs an extension)
21237 function setupDepthTexture( framebuffer, renderTarget ) {
21239 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
21240 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
21242 _gl.bindFramebuffer( 36160, framebuffer );
21244 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
21246 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
21250 // upload an empty depth texture with framebuffer size
21251 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
21252 renderTarget.depthTexture.image.width !== renderTarget.width ||
21253 renderTarget.depthTexture.image.height !== renderTarget.height ) {
21255 renderTarget.depthTexture.image.width = renderTarget.width;
21256 renderTarget.depthTexture.image.height = renderTarget.height;
21257 renderTarget.depthTexture.needsUpdate = true;
21261 setTexture2D( renderTarget.depthTexture, 0 );
21263 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
21265 if ( renderTarget.depthTexture.format === DepthFormat ) {
21267 _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 );
21269 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
21271 _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 );
21275 throw new Error( 'Unknown depthTexture format' );
21281 // Setup GL resources for a non-texture depth buffer
21282 function setupDepthRenderbuffer( renderTarget ) {
21284 const renderTargetProperties = properties.get( renderTarget );
21286 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
21288 if ( renderTarget.depthTexture ) {
21290 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
21292 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
21298 renderTargetProperties.__webglDepthbuffer = [];
21300 for ( let i = 0; i < 6; i ++ ) {
21302 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] );
21303 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
21304 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
21310 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer );
21311 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
21312 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
21318 _gl.bindFramebuffer( 36160, null );
21322 // Set up GL resources for the render target
21323 function setupRenderTarget( renderTarget ) {
21325 const renderTargetProperties = properties.get( renderTarget );
21326 const textureProperties = properties.get( renderTarget.texture );
21328 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
21330 textureProperties.__webglTexture = _gl.createTexture();
21332 info.memory.textures ++;
21334 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
21335 const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
21336 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
21338 // Handles WebGL2 RGBFormat fallback - #18858
21340 if ( isWebGL2 && renderTarget.texture.format === RGBFormat && ( renderTarget.texture.type === FloatType || renderTarget.texture.type === HalfFloatType ) ) {
21342 renderTarget.texture.format = RGBAFormat;
21344 console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' );
21348 // Setup framebuffer
21352 renderTargetProperties.__webglFramebuffer = [];
21354 for ( let i = 0; i < 6; i ++ ) {
21356 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
21362 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
21364 if ( isMultisample ) {
21368 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
21369 renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
21371 _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
21373 const glFormat = utils.convert( renderTarget.texture.format );
21374 const glType = utils.convert( renderTarget.texture.type );
21375 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
21376 const samples = getRenderTargetSamples( renderTarget );
21377 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
21379 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
21380 _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
21381 _gl.bindRenderbuffer( 36161, null );
21383 if ( renderTarget.depthBuffer ) {
21385 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
21386 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
21390 _gl.bindFramebuffer( 36160, null );
21395 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
21403 // Setup color buffer
21407 state.bindTexture( 34067, textureProperties.__webglTexture );
21408 setTextureParameters( 34067, renderTarget.texture, supportsMips );
21410 for ( let i = 0; i < 6; i ++ ) {
21412 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i );
21416 if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
21418 generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height );
21422 state.bindTexture( 34067, null );
21426 state.bindTexture( 3553, textureProperties.__webglTexture );
21427 setTextureParameters( 3553, renderTarget.texture, supportsMips );
21428 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 );
21430 if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
21432 generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height );
21436 state.bindTexture( 3553, null );
21440 // Setup depth and stencil buffers
21442 if ( renderTarget.depthBuffer ) {
21444 setupDepthRenderbuffer( renderTarget );
21450 function updateRenderTargetMipmap( renderTarget ) {
21452 const texture = renderTarget.texture;
21453 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
21455 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
21457 const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553;
21458 const webglTexture = properties.get( texture ).__webglTexture;
21460 state.bindTexture( target, webglTexture );
21461 generateMipmap( target, texture, renderTarget.width, renderTarget.height );
21462 state.bindTexture( target, null );
21468 function updateMultisampleRenderTarget( renderTarget ) {
21470 if ( renderTarget.isWebGLMultisampleRenderTarget ) {
21474 const renderTargetProperties = properties.get( renderTarget );
21476 _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
21477 _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
21479 const width = renderTarget.width;
21480 const height = renderTarget.height;
21483 if ( renderTarget.depthBuffer ) mask |= 256;
21484 if ( renderTarget.stencilBuffer ) mask |= 1024;
21486 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
21488 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); // see #18905
21492 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
21500 function getRenderTargetSamples( renderTarget ) {
21502 return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
21503 Math.min( maxSamples, renderTarget.samples ) : 0;
21507 function updateVideoTexture( texture ) {
21509 const frame = info.render.frame;
21511 // Check the last frame we updated the VideoTexture
21513 if ( _videoTextures.get( texture ) !== frame ) {
21515 _videoTextures.set( texture, frame );
21522 // backwards compatibility
21524 let warnedTexture2D = false;
21525 let warnedTextureCube = false;
21527 function safeSetTexture2D( texture, slot ) {
21529 if ( texture && texture.isWebGLRenderTarget ) {
21531 if ( warnedTexture2D === false ) {
21533 console.warn( "THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead." );
21534 warnedTexture2D = true;
21538 texture = texture.texture;
21542 setTexture2D( texture, slot );
21546 function safeSetTextureCube( texture, slot ) {
21548 if ( texture && texture.isWebGLCubeRenderTarget ) {
21550 if ( warnedTextureCube === false ) {
21552 console.warn( "THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
21553 warnedTextureCube = true;
21557 texture = texture.texture;
21562 setTextureCube( texture, slot );
21568 this.allocateTextureUnit = allocateTextureUnit;
21569 this.resetTextureUnits = resetTextureUnits;
21571 this.setTexture2D = setTexture2D;
21572 this.setTexture2DArray = setTexture2DArray;
21573 this.setTexture3D = setTexture3D;
21574 this.setTextureCube = setTextureCube;
21575 this.setupRenderTarget = setupRenderTarget;
21576 this.updateRenderTargetMipmap = updateRenderTargetMipmap;
21577 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
21579 this.safeSetTexture2D = safeSetTexture2D;
21580 this.safeSetTextureCube = safeSetTextureCube;
21584 function WebGLUtils( gl, extensions, capabilities ) {
21586 const isWebGL2 = capabilities.isWebGL2;
21588 function convert( p ) {
21592 if ( p === UnsignedByteType ) return 5121;
21593 if ( p === UnsignedShort4444Type ) return 32819;
21594 if ( p === UnsignedShort5551Type ) return 32820;
21595 if ( p === UnsignedShort565Type ) return 33635;
21597 if ( p === ByteType ) return 5120;
21598 if ( p === ShortType ) return 5122;
21599 if ( p === UnsignedShortType ) return 5123;
21600 if ( p === IntType ) return 5124;
21601 if ( p === UnsignedIntType ) return 5125;
21602 if ( p === FloatType ) return 5126;
21604 if ( p === HalfFloatType ) {
21606 if ( isWebGL2 ) return 5131;
21608 extension = extensions.get( 'OES_texture_half_float' );
21610 if ( extension !== null ) {
21612 return extension.HALF_FLOAT_OES;
21622 if ( p === AlphaFormat ) return 6406;
21623 if ( p === RGBFormat ) return 6407;
21624 if ( p === RGBAFormat ) return 6408;
21625 if ( p === LuminanceFormat ) return 6409;
21626 if ( p === LuminanceAlphaFormat ) return 6410;
21627 if ( p === DepthFormat ) return 6402;
21628 if ( p === DepthStencilFormat ) return 34041;
21629 if ( p === RedFormat ) return 6403;
21633 if ( p === RedIntegerFormat ) return 36244;
21634 if ( p === RGFormat ) return 33319;
21635 if ( p === RGIntegerFormat ) return 33320;
21636 if ( p === RGBIntegerFormat ) return 36248;
21637 if ( p === RGBAIntegerFormat ) return 36249;
21639 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
21640 p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
21642 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
21644 if ( extension !== null ) {
21646 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
21647 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
21648 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
21649 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
21659 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
21660 p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
21662 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
21664 if ( extension !== null ) {
21666 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
21667 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
21668 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
21669 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
21679 if ( p === RGB_ETC1_Format ) {
21681 extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
21683 if ( extension !== null ) {
21685 return extension.COMPRESSED_RGB_ETC1_WEBGL;
21695 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
21697 extension = extensions.get( 'WEBGL_compressed_texture_etc' );
21699 if ( extension !== null ) {
21701 if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2;
21702 if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC;
21708 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
21709 p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
21710 p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
21711 p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
21712 p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ||
21713 p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format ||
21714 p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format ||
21715 p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format ||
21716 p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format ||
21717 p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) {
21719 extension = extensions.get( 'WEBGL_compressed_texture_astc' );
21721 if ( extension !== null ) {
21735 if ( p === RGBA_BPTC_Format ) {
21737 extension = extensions.get( 'EXT_texture_compression_bptc' );
21739 if ( extension !== null ) {
21753 if ( p === UnsignedInt248Type ) {
21755 if ( isWebGL2 ) return 34042;
21757 extension = extensions.get( 'WEBGL_depth_texture' );
21759 if ( extension !== null ) {
21761 return extension.UNSIGNED_INT_24_8_WEBGL;
21773 return { convert: convert };
21777 function ArrayCamera( array = [] ) {
21779 PerspectiveCamera.call( this );
21781 this.cameras = array;
21785 ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
21787 constructor: ArrayCamera,
21789 isArrayCamera: true
21795 Object3D.call( this );
21797 this.type = 'Group';
21801 Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
21803 constructor: Group,
21809 function WebXRController() {
21811 this._targetRay = null;
21817 Object.assign( WebXRController.prototype, {
21819 constructor: WebXRController,
21821 getHandSpace: function () {
21823 if ( this._hand === null ) {
21825 this._hand = new Group();
21826 this._hand.matrixAutoUpdate = false;
21827 this._hand.visible = false;
21829 this._hand.joints = [];
21830 this._hand.inputState = { pinching: false };
21832 if ( window.XRHand ) {
21834 for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
21836 // The transform of this joint will be updated with the joint pose on each frame
21837 const joint = new Group();
21838 joint.matrixAutoUpdate = false;
21839 joint.visible = false;
21840 this._hand.joints.push( joint );
21842 this._hand.add( joint );
21854 getTargetRaySpace: function () {
21856 if ( this._targetRay === null ) {
21858 this._targetRay = new Group();
21859 this._targetRay.matrixAutoUpdate = false;
21860 this._targetRay.visible = false;
21864 return this._targetRay;
21868 getGripSpace: function () {
21870 if ( this._grip === null ) {
21872 this._grip = new Group();
21873 this._grip.matrixAutoUpdate = false;
21874 this._grip.visible = false;
21882 dispatchEvent: function ( event ) {
21884 if ( this._targetRay !== null ) {
21886 this._targetRay.dispatchEvent( event );
21890 if ( this._grip !== null ) {
21892 this._grip.dispatchEvent( event );
21896 if ( this._hand !== null ) {
21898 this._hand.dispatchEvent( event );
21906 disconnect: function ( inputSource ) {
21908 this.dispatchEvent( { type: 'disconnected', data: inputSource } );
21910 if ( this._targetRay !== null ) {
21912 this._targetRay.visible = false;
21916 if ( this._grip !== null ) {
21918 this._grip.visible = false;
21922 if ( this._hand !== null ) {
21924 this._hand.visible = false;
21932 update: function ( inputSource, frame, referenceSpace ) {
21934 let inputPose = null;
21935 let gripPose = null;
21936 let handPose = null;
21938 const targetRay = this._targetRay;
21939 const grip = this._grip;
21940 const hand = this._hand;
21942 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
21944 if ( hand && inputSource.hand ) {
21948 for ( let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) {
21950 if ( inputSource.hand[ i ] ) {
21952 // Update the joints groups with the XRJoint poses
21953 const jointPose = frame.getJointPose( inputSource.hand[ i ], referenceSpace );
21954 const joint = hand.joints[ i ];
21956 if ( jointPose !== null ) {
21958 joint.matrix.fromArray( jointPose.transform.matrix );
21959 joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
21960 joint.jointRadius = jointPose.radius;
21964 joint.visible = jointPose !== null;
21969 const indexTip = hand.joints[ window.XRHand.INDEX_PHALANX_TIP ];
21970 const thumbTip = hand.joints[ window.XRHand.THUMB_PHALANX_TIP ];
21971 const distance = indexTip.position.distanceTo( thumbTip.position );
21973 const distanceToPinch = 0.02;
21974 const threshold = 0.005;
21976 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
21978 hand.inputState.pinching = false;
21979 this.dispatchEvent( {
21981 handedness: inputSource.handedness,
21985 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
21987 hand.inputState.pinching = true;
21988 this.dispatchEvent( {
21989 type: "pinchstart",
21990 handedness: inputSource.handedness,
22002 if ( targetRay !== null ) {
22004 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
22006 if ( inputPose !== null ) {
22008 targetRay.matrix.fromArray( inputPose.transform.matrix );
22009 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
22015 if ( grip !== null && inputSource.gripSpace ) {
22017 gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
22019 if ( gripPose !== null ) {
22021 grip.matrix.fromArray( gripPose.transform.matrix );
22022 grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
22032 if ( targetRay !== null ) {
22034 targetRay.visible = ( inputPose !== null );
22038 if ( grip !== null ) {
22040 grip.visible = ( gripPose !== null );
22044 if ( hand !== null ) {
22046 hand.visible = ( handPose !== null );
22056 function WebXRManager( renderer, gl ) {
22058 const scope = this;
22060 let session = null;
22062 let framebufferScaleFactor = 1.0;
22064 let referenceSpace = null;
22065 let referenceSpaceType = 'local-floor';
22069 const controllers = [];
22070 const inputSourcesMap = new Map();
22074 const cameraL = new PerspectiveCamera();
22075 cameraL.layers.enable( 1 );
22076 cameraL.viewport = new Vector4();
22078 const cameraR = new PerspectiveCamera();
22079 cameraR.layers.enable( 2 );
22080 cameraR.viewport = new Vector4();
22082 const cameras = [ cameraL, cameraR ];
22084 const cameraVR = new ArrayCamera();
22085 cameraVR.layers.enable( 1 );
22086 cameraVR.layers.enable( 2 );
22088 let _currentDepthNear = null;
22089 let _currentDepthFar = null;
22093 this.enabled = false;
22095 this.isPresenting = false;
22097 this.getController = function ( index ) {
22099 let controller = controllers[ index ];
22101 if ( controller === undefined ) {
22103 controller = new WebXRController();
22104 controllers[ index ] = controller;
22108 return controller.getTargetRaySpace();
22112 this.getControllerGrip = function ( index ) {
22114 let controller = controllers[ index ];
22116 if ( controller === undefined ) {
22118 controller = new WebXRController();
22119 controllers[ index ] = controller;
22123 return controller.getGripSpace();
22127 this.getHand = function ( index ) {
22129 let controller = controllers[ index ];
22131 if ( controller === undefined ) {
22133 controller = new WebXRController();
22134 controllers[ index ] = controller;
22138 return controller.getHandSpace();
22144 function onSessionEvent( event ) {
22146 const controller = inputSourcesMap.get( event.inputSource );
22148 if ( controller ) {
22150 controller.dispatchEvent( { type: event.type, data: event.inputSource } );
22156 function onSessionEnd() {
22158 inputSourcesMap.forEach( function ( controller, inputSource ) {
22160 controller.disconnect( inputSource );
22164 inputSourcesMap.clear();
22168 renderer.setFramebuffer( null );
22169 renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830
22172 scope.isPresenting = false;
22174 scope.dispatchEvent( { type: 'sessionend' } );
22178 function onRequestReferenceSpace( value ) {
22180 referenceSpace = value;
22182 animation.setContext( session );
22185 scope.isPresenting = true;
22187 scope.dispatchEvent( { type: 'sessionstart' } );
22191 this.setFramebufferScaleFactor = function ( value ) {
22193 framebufferScaleFactor = value;
22195 if ( scope.isPresenting === true ) {
22197 console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
22203 this.setReferenceSpaceType = function ( value ) {
22205 referenceSpaceType = value;
22207 if ( scope.isPresenting === true ) {
22209 console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
22215 this.getReferenceSpace = function () {
22217 return referenceSpace;
22221 this.getSession = function () {
22227 this.setSession = function ( value ) {
22231 if ( session !== null ) {
22233 session.addEventListener( 'select', onSessionEvent );
22234 session.addEventListener( 'selectstart', onSessionEvent );
22235 session.addEventListener( 'selectend', onSessionEvent );
22236 session.addEventListener( 'squeeze', onSessionEvent );
22237 session.addEventListener( 'squeezestart', onSessionEvent );
22238 session.addEventListener( 'squeezeend', onSessionEvent );
22239 session.addEventListener( 'end', onSessionEnd );
22241 const attributes = gl.getContextAttributes();
22243 if ( attributes.xrCompatible !== true ) {
22245 gl.makeXRCompatible();
22249 const layerInit = {
22250 antialias: attributes.antialias,
22251 alpha: attributes.alpha,
22252 depth: attributes.depth,
22253 stencil: attributes.stencil,
22254 framebufferScaleFactor: framebufferScaleFactor
22257 // eslint-disable-next-line no-undef
22258 const baseLayer = new XRWebGLLayer( session, gl, layerInit );
22260 session.updateRenderState( { baseLayer: baseLayer } );
22262 session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace );
22266 session.addEventListener( 'inputsourceschange', updateInputSources );
22272 function updateInputSources( event ) {
22274 const inputSources = session.inputSources;
22276 // Assign inputSources to available controllers
22278 for ( let i = 0; i < controllers.length; i ++ ) {
22280 inputSourcesMap.set( inputSources[ i ], controllers[ i ] );
22284 // Notify disconnected
22286 for ( let i = 0; i < event.removed.length; i ++ ) {
22288 const inputSource = event.removed[ i ];
22289 const controller = inputSourcesMap.get( inputSource );
22291 if ( controller ) {
22293 controller.dispatchEvent( { type: 'disconnected', data: inputSource } );
22294 inputSourcesMap.delete( inputSource );
22300 // Notify connected
22302 for ( let i = 0; i < event.added.length; i ++ ) {
22304 const inputSource = event.added[ i ];
22305 const controller = inputSourcesMap.get( inputSource );
22307 if ( controller ) {
22309 controller.dispatchEvent( { type: 'connected', data: inputSource } );
22319 const cameraLPos = new Vector3();
22320 const cameraRPos = new Vector3();
22323 * Assumes 2 cameras that are parallel and share an X-axis, and that
22324 * the cameras' projection and world matrices have already been set.
22325 * And that near and far planes are identical for both cameras.
22326 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
22328 function setProjectionFromUnion( camera, cameraL, cameraR ) {
22330 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
22331 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
22333 const ipd = cameraLPos.distanceTo( cameraRPos );
22335 const projL = cameraL.projectionMatrix.elements;
22336 const projR = cameraR.projectionMatrix.elements;
22338 // VR systems will have identical far and near planes, and
22339 // most likely identical top and bottom frustum extents.
22340 // Use the left camera for these values.
22341 const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
22342 const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
22343 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
22344 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
22346 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
22347 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
22348 const left = near * leftFov;
22349 const right = near * rightFov;
22351 // Calculate the new camera's position offset from the
22352 // left camera. xOffset should be roughly half `ipd`.
22353 const zOffset = ipd / ( - leftFov + rightFov );
22354 const xOffset = zOffset * - leftFov;
22356 // TODO: Better way to apply this offset?
22357 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
22358 camera.translateX( xOffset );
22359 camera.translateZ( zOffset );
22360 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
22361 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
22363 // Find the union of the frustum values of the cameras and scale
22364 // the values so that the near plane's position does not change in world space,
22365 // although must now be relative to the new union camera.
22366 const near2 = near + zOffset;
22367 const far2 = far + zOffset;
22368 const left2 = left - xOffset;
22369 const right2 = right + ( ipd - xOffset );
22370 const top2 = topFov * far / far2 * near2;
22371 const bottom2 = bottomFov * far / far2 * near2;
22373 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
22377 function updateCamera( camera, parent ) {
22379 if ( parent === null ) {
22381 camera.matrixWorld.copy( camera.matrix );
22385 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
22389 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
22393 this.getCamera = function ( camera ) {
22395 cameraVR.near = cameraR.near = cameraL.near = camera.near;
22396 cameraVR.far = cameraR.far = cameraL.far = camera.far;
22398 if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) {
22400 // Note that the new renderState won't apply until the next frame. See #18320
22402 session.updateRenderState( {
22403 depthNear: cameraVR.near,
22404 depthFar: cameraVR.far
22407 _currentDepthNear = cameraVR.near;
22408 _currentDepthFar = cameraVR.far;
22412 const parent = camera.parent;
22413 const cameras = cameraVR.cameras;
22415 updateCamera( cameraVR, parent );
22417 for ( let i = 0; i < cameras.length; i ++ ) {
22419 updateCamera( cameras[ i ], parent );
22423 // update camera and its children
22425 camera.matrixWorld.copy( cameraVR.matrixWorld );
22427 const children = camera.children;
22429 for ( let i = 0, l = children.length; i < l; i ++ ) {
22431 children[ i ].updateMatrixWorld( true );
22435 // update projection matrix for proper view frustum culling
22437 if ( cameras.length === 2 ) {
22439 setProjectionFromUnion( cameraVR, cameraL, cameraR );
22443 // assume single camera setup (AR)
22445 cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
22455 let onAnimationFrameCallback = null;
22457 function onAnimationFrame( time, frame ) {
22459 pose = frame.getViewerPose( referenceSpace );
22461 if ( pose !== null ) {
22463 const views = pose.views;
22464 const baseLayer = session.renderState.baseLayer;
22466 renderer.setFramebuffer( baseLayer.framebuffer );
22468 let cameraVRNeedsUpdate = false;
22470 // check if it's necessary to rebuild cameraVR's camera list
22472 if ( views.length !== cameraVR.cameras.length ) {
22474 cameraVR.cameras.length = 0;
22475 cameraVRNeedsUpdate = true;
22479 for ( let i = 0; i < views.length; i ++ ) {
22481 const view = views[ i ];
22482 const viewport = baseLayer.getViewport( view );
22484 const camera = cameras[ i ];
22485 camera.matrix.fromArray( view.transform.matrix );
22486 camera.projectionMatrix.fromArray( view.projectionMatrix );
22487 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
22491 cameraVR.matrix.copy( camera.matrix );
22495 if ( cameraVRNeedsUpdate === true ) {
22497 cameraVR.cameras.push( camera );
22507 const inputSources = session.inputSources;
22509 for ( let i = 0; i < controllers.length; i ++ ) {
22511 const controller = controllers[ i ];
22512 const inputSource = inputSources[ i ];
22514 controller.update( inputSource, frame, referenceSpace );
22518 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
22522 const animation = new WebGLAnimation();
22523 animation.setAnimationLoop( onAnimationFrame );
22525 this.setAnimationLoop = function ( callback ) {
22527 onAnimationFrameCallback = callback;
22531 this.dispose = function () {};
22535 Object.assign( WebXRManager.prototype, EventDispatcher.prototype );
22537 function WebGLMaterials( properties ) {
22539 function refreshFogUniforms( uniforms, fog ) {
22541 uniforms.fogColor.value.copy( fog.color );
22545 uniforms.fogNear.value = fog.near;
22546 uniforms.fogFar.value = fog.far;
22548 } else if ( fog.isFogExp2 ) {
22550 uniforms.fogDensity.value = fog.density;
22556 function refreshMaterialUniforms( uniforms, material, pixelRatio, height ) {
22558 if ( material.isMeshBasicMaterial ) {
22560 refreshUniformsCommon( uniforms, material );
22562 } else if ( material.isMeshLambertMaterial ) {
22564 refreshUniformsCommon( uniforms, material );
22565 refreshUniformsLambert( uniforms, material );
22567 } else if ( material.isMeshToonMaterial ) {
22569 refreshUniformsCommon( uniforms, material );
22570 refreshUniformsToon( uniforms, material );
22572 } else if ( material.isMeshPhongMaterial ) {
22574 refreshUniformsCommon( uniforms, material );
22575 refreshUniformsPhong( uniforms, material );
22577 } else if ( material.isMeshStandardMaterial ) {
22579 refreshUniformsCommon( uniforms, material );
22581 if ( material.isMeshPhysicalMaterial ) {
22583 refreshUniformsPhysical( uniforms, material );
22587 refreshUniformsStandard( uniforms, material );
22591 } else if ( material.isMeshMatcapMaterial ) {
22593 refreshUniformsCommon( uniforms, material );
22594 refreshUniformsMatcap( uniforms, material );
22596 } else if ( material.isMeshDepthMaterial ) {
22598 refreshUniformsCommon( uniforms, material );
22599 refreshUniformsDepth( uniforms, material );
22601 } else if ( material.isMeshDistanceMaterial ) {
22603 refreshUniformsCommon( uniforms, material );
22604 refreshUniformsDistance( uniforms, material );
22606 } else if ( material.isMeshNormalMaterial ) {
22608 refreshUniformsCommon( uniforms, material );
22609 refreshUniformsNormal( uniforms, material );
22611 } else if ( material.isLineBasicMaterial ) {
22613 refreshUniformsLine( uniforms, material );
22615 if ( material.isLineDashedMaterial ) {
22617 refreshUniformsDash( uniforms, material );
22621 } else if ( material.isPointsMaterial ) {
22623 refreshUniformsPoints( uniforms, material, pixelRatio, height );
22625 } else if ( material.isSpriteMaterial ) {
22627 refreshUniformsSprites( uniforms, material );
22629 } else if ( material.isShadowMaterial ) {
22631 uniforms.color.value.copy( material.color );
22632 uniforms.opacity.value = material.opacity;
22634 } else if ( material.isShaderMaterial ) {
22636 material.uniformsNeedUpdate = false; // #15581
22642 function refreshUniformsCommon( uniforms, material ) {
22644 uniforms.opacity.value = material.opacity;
22646 if ( material.color ) {
22648 uniforms.diffuse.value.copy( material.color );
22652 if ( material.emissive ) {
22654 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
22658 if ( material.map ) {
22660 uniforms.map.value = material.map;
22664 if ( material.alphaMap ) {
22666 uniforms.alphaMap.value = material.alphaMap;
22670 if ( material.specularMap ) {
22672 uniforms.specularMap.value = material.specularMap;
22676 const envMap = properties.get( material ).envMap;
22680 uniforms.envMap.value = envMap;
22682 uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap._needsFlipEnvMap ) ? - 1 : 1;
22684 uniforms.reflectivity.value = material.reflectivity;
22685 uniforms.refractionRatio.value = material.refractionRatio;
22687 const maxMipLevel = properties.get( envMap ).__maxMipLevel;
22689 if ( maxMipLevel !== undefined ) {
22691 uniforms.maxMipLevel.value = maxMipLevel;
22697 if ( material.lightMap ) {
22699 uniforms.lightMap.value = material.lightMap;
22700 uniforms.lightMapIntensity.value = material.lightMapIntensity;
22704 if ( material.aoMap ) {
22706 uniforms.aoMap.value = material.aoMap;
22707 uniforms.aoMapIntensity.value = material.aoMapIntensity;
22711 // uv repeat and offset setting priorities
22714 // 3. displacementMap map
22717 // 6. roughnessMap map
22718 // 7. metalnessMap map
22720 // 9. emissiveMap map
22721 // 10. clearcoat map
22722 // 11. clearcoat normal map
22723 // 12. clearcoat roughnessMap map
22727 if ( material.map ) {
22729 uvScaleMap = material.map;
22731 } else if ( material.specularMap ) {
22733 uvScaleMap = material.specularMap;
22735 } else if ( material.displacementMap ) {
22737 uvScaleMap = material.displacementMap;
22739 } else if ( material.normalMap ) {
22741 uvScaleMap = material.normalMap;
22743 } else if ( material.bumpMap ) {
22745 uvScaleMap = material.bumpMap;
22747 } else if ( material.roughnessMap ) {
22749 uvScaleMap = material.roughnessMap;
22751 } else if ( material.metalnessMap ) {
22753 uvScaleMap = material.metalnessMap;
22755 } else if ( material.alphaMap ) {
22757 uvScaleMap = material.alphaMap;
22759 } else if ( material.emissiveMap ) {
22761 uvScaleMap = material.emissiveMap;
22763 } else if ( material.clearcoatMap ) {
22765 uvScaleMap = material.clearcoatMap;
22767 } else if ( material.clearcoatNormalMap ) {
22769 uvScaleMap = material.clearcoatNormalMap;
22771 } else if ( material.clearcoatRoughnessMap ) {
22773 uvScaleMap = material.clearcoatRoughnessMap;
22777 if ( uvScaleMap !== undefined ) {
22779 // backwards compatibility
22780 if ( uvScaleMap.isWebGLRenderTarget ) {
22782 uvScaleMap = uvScaleMap.texture;
22786 if ( uvScaleMap.matrixAutoUpdate === true ) {
22788 uvScaleMap.updateMatrix();
22792 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22796 // uv repeat and offset setting priorities for uv2
22802 if ( material.aoMap ) {
22804 uv2ScaleMap = material.aoMap;
22806 } else if ( material.lightMap ) {
22808 uv2ScaleMap = material.lightMap;
22812 if ( uv2ScaleMap !== undefined ) {
22814 // backwards compatibility
22815 if ( uv2ScaleMap.isWebGLRenderTarget ) {
22817 uv2ScaleMap = uv2ScaleMap.texture;
22821 if ( uv2ScaleMap.matrixAutoUpdate === true ) {
22823 uv2ScaleMap.updateMatrix();
22827 uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix );
22833 function refreshUniformsLine( uniforms, material ) {
22835 uniforms.diffuse.value.copy( material.color );
22836 uniforms.opacity.value = material.opacity;
22840 function refreshUniformsDash( uniforms, material ) {
22842 uniforms.dashSize.value = material.dashSize;
22843 uniforms.totalSize.value = material.dashSize + material.gapSize;
22844 uniforms.scale.value = material.scale;
22848 function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
22850 uniforms.diffuse.value.copy( material.color );
22851 uniforms.opacity.value = material.opacity;
22852 uniforms.size.value = material.size * pixelRatio;
22853 uniforms.scale.value = height * 0.5;
22855 if ( material.map ) {
22857 uniforms.map.value = material.map;
22861 if ( material.alphaMap ) {
22863 uniforms.alphaMap.value = material.alphaMap;
22867 // uv repeat and offset setting priorities
22873 if ( material.map ) {
22875 uvScaleMap = material.map;
22877 } else if ( material.alphaMap ) {
22879 uvScaleMap = material.alphaMap;
22883 if ( uvScaleMap !== undefined ) {
22885 if ( uvScaleMap.matrixAutoUpdate === true ) {
22887 uvScaleMap.updateMatrix();
22891 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22897 function refreshUniformsSprites( uniforms, material ) {
22899 uniforms.diffuse.value.copy( material.color );
22900 uniforms.opacity.value = material.opacity;
22901 uniforms.rotation.value = material.rotation;
22903 if ( material.map ) {
22905 uniforms.map.value = material.map;
22909 if ( material.alphaMap ) {
22911 uniforms.alphaMap.value = material.alphaMap;
22915 // uv repeat and offset setting priorities
22921 if ( material.map ) {
22923 uvScaleMap = material.map;
22925 } else if ( material.alphaMap ) {
22927 uvScaleMap = material.alphaMap;
22931 if ( uvScaleMap !== undefined ) {
22933 if ( uvScaleMap.matrixAutoUpdate === true ) {
22935 uvScaleMap.updateMatrix();
22939 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
22945 function refreshUniformsLambert( uniforms, material ) {
22947 if ( material.emissiveMap ) {
22949 uniforms.emissiveMap.value = material.emissiveMap;
22955 function refreshUniformsPhong( uniforms, material ) {
22957 uniforms.specular.value.copy( material.specular );
22958 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
22960 if ( material.emissiveMap ) {
22962 uniforms.emissiveMap.value = material.emissiveMap;
22966 if ( material.bumpMap ) {
22968 uniforms.bumpMap.value = material.bumpMap;
22969 uniforms.bumpScale.value = material.bumpScale;
22970 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
22974 if ( material.normalMap ) {
22976 uniforms.normalMap.value = material.normalMap;
22977 uniforms.normalScale.value.copy( material.normalScale );
22978 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
22982 if ( material.displacementMap ) {
22984 uniforms.displacementMap.value = material.displacementMap;
22985 uniforms.displacementScale.value = material.displacementScale;
22986 uniforms.displacementBias.value = material.displacementBias;
22992 function refreshUniformsToon( uniforms, material ) {
22994 if ( material.gradientMap ) {
22996 uniforms.gradientMap.value = material.gradientMap;
23000 if ( material.emissiveMap ) {
23002 uniforms.emissiveMap.value = material.emissiveMap;
23006 if ( material.bumpMap ) {
23008 uniforms.bumpMap.value = material.bumpMap;
23009 uniforms.bumpScale.value = material.bumpScale;
23010 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
23014 if ( material.normalMap ) {
23016 uniforms.normalMap.value = material.normalMap;
23017 uniforms.normalScale.value.copy( material.normalScale );
23018 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
23022 if ( material.displacementMap ) {
23024 uniforms.displacementMap.value = material.displacementMap;
23025 uniforms.displacementScale.value = material.displacementScale;
23026 uniforms.displacementBias.value = material.displacementBias;
23032 function refreshUniformsStandard( uniforms, material ) {
23034 uniforms.roughness.value = material.roughness;
23035 uniforms.metalness.value = material.metalness;
23037 if ( material.roughnessMap ) {
23039 uniforms.roughnessMap.value = material.roughnessMap;
23043 if ( material.metalnessMap ) {
23045 uniforms.metalnessMap.value = material.metalnessMap;
23049 if ( material.emissiveMap ) {
23051 uniforms.emissiveMap.value = material.emissiveMap;
23055 if ( material.bumpMap ) {
23057 uniforms.bumpMap.value = material.bumpMap;
23058 uniforms.bumpScale.value = material.bumpScale;
23059 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
23063 if ( material.normalMap ) {
23065 uniforms.normalMap.value = material.normalMap;
23066 uniforms.normalScale.value.copy( material.normalScale );
23067 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
23071 if ( material.displacementMap ) {
23073 uniforms.displacementMap.value = material.displacementMap;
23074 uniforms.displacementScale.value = material.displacementScale;
23075 uniforms.displacementBias.value = material.displacementBias;
23079 const envMap = properties.get( material ).envMap;
23083 //uniforms.envMap.value = material.envMap; // part of uniforms common
23084 uniforms.envMapIntensity.value = material.envMapIntensity;
23090 function refreshUniformsPhysical( uniforms, material ) {
23092 refreshUniformsStandard( uniforms, material );
23094 uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common
23096 uniforms.clearcoat.value = material.clearcoat;
23097 uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
23098 if ( material.sheen ) uniforms.sheen.value.copy( material.sheen );
23100 if ( material.clearcoatMap ) {
23102 uniforms.clearcoatMap.value = material.clearcoatMap;
23106 if ( material.clearcoatRoughnessMap ) {
23108 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
23112 if ( material.clearcoatNormalMap ) {
23114 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
23115 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
23117 if ( material.side === BackSide ) {
23119 uniforms.clearcoatNormalScale.value.negate();
23125 uniforms.transmission.value = material.transmission;
23127 if ( material.transmissionMap ) {
23129 uniforms.transmissionMap.value = material.transmissionMap;
23135 function refreshUniformsMatcap( uniforms, material ) {
23137 if ( material.matcap ) {
23139 uniforms.matcap.value = material.matcap;
23143 if ( material.bumpMap ) {
23145 uniforms.bumpMap.value = material.bumpMap;
23146 uniforms.bumpScale.value = material.bumpScale;
23147 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
23151 if ( material.normalMap ) {
23153 uniforms.normalMap.value = material.normalMap;
23154 uniforms.normalScale.value.copy( material.normalScale );
23155 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
23159 if ( material.displacementMap ) {
23161 uniforms.displacementMap.value = material.displacementMap;
23162 uniforms.displacementScale.value = material.displacementScale;
23163 uniforms.displacementBias.value = material.displacementBias;
23169 function refreshUniformsDepth( uniforms, material ) {
23171 if ( material.displacementMap ) {
23173 uniforms.displacementMap.value = material.displacementMap;
23174 uniforms.displacementScale.value = material.displacementScale;
23175 uniforms.displacementBias.value = material.displacementBias;
23181 function refreshUniformsDistance( uniforms, material ) {
23183 if ( material.displacementMap ) {
23185 uniforms.displacementMap.value = material.displacementMap;
23186 uniforms.displacementScale.value = material.displacementScale;
23187 uniforms.displacementBias.value = material.displacementBias;
23191 uniforms.referencePosition.value.copy( material.referencePosition );
23192 uniforms.nearDistance.value = material.nearDistance;
23193 uniforms.farDistance.value = material.farDistance;
23197 function refreshUniformsNormal( uniforms, material ) {
23199 if ( material.bumpMap ) {
23201 uniforms.bumpMap.value = material.bumpMap;
23202 uniforms.bumpScale.value = material.bumpScale;
23203 if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
23207 if ( material.normalMap ) {
23209 uniforms.normalMap.value = material.normalMap;
23210 uniforms.normalScale.value.copy( material.normalScale );
23211 if ( material.side === BackSide ) uniforms.normalScale.value.negate();
23215 if ( material.displacementMap ) {
23217 uniforms.displacementMap.value = material.displacementMap;
23218 uniforms.displacementScale.value = material.displacementScale;
23219 uniforms.displacementBias.value = material.displacementBias;
23226 refreshFogUniforms: refreshFogUniforms,
23227 refreshMaterialUniforms: refreshMaterialUniforms
23232 function createCanvasElement() {
23234 const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
23235 canvas.style.display = 'block';
23240 function WebGLRenderer( parameters ) {
23242 parameters = parameters || {};
23244 const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(),
23245 _context = parameters.context !== undefined ? parameters.context : null,
23247 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
23248 _depth = parameters.depth !== undefined ? parameters.depth : true,
23249 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
23250 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
23251 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
23252 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
23253 _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default',
23254 _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false;
23256 let currentRenderList = null;
23257 let currentRenderState = null;
23259 // public properties
23261 this.domElement = _canvas;
23263 // Debug configuration container
23267 * Enables error checking and reporting when shader programs are being compiled
23270 checkShaderErrors: true
23275 this.autoClear = true;
23276 this.autoClearColor = true;
23277 this.autoClearDepth = true;
23278 this.autoClearStencil = true;
23282 this.sortObjects = true;
23284 // user-defined clipping
23286 this.clippingPlanes = [];
23287 this.localClippingEnabled = false;
23289 // physically based shading
23291 this.gammaFactor = 2.0; // for backwards compatibility
23292 this.outputEncoding = LinearEncoding;
23296 this.physicallyCorrectLights = false;
23300 this.toneMapping = NoToneMapping;
23301 this.toneMappingExposure = 1.0;
23305 this.maxMorphTargets = 8;
23306 this.maxMorphNormals = 4;
23308 // internal properties
23310 const _this = this;
23312 let _isContextLost = false;
23314 // internal state cache
23316 let _framebuffer = null;
23318 let _currentActiveCubeFace = 0;
23319 let _currentActiveMipmapLevel = 0;
23320 let _currentRenderTarget = null;
23321 let _currentFramebuffer = null;
23322 let _currentMaterialId = - 1;
23324 let _currentCamera = null;
23325 let _currentArrayCamera = null;
23327 const _currentViewport = new Vector4();
23328 const _currentScissor = new Vector4();
23329 let _currentScissorTest = null;
23333 let _width = _canvas.width;
23334 let _height = _canvas.height;
23336 let _pixelRatio = 1;
23337 let _opaqueSort = null;
23338 let _transparentSort = null;
23340 const _viewport = new Vector4( 0, 0, _width, _height );
23341 const _scissor = new Vector4( 0, 0, _width, _height );
23342 let _scissorTest = false;
23346 const _frustum = new Frustum();
23350 let _clippingEnabled = false;
23351 let _localClippingEnabled = false;
23353 // camera matrices cache
23355 const _projScreenMatrix = new Matrix4();
23357 const _vector3 = new Vector3();
23359 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
23361 function getTargetPixelRatio() {
23363 return _currentRenderTarget === null ? _pixelRatio : 1;
23369 let _gl = _context;
23371 function getContext( contextNames, contextAttributes ) {
23373 for ( let i = 0; i < contextNames.length; i ++ ) {
23375 const contextName = contextNames[ i ];
23376 const context = _canvas.getContext( contextName, contextAttributes );
23377 if ( context !== null ) return context;
23387 const contextAttributes = {
23391 antialias: _antialias,
23392 premultipliedAlpha: _premultipliedAlpha,
23393 preserveDrawingBuffer: _preserveDrawingBuffer,
23394 powerPreference: _powerPreference,
23395 failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat
23398 // event listeners must be registered before WebGL context is created, see #12753
23400 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
23401 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
23403 if ( _gl === null ) {
23405 const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
23407 if ( _this.isWebGL1Renderer === true ) {
23409 contextNames.shift();
23413 _gl = getContext( contextNames, contextAttributes );
23415 if ( _gl === null ) {
23417 if ( getContext( contextNames ) ) {
23419 throw new Error( 'Error creating WebGL context with your selected attributes.' );
23423 throw new Error( 'Error creating WebGL context.' );
23431 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
23433 if ( _gl.getShaderPrecisionFormat === undefined ) {
23435 _gl.getShaderPrecisionFormat = function () {
23437 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
23443 } catch ( error ) {
23445 console.error( 'THREE.WebGLRenderer: ' + error.message );
23450 let extensions, capabilities, state, info;
23451 let properties, textures, cubemaps, attributes, geometries, objects;
23452 let programCache, materials, renderLists, renderStates, clipping;
23454 let background, morphtargets, bufferRenderer, indexedBufferRenderer;
23456 let utils, bindingStates;
23458 function initGLContext() {
23460 extensions = new WebGLExtensions( _gl );
23462 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
23464 if ( capabilities.isWebGL2 === false ) {
23466 extensions.get( 'WEBGL_depth_texture' );
23467 extensions.get( 'OES_texture_float' );
23468 extensions.get( 'OES_texture_half_float' );
23469 extensions.get( 'OES_texture_half_float_linear' );
23470 extensions.get( 'OES_standard_derivatives' );
23471 extensions.get( 'OES_element_index_uint' );
23472 extensions.get( 'OES_vertex_array_object' );
23473 extensions.get( 'ANGLE_instanced_arrays' );
23477 extensions.get( 'OES_texture_float_linear' );
23479 utils = new WebGLUtils( _gl, extensions, capabilities );
23481 state = new WebGLState( _gl, extensions, capabilities );
23482 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
23483 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
23485 info = new WebGLInfo( _gl );
23486 properties = new WebGLProperties();
23487 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
23488 cubemaps = new WebGLCubeMaps( _this );
23489 attributes = new WebGLAttributes( _gl, capabilities );
23490 bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
23491 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
23492 objects = new WebGLObjects( _gl, geometries, attributes, info );
23493 morphtargets = new WebGLMorphtargets( _gl );
23494 clipping = new WebGLClipping( properties );
23495 programCache = new WebGLPrograms( _this, cubemaps, extensions, capabilities, bindingStates, clipping );
23496 materials = new WebGLMaterials( properties );
23497 renderLists = new WebGLRenderLists( properties );
23498 renderStates = new WebGLRenderStates( extensions, capabilities );
23499 background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha );
23501 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
23502 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
23504 info.programs = programCache.programs;
23506 _this.capabilities = capabilities;
23507 _this.extensions = extensions;
23508 _this.properties = properties;
23509 _this.renderLists = renderLists;
23510 _this.state = state;
23519 const xr = new WebXRManager( _this, _gl );
23525 const shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
23527 this.shadowMap = shadowMap;
23531 this.getContext = function () {
23537 this.getContextAttributes = function () {
23539 return _gl.getContextAttributes();
23543 this.forceContextLoss = function () {
23545 const extension = extensions.get( 'WEBGL_lose_context' );
23546 if ( extension ) extension.loseContext();
23550 this.forceContextRestore = function () {
23552 const extension = extensions.get( 'WEBGL_lose_context' );
23553 if ( extension ) extension.restoreContext();
23557 this.getPixelRatio = function () {
23559 return _pixelRatio;
23563 this.setPixelRatio = function ( value ) {
23565 if ( value === undefined ) return;
23567 _pixelRatio = value;
23569 this.setSize( _width, _height, false );
23573 this.getSize = function ( target ) {
23575 if ( target === undefined ) {
23577 console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
23579 target = new Vector2();
23583 return target.set( _width, _height );
23587 this.setSize = function ( width, height, updateStyle ) {
23589 if ( xr.isPresenting ) {
23591 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
23599 _canvas.width = Math.floor( width * _pixelRatio );
23600 _canvas.height = Math.floor( height * _pixelRatio );
23602 if ( updateStyle !== false ) {
23604 _canvas.style.width = width + 'px';
23605 _canvas.style.height = height + 'px';
23609 this.setViewport( 0, 0, width, height );
23613 this.getDrawingBufferSize = function ( target ) {
23615 if ( target === undefined ) {
23617 console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
23619 target = new Vector2();
23623 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
23627 this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
23632 _pixelRatio = pixelRatio;
23634 _canvas.width = Math.floor( width * pixelRatio );
23635 _canvas.height = Math.floor( height * pixelRatio );
23637 this.setViewport( 0, 0, width, height );
23641 this.getCurrentViewport = function ( target ) {
23643 if ( target === undefined ) {
23645 console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' );
23647 target = new Vector4();
23651 return target.copy( _currentViewport );
23655 this.getViewport = function ( target ) {
23657 return target.copy( _viewport );
23661 this.setViewport = function ( x, y, width, height ) {
23663 if ( x.isVector4 ) {
23665 _viewport.set( x.x, x.y, x.z, x.w );
23669 _viewport.set( x, y, width, height );
23673 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
23677 this.getScissor = function ( target ) {
23679 return target.copy( _scissor );
23683 this.setScissor = function ( x, y, width, height ) {
23685 if ( x.isVector4 ) {
23687 _scissor.set( x.x, x.y, x.z, x.w );
23691 _scissor.set( x, y, width, height );
23695 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
23699 this.getScissorTest = function () {
23701 return _scissorTest;
23705 this.setScissorTest = function ( boolean ) {
23707 state.setScissorTest( _scissorTest = boolean );
23711 this.setOpaqueSort = function ( method ) {
23713 _opaqueSort = method;
23717 this.setTransparentSort = function ( method ) {
23719 _transparentSort = method;
23725 this.getClearColor = function () {
23727 return background.getClearColor();
23731 this.setClearColor = function () {
23733 background.setClearColor.apply( background, arguments );
23737 this.getClearAlpha = function () {
23739 return background.getClearAlpha();
23743 this.setClearAlpha = function () {
23745 background.setClearAlpha.apply( background, arguments );
23749 this.clear = function ( color, depth, stencil ) {
23753 if ( color === undefined || color ) bits |= 16384;
23754 if ( depth === undefined || depth ) bits |= 256;
23755 if ( stencil === undefined || stencil ) bits |= 1024;
23761 this.clearColor = function () {
23763 this.clear( true, false, false );
23767 this.clearDepth = function () {
23769 this.clear( false, true, false );
23773 this.clearStencil = function () {
23775 this.clear( false, false, true );
23781 this.dispose = function () {
23783 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
23784 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
23786 renderLists.dispose();
23787 renderStates.dispose();
23788 properties.dispose();
23789 cubemaps.dispose();
23791 bindingStates.dispose();
23801 function onContextLost( event ) {
23803 event.preventDefault();
23805 console.log( 'THREE.WebGLRenderer: Context Lost.' );
23807 _isContextLost = true;
23811 function onContextRestore( /* event */ ) {
23813 console.log( 'THREE.WebGLRenderer: Context Restored.' );
23815 _isContextLost = false;
23821 function onMaterialDispose( event ) {
23823 const material = event.target;
23825 material.removeEventListener( 'dispose', onMaterialDispose );
23827 deallocateMaterial( material );
23831 // Buffer deallocation
23833 function deallocateMaterial( material ) {
23835 releaseMaterialProgramReference( material );
23837 properties.remove( material );
23842 function releaseMaterialProgramReference( material ) {
23844 const programInfo = properties.get( material ).program;
23846 if ( programInfo !== undefined ) {
23848 programCache.releaseProgram( programInfo );
23854 // Buffer rendering
23856 function renderObjectImmediate( object, program ) {
23858 object.render( function ( object ) {
23860 _this.renderBufferImmediate( object, program );
23866 this.renderBufferImmediate = function ( object, program ) {
23868 bindingStates.initAttributes();
23870 const buffers = properties.get( object );
23872 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
23873 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
23874 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
23875 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
23877 const programAttributes = program.getAttributes();
23879 if ( object.hasPositions ) {
23881 _gl.bindBuffer( 34962, buffers.position );
23882 _gl.bufferData( 34962, object.positionArray, 35048 );
23884 bindingStates.enableAttribute( programAttributes.position );
23885 _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 );
23889 if ( object.hasNormals ) {
23891 _gl.bindBuffer( 34962, buffers.normal );
23892 _gl.bufferData( 34962, object.normalArray, 35048 );
23894 bindingStates.enableAttribute( programAttributes.normal );
23895 _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 );
23899 if ( object.hasUvs ) {
23901 _gl.bindBuffer( 34962, buffers.uv );
23902 _gl.bufferData( 34962, object.uvArray, 35048 );
23904 bindingStates.enableAttribute( programAttributes.uv );
23905 _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 );
23909 if ( object.hasColors ) {
23911 _gl.bindBuffer( 34962, buffers.color );
23912 _gl.bufferData( 34962, object.colorArray, 35048 );
23914 bindingStates.enableAttribute( programAttributes.color );
23915 _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 );
23919 bindingStates.disableUnusedAttributes();
23921 _gl.drawArrays( 4, 0, object.count );
23927 this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
23929 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
23931 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
23933 const program = setProgram( camera, scene, material, object );
23935 state.setMaterial( material, frontFaceCW );
23939 let index = geometry.index;
23940 const position = geometry.attributes.position;
23944 if ( index === null ) {
23946 if ( position === undefined || position.count === 0 ) return;
23948 } else if ( index.count === 0 ) {
23956 let rangeFactor = 1;
23958 if ( material.wireframe === true ) {
23960 index = geometries.getWireframeAttribute( geometry );
23965 if ( material.morphTargets || material.morphNormals ) {
23967 morphtargets.update( object, geometry, material, program );
23971 bindingStates.setup( object, material, program, geometry, index );
23974 let renderer = bufferRenderer;
23976 if ( index !== null ) {
23978 attribute = attributes.get( index );
23980 renderer = indexedBufferRenderer;
23981 renderer.setIndex( attribute );
23987 const dataCount = ( index !== null ) ? index.count : position.count;
23989 const rangeStart = geometry.drawRange.start * rangeFactor;
23990 const rangeCount = geometry.drawRange.count * rangeFactor;
23992 const groupStart = group !== null ? group.start * rangeFactor : 0;
23993 const groupCount = group !== null ? group.count * rangeFactor : Infinity;
23995 const drawStart = Math.max( rangeStart, groupStart );
23996 const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
23998 const drawCount = Math.max( 0, drawEnd - drawStart + 1 );
24000 if ( drawCount === 0 ) return;
24004 if ( object.isMesh ) {
24006 if ( material.wireframe === true ) {
24008 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
24009 renderer.setMode( 1 );
24013 renderer.setMode( 4 );
24017 } else if ( object.isLine ) {
24019 let lineWidth = material.linewidth;
24021 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
24023 state.setLineWidth( lineWidth * getTargetPixelRatio() );
24025 if ( object.isLineSegments ) {
24027 renderer.setMode( 1 );
24029 } else if ( object.isLineLoop ) {
24031 renderer.setMode( 2 );
24035 renderer.setMode( 3 );
24039 } else if ( object.isPoints ) {
24041 renderer.setMode( 0 );
24043 } else if ( object.isSprite ) {
24045 renderer.setMode( 4 );
24049 if ( object.isInstancedMesh ) {
24051 renderer.renderInstances( drawStart, drawCount, object.count );
24053 } else if ( geometry.isInstancedBufferGeometry ) {
24055 const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
24057 renderer.renderInstances( drawStart, drawCount, instanceCount );
24061 renderer.render( drawStart, drawCount );
24069 this.compile = function ( scene, camera ) {
24071 currentRenderState = renderStates.get( scene, camera );
24072 currentRenderState.init();
24074 scene.traverseVisible( function ( object ) {
24076 if ( object.isLight && object.layers.test( camera.layers ) ) {
24078 currentRenderState.pushLight( object );
24080 if ( object.castShadow ) {
24082 currentRenderState.pushShadow( object );
24090 currentRenderState.setupLights( camera );
24092 const compiled = new WeakMap();
24094 scene.traverse( function ( object ) {
24096 const material = object.material;
24100 if ( Array.isArray( material ) ) {
24102 for ( let i = 0; i < material.length; i ++ ) {
24104 const material2 = material[ i ];
24106 if ( compiled.has( material2 ) === false ) {
24108 initMaterial( material2, scene, object );
24109 compiled.set( material2 );
24115 } else if ( compiled.has( material ) === false ) {
24117 initMaterial( material, scene, object );
24118 compiled.set( material );
24130 let onAnimationFrameCallback = null;
24132 function onAnimationFrame( time ) {
24134 if ( xr.isPresenting ) return;
24135 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
24139 const animation = new WebGLAnimation();
24140 animation.setAnimationLoop( onAnimationFrame );
24142 if ( typeof window !== 'undefined' ) animation.setContext( window );
24144 this.setAnimationLoop = function ( callback ) {
24146 onAnimationFrameCallback = callback;
24147 xr.setAnimationLoop( callback );
24149 ( callback === null ) ? animation.stop() : animation.start();
24155 this.render = function ( scene, camera ) {
24157 let renderTarget, forceClear;
24159 if ( arguments[ 2 ] !== undefined ) {
24161 console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' );
24162 renderTarget = arguments[ 2 ];
24166 if ( arguments[ 3 ] !== undefined ) {
24168 console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' );
24169 forceClear = arguments[ 3 ];
24173 if ( camera !== undefined && camera.isCamera !== true ) {
24175 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
24180 if ( _isContextLost === true ) return;
24182 // reset caching for this frame
24184 bindingStates.resetDefaultState();
24185 _currentMaterialId = - 1;
24186 _currentCamera = null;
24188 // update scene graph
24190 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
24192 // update camera matrices and frustum
24194 if ( camera.parent === null ) camera.updateMatrixWorld();
24196 if ( xr.enabled === true && xr.isPresenting === true ) {
24198 camera = xr.getCamera( camera );
24203 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );
24205 currentRenderState = renderStates.get( scene, camera );
24206 currentRenderState.init();
24208 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
24209 _frustum.setFromProjectionMatrix( _projScreenMatrix );
24211 _localClippingEnabled = this.localClippingEnabled;
24212 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
24214 currentRenderList = renderLists.get( scene, camera );
24215 currentRenderList.init();
24217 projectObject( scene, camera, 0, _this.sortObjects );
24219 currentRenderList.finish();
24221 if ( _this.sortObjects === true ) {
24223 currentRenderList.sort( _opaqueSort, _transparentSort );
24229 if ( _clippingEnabled === true ) clipping.beginShadows();
24231 const shadowsArray = currentRenderState.state.shadowsArray;
24233 shadowMap.render( shadowsArray, scene, camera );
24235 currentRenderState.setupLights( camera );
24237 if ( _clippingEnabled === true ) clipping.endShadows();
24241 if ( this.info.autoReset === true ) this.info.reset();
24243 if ( renderTarget !== undefined ) {
24245 this.setRenderTarget( renderTarget );
24251 background.render( currentRenderList, scene, camera, forceClear );
24255 const opaqueObjects = currentRenderList.opaque;
24256 const transparentObjects = currentRenderList.transparent;
24258 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
24259 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
24263 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
24267 if ( _currentRenderTarget !== null ) {
24269 // Generate mipmap if we're using any kind of mipmap filtering
24271 textures.updateRenderTargetMipmap( _currentRenderTarget );
24273 // resolve multisample renderbuffers to a single-sample texture if necessary
24275 textures.updateMultisampleRenderTarget( _currentRenderTarget );
24279 // Ensure depth buffer writing is enabled so it can be cleared on next render
24281 state.buffers.depth.setTest( true );
24282 state.buffers.depth.setMask( true );
24283 state.buffers.color.setMask( true );
24285 state.setPolygonOffset( false );
24289 currentRenderList = null;
24290 currentRenderState = null;
24294 function projectObject( object, camera, groupOrder, sortObjects ) {
24296 if ( object.visible === false ) return;
24298 const visible = object.layers.test( camera.layers );
24302 if ( object.isGroup ) {
24304 groupOrder = object.renderOrder;
24306 } else if ( object.isLOD ) {
24308 if ( object.autoUpdate === true ) object.update( camera );
24310 } else if ( object.isLight ) {
24312 currentRenderState.pushLight( object );
24314 if ( object.castShadow ) {
24316 currentRenderState.pushShadow( object );
24320 } else if ( object.isSprite ) {
24322 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
24324 if ( sortObjects ) {
24326 _vector3.setFromMatrixPosition( object.matrixWorld )
24327 .applyMatrix4( _projScreenMatrix );
24331 const geometry = objects.update( object );
24332 const material = object.material;
24334 if ( material.visible ) {
24336 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
24342 } else if ( object.isImmediateRenderObject ) {
24344 if ( sortObjects ) {
24346 _vector3.setFromMatrixPosition( object.matrixWorld )
24347 .applyMatrix4( _projScreenMatrix );
24351 currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null );
24353 } else if ( object.isMesh || object.isLine || object.isPoints ) {
24355 if ( object.isSkinnedMesh ) {
24357 // update skeleton only once in a frame
24359 if ( object.skeleton.frame !== info.render.frame ) {
24361 object.skeleton.update();
24362 object.skeleton.frame = info.render.frame;
24368 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
24370 if ( sortObjects ) {
24372 _vector3.setFromMatrixPosition( object.matrixWorld )
24373 .applyMatrix4( _projScreenMatrix );
24377 const geometry = objects.update( object );
24378 const material = object.material;
24380 if ( Array.isArray( material ) ) {
24382 const groups = geometry.groups;
24384 for ( let i = 0, l = groups.length; i < l; i ++ ) {
24386 const group = groups[ i ];
24387 const groupMaterial = material[ group.materialIndex ];
24389 if ( groupMaterial && groupMaterial.visible ) {
24391 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
24397 } else if ( material.visible ) {
24399 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
24409 const children = object.children;
24411 for ( let i = 0, l = children.length; i < l; i ++ ) {
24413 projectObject( children[ i ], camera, groupOrder, sortObjects );
24419 function renderObjects( renderList, scene, camera ) {
24421 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
24423 for ( let i = 0, l = renderList.length; i < l; i ++ ) {
24425 const renderItem = renderList[ i ];
24427 const object = renderItem.object;
24428 const geometry = renderItem.geometry;
24429 const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
24430 const group = renderItem.group;
24432 if ( camera.isArrayCamera ) {
24434 _currentArrayCamera = camera;
24436 const cameras = camera.cameras;
24438 for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
24440 const camera2 = cameras[ j ];
24442 if ( object.layers.test( camera2.layers ) ) {
24444 state.viewport( _currentViewport.copy( camera2.viewport ) );
24446 currentRenderState.setupLights( camera2 );
24448 renderObject( object, scene, camera2, geometry, material, group );
24456 _currentArrayCamera = null;
24458 renderObject( object, scene, camera, geometry, material, group );
24466 function renderObject( object, scene, camera, geometry, material, group ) {
24468 object.onBeforeRender( _this, scene, camera, geometry, material, group );
24469 currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );
24471 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
24472 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
24474 if ( object.isImmediateRenderObject ) {
24476 const program = setProgram( camera, scene, material, object );
24478 state.setMaterial( material );
24480 bindingStates.reset();
24482 renderObjectImmediate( object, program );
24486 _this.renderBufferDirect( camera, scene, geometry, material, object, group );
24490 object.onAfterRender( _this, scene, camera, geometry, material, group );
24491 currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );
24495 function initMaterial( material, scene, object ) {
24497 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
24499 const materialProperties = properties.get( material );
24501 const lights = currentRenderState.state.lights;
24502 const shadowsArray = currentRenderState.state.shadowsArray;
24504 const lightsStateVersion = lights.state.version;
24506 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
24507 const programCacheKey = programCache.getProgramCacheKey( parameters );
24509 let program = materialProperties.program;
24510 let programChange = true;
24512 if ( program === undefined ) {
24515 material.addEventListener( 'dispose', onMaterialDispose );
24517 } else if ( program.cacheKey !== programCacheKey ) {
24519 // changed glsl or parameters
24520 releaseMaterialProgramReference( material );
24522 } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) {
24524 programChange = false;
24526 } else if ( parameters.shaderID !== undefined ) {
24528 // same glsl and uniform list, envMap still needs the update here to avoid a frame-late effect
24530 const environment = material.isMeshStandardMaterial ? scene.environment : null;
24531 materialProperties.envMap = cubemaps.get( material.envMap || environment );
24537 // only rebuild uniform list
24538 programChange = false;
24542 if ( programChange ) {
24544 parameters.uniforms = programCache.getUniforms( material );
24546 material.onBeforeCompile( parameters, _this );
24548 program = programCache.acquireProgram( parameters, programCacheKey );
24550 materialProperties.program = program;
24551 materialProperties.uniforms = parameters.uniforms;
24552 materialProperties.outputEncoding = parameters.outputEncoding;
24556 const uniforms = materialProperties.uniforms;
24558 if ( ! material.isShaderMaterial &&
24559 ! material.isRawShaderMaterial ||
24560 material.clipping === true ) {
24562 materialProperties.numClippingPlanes = clipping.numPlanes;
24563 materialProperties.numIntersection = clipping.numIntersection;
24564 uniforms.clippingPlanes = clipping.uniform;
24568 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
24569 materialProperties.fog = scene.fog;
24570 materialProperties.envMap = cubemaps.get( material.envMap || materialProperties.environment );
24572 // store the light setup it was created for
24574 materialProperties.needsLights = materialNeedsLights( material );
24575 materialProperties.lightsStateVersion = lightsStateVersion;
24577 if ( materialProperties.needsLights ) {
24579 // wire up the material to this renderer's lighting state
24581 uniforms.ambientLightColor.value = lights.state.ambient;
24582 uniforms.lightProbe.value = lights.state.probe;
24583 uniforms.directionalLights.value = lights.state.directional;
24584 uniforms.directionalLightShadows.value = lights.state.directionalShadow;
24585 uniforms.spotLights.value = lights.state.spot;
24586 uniforms.spotLightShadows.value = lights.state.spotShadow;
24587 uniforms.rectAreaLights.value = lights.state.rectArea;
24588 uniforms.ltc_1.value = lights.state.rectAreaLTC1;
24589 uniforms.ltc_2.value = lights.state.rectAreaLTC2;
24590 uniforms.pointLights.value = lights.state.point;
24591 uniforms.pointLightShadows.value = lights.state.pointShadow;
24592 uniforms.hemisphereLights.value = lights.state.hemi;
24594 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
24595 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
24596 uniforms.spotShadowMap.value = lights.state.spotShadowMap;
24597 uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
24598 uniforms.pointShadowMap.value = lights.state.pointShadowMap;
24599 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
24600 // TODO (abelnation): add area lights shadow info to uniforms
24604 const progUniforms = materialProperties.program.getUniforms();
24605 const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
24607 materialProperties.uniformsList = uniformsList;
24611 function setProgram( camera, scene, material, object ) {
24613 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
24615 textures.resetTextureUnits();
24617 const fog = scene.fog;
24618 const environment = material.isMeshStandardMaterial ? scene.environment : null;
24619 const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
24620 const envMap = cubemaps.get( material.envMap || environment );
24622 const materialProperties = properties.get( material );
24623 const lights = currentRenderState.state.lights;
24625 if ( _clippingEnabled === true ) {
24627 if ( _localClippingEnabled === true || camera !== _currentCamera ) {
24630 camera === _currentCamera &&
24631 material.id === _currentMaterialId;
24633 // we might want to call this function with some ClippingGroup
24634 // object instead of the material, once it becomes feasible
24636 clipping.setState( material, camera, useCache );
24642 if ( material.version === materialProperties.__version ) {
24644 if ( material.fog && materialProperties.fog !== fog ) {
24646 initMaterial( material, scene, object );
24648 } else if ( materialProperties.environment !== environment ) {
24650 initMaterial( material, scene, object );
24652 } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
24654 initMaterial( material, scene, object );
24656 } else if ( materialProperties.numClippingPlanes !== undefined &&
24657 ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
24658 materialProperties.numIntersection !== clipping.numIntersection ) ) {
24660 initMaterial( material, scene, object );
24662 } else if ( materialProperties.outputEncoding !== encoding ) {
24664 initMaterial( material, scene, object );
24666 } else if ( materialProperties.envMap !== envMap ) {
24668 initMaterial( material, scene, object );
24674 initMaterial( material, scene, object );
24675 materialProperties.__version = material.version;
24679 let refreshProgram = false;
24680 let refreshMaterial = false;
24681 let refreshLights = false;
24683 const program = materialProperties.program,
24684 p_uniforms = program.getUniforms(),
24685 m_uniforms = materialProperties.uniforms;
24687 if ( state.useProgram( program.program ) ) {
24689 refreshProgram = true;
24690 refreshMaterial = true;
24691 refreshLights = true;
24695 if ( material.id !== _currentMaterialId ) {
24697 _currentMaterialId = material.id;
24699 refreshMaterial = true;
24703 if ( refreshProgram || _currentCamera !== camera ) {
24705 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
24707 if ( capabilities.logarithmicDepthBuffer ) {
24709 p_uniforms.setValue( _gl, 'logDepthBufFC',
24710 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
24714 if ( _currentCamera !== camera ) {
24716 _currentCamera = camera;
24718 // lighting uniforms depend on the camera so enforce an update
24719 // now, in case this material supports lights - or later, when
24720 // the next material that does gets activated:
24722 refreshMaterial = true; // set to true on material change
24723 refreshLights = true; // remains set until update done
24727 // load material specific uniforms
24728 // (shader material also gets them for the sake of genericity)
24730 if ( material.isShaderMaterial ||
24731 material.isMeshPhongMaterial ||
24732 material.isMeshToonMaterial ||
24733 material.isMeshStandardMaterial ||
24734 material.envMap ) {
24736 const uCamPos = p_uniforms.map.cameraPosition;
24738 if ( uCamPos !== undefined ) {
24740 uCamPos.setValue( _gl,
24741 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
24747 if ( material.isMeshPhongMaterial ||
24748 material.isMeshToonMaterial ||
24749 material.isMeshLambertMaterial ||
24750 material.isMeshBasicMaterial ||
24751 material.isMeshStandardMaterial ||
24752 material.isShaderMaterial ) {
24754 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
24758 if ( material.isMeshPhongMaterial ||
24759 material.isMeshToonMaterial ||
24760 material.isMeshLambertMaterial ||
24761 material.isMeshBasicMaterial ||
24762 material.isMeshStandardMaterial ||
24763 material.isShaderMaterial ||
24764 material.isShadowMaterial ||
24765 material.skinning ) {
24767 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
24773 // skinning uniforms must be set even if material didn't change
24774 // auto-setting of texture unit for bone texture must go before other textures
24775 // otherwise textures used for skinning can take over texture units reserved for other material textures
24777 if ( material.skinning ) {
24779 p_uniforms.setOptional( _gl, object, 'bindMatrix' );
24780 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
24782 const skeleton = object.skeleton;
24786 const bones = skeleton.bones;
24788 if ( capabilities.floatVertexTextures ) {
24790 if ( skeleton.boneTexture === null ) {
24792 // layout (1 matrix = 4 pixels)
24793 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
24794 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
24795 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
24796 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
24797 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
24800 let size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
24801 size = MathUtils.ceilPowerOfTwo( size );
24802 size = Math.max( size, 4 );
24804 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
24805 boneMatrices.set( skeleton.boneMatrices ); // copy current values
24807 const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
24809 skeleton.boneMatrices = boneMatrices;
24810 skeleton.boneTexture = boneTexture;
24811 skeleton.boneTextureSize = size;
24815 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
24816 p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
24820 p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
24828 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
24830 materialProperties.receiveShadow = object.receiveShadow;
24831 p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
24835 if ( refreshMaterial ) {
24837 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
24839 if ( materialProperties.needsLights ) {
24841 // the current material requires lighting info
24843 // note: all lighting uniforms are always set correctly
24844 // they simply reference the renderer's state for their
24847 // use the current material's .needsUpdate flags to set
24848 // the GL state when required
24850 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
24854 // refresh uniforms common to several materials
24856 if ( fog && material.fog ) {
24858 materials.refreshFogUniforms( m_uniforms, fog );
24862 materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height );
24864 WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
24868 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
24870 WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
24871 material.uniformsNeedUpdate = false;
24875 if ( material.isSpriteMaterial ) {
24877 p_uniforms.setValue( _gl, 'center', object.center );
24883 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
24884 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
24885 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
24891 // If uniforms are marked as clean, they don't need to be loaded to the GPU.
24893 function markUniformsLightsNeedsUpdate( uniforms, value ) {
24895 uniforms.ambientLightColor.needsUpdate = value;
24896 uniforms.lightProbe.needsUpdate = value;
24898 uniforms.directionalLights.needsUpdate = value;
24899 uniforms.directionalLightShadows.needsUpdate = value;
24900 uniforms.pointLights.needsUpdate = value;
24901 uniforms.pointLightShadows.needsUpdate = value;
24902 uniforms.spotLights.needsUpdate = value;
24903 uniforms.spotLightShadows.needsUpdate = value;
24904 uniforms.rectAreaLights.needsUpdate = value;
24905 uniforms.hemisphereLights.needsUpdate = value;
24909 function materialNeedsLights( material ) {
24911 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
24912 material.isMeshStandardMaterial || material.isShadowMaterial ||
24913 ( material.isShaderMaterial && material.lights === true );
24918 this.setFramebuffer = function ( value ) {
24920 if ( _framebuffer !== value && _currentRenderTarget === null ) _gl.bindFramebuffer( 36160, value );
24922 _framebuffer = value;
24926 this.getActiveCubeFace = function () {
24928 return _currentActiveCubeFace;
24932 this.getActiveMipmapLevel = function () {
24934 return _currentActiveMipmapLevel;
24938 this.getRenderList = function () {
24940 return currentRenderList;
24944 this.setRenderList = function ( renderList ) {
24946 currentRenderList = renderList;
24950 this.getRenderState = function () {
24952 return currentRenderState;
24956 this.setRenderState = function ( renderState ) {
24958 currentRenderState = renderState;
24962 this.getRenderTarget = function () {
24964 return _currentRenderTarget;
24968 this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
24970 _currentRenderTarget = renderTarget;
24971 _currentActiveCubeFace = activeCubeFace;
24972 _currentActiveMipmapLevel = activeMipmapLevel;
24974 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
24976 textures.setupRenderTarget( renderTarget );
24980 let framebuffer = _framebuffer;
24981 let isCube = false;
24983 if ( renderTarget ) {
24985 const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
24987 if ( renderTarget.isWebGLCubeRenderTarget ) {
24989 framebuffer = __webglFramebuffer[ activeCubeFace ];
24992 } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
24994 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
24998 framebuffer = __webglFramebuffer;
25002 _currentViewport.copy( renderTarget.viewport );
25003 _currentScissor.copy( renderTarget.scissor );
25004 _currentScissorTest = renderTarget.scissorTest;
25008 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
25009 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
25010 _currentScissorTest = _scissorTest;
25014 if ( _currentFramebuffer !== framebuffer ) {
25016 _gl.bindFramebuffer( 36160, framebuffer );
25017 _currentFramebuffer = framebuffer;
25021 state.viewport( _currentViewport );
25022 state.scissor( _currentScissor );
25023 state.setScissorTest( _currentScissorTest );
25027 const textureProperties = properties.get( renderTarget.texture );
25028 _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
25034 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
25036 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
25038 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
25043 let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
25045 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
25047 framebuffer = framebuffer[ activeCubeFaceIndex ];
25051 if ( framebuffer ) {
25053 let restore = false;
25055 if ( framebuffer !== _currentFramebuffer ) {
25057 _gl.bindFramebuffer( 36160, framebuffer );
25065 const texture = renderTarget.texture;
25066 const textureFormat = texture.format;
25067 const textureType = texture.type;
25069 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) {
25071 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
25076 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513)
25077 ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
25078 ! ( textureType === HalfFloatType && ( capabilities.isWebGL2 ? extensions.get( 'EXT_color_buffer_float' ) : extensions.get( 'EXT_color_buffer_half_float' ) ) ) ) {
25080 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
25085 if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) {
25087 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
25089 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
25091 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
25097 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
25105 _gl.bindFramebuffer( 36160, _currentFramebuffer );
25115 this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
25117 const levelScale = Math.pow( 2, - level );
25118 const width = Math.floor( texture.image.width * levelScale );
25119 const height = Math.floor( texture.image.height * levelScale );
25120 const glFormat = utils.convert( texture.format );
25122 textures.setTexture2D( texture, 0 );
25124 _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 );
25126 state.unbindTexture();
25130 this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
25132 const width = srcTexture.image.width;
25133 const height = srcTexture.image.height;
25134 const glFormat = utils.convert( dstTexture.format );
25135 const glType = utils.convert( dstTexture.type );
25137 textures.setTexture2D( dstTexture, 0 );
25139 // As another texture upload may have changed pixelStorei
25140 // parameters, make sure they are correct for the dstTexture
25141 _gl.pixelStorei( 37440, dstTexture.flipY );
25142 _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
25143 _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
25145 if ( srcTexture.isDataTexture ) {
25147 _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
25151 if ( srcTexture.isCompressedTexture ) {
25153 _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
25157 _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image );
25163 // Generate mipmaps only when copying level 0
25164 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 );
25166 state.unbindTexture();
25170 this.initTexture = function ( texture ) {
25172 textures.setTexture2D( texture, 0 );
25174 state.unbindTexture();
25178 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
25180 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
25186 function WebGL1Renderer( parameters ) {
25188 WebGLRenderer.call( this, parameters );
25192 WebGL1Renderer.prototype = Object.assign( Object.create( WebGLRenderer.prototype ), {
25194 constructor: WebGL1Renderer,
25196 isWebGL1Renderer: true
25202 constructor( color, density ) {
25204 Object.defineProperty( this, 'isFogExp2', { value: true } );
25208 this.color = new Color( color );
25209 this.density = ( density !== undefined ) ? density : 0.00025;
25215 return new FogExp2( this.color, this.density );
25219 toJSON( /* meta */ ) {
25223 color: this.color.getHex(),
25224 density: this.density
25233 constructor( color, near, far ) {
25235 Object.defineProperty( this, 'isFog', { value: true } );
25239 this.color = new Color( color );
25241 this.near = ( near !== undefined ) ? near : 1;
25242 this.far = ( far !== undefined ) ? far : 1000;
25248 return new Fog( this.color, this.near, this.far );
25252 toJSON( /* meta */ ) {
25256 color: this.color.getHex(),
25265 class Scene extends Object3D {
25271 Object.defineProperty( this, 'isScene', { value: true } );
25273 this.type = 'Scene';
25275 this.background = null;
25276 this.environment = null;
25279 this.overrideMaterial = null;
25281 this.autoUpdate = true; // checked by the renderer
25283 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
25285 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
25291 copy( source, recursive ) {
25293 super.copy( source, recursive );
25295 if ( source.background !== null ) this.background = source.background.clone();
25296 if ( source.environment !== null ) this.environment = source.environment.clone();
25297 if ( source.fog !== null ) this.fog = source.fog.clone();
25299 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
25301 this.autoUpdate = source.autoUpdate;
25302 this.matrixAutoUpdate = source.matrixAutoUpdate;
25310 const data = super.toJSON( meta );
25312 if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
25313 if ( this.environment !== null ) data.object.environment = this.environment.toJSON( meta );
25314 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
25322 function InterleavedBuffer( array, stride ) {
25324 this.array = array;
25325 this.stride = stride;
25326 this.count = array !== undefined ? array.length / stride : 0;
25328 this.usage = StaticDrawUsage;
25329 this.updateRange = { offset: 0, count: - 1 };
25333 this.uuid = MathUtils.generateUUID();
25337 Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
25339 set: function ( value ) {
25341 if ( value === true ) this.version ++;
25347 Object.assign( InterleavedBuffer.prototype, {
25349 isInterleavedBuffer: true,
25351 onUploadCallback: function () {},
25353 setUsage: function ( value ) {
25355 this.usage = value;
25361 copy: function ( source ) {
25363 this.array = new source.array.constructor( source.array );
25364 this.count = source.count;
25365 this.stride = source.stride;
25366 this.usage = source.usage;
25372 copyAt: function ( index1, attribute, index2 ) {
25374 index1 *= this.stride;
25375 index2 *= attribute.stride;
25377 for ( let i = 0, l = this.stride; i < l; i ++ ) {
25379 this.array[ index1 + i ] = attribute.array[ index2 + i ];
25387 set: function ( value, offset = 0 ) {
25389 this.array.set( value, offset );
25395 clone: function ( data ) {
25397 if ( data.arrayBuffers === undefined ) {
25399 data.arrayBuffers = {};
25403 if ( this.array.buffer._uuid === undefined ) {
25405 this.array.buffer._uuid = MathUtils.generateUUID();
25409 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
25411 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
25415 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
25417 const ib = new InterleavedBuffer( array, this.stride );
25418 ib.setUsage( this.usage );
25424 onUpload: function ( callback ) {
25426 this.onUploadCallback = callback;
25432 toJSON: function ( data ) {
25434 if ( data.arrayBuffers === undefined ) {
25436 data.arrayBuffers = {};
25440 // generate UUID for array buffer if necessary
25442 if ( this.array.buffer._uuid === undefined ) {
25444 this.array.buffer._uuid = MathUtils.generateUUID();
25448 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
25450 data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) );
25458 buffer: this.array.buffer._uuid,
25459 type: this.array.constructor.name,
25460 stride: this.stride
25467 const _vector$6 = new Vector3();
25469 function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
25473 this.data = interleavedBuffer;
25474 this.itemSize = itemSize;
25475 this.offset = offset;
25477 this.normalized = normalized === true;
25481 Object.defineProperties( InterleavedBufferAttribute.prototype, {
25487 return this.data.count;
25497 return this.data.array;
25505 set: function ( value ) {
25507 this.data.needsUpdate = value;
25515 Object.assign( InterleavedBufferAttribute.prototype, {
25517 isInterleavedBufferAttribute: true,
25519 applyMatrix4: function ( m ) {
25521 for ( let i = 0, l = this.data.count; i < l; i ++ ) {
25523 _vector$6.x = this.getX( i );
25524 _vector$6.y = this.getY( i );
25525 _vector$6.z = this.getZ( i );
25527 _vector$6.applyMatrix4( m );
25529 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
25537 setX: function ( index, x ) {
25539 this.data.array[ index * this.data.stride + this.offset ] = x;
25545 setY: function ( index, y ) {
25547 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
25553 setZ: function ( index, z ) {
25555 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
25561 setW: function ( index, w ) {
25563 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
25569 getX: function ( index ) {
25571 return this.data.array[ index * this.data.stride + this.offset ];
25575 getY: function ( index ) {
25577 return this.data.array[ index * this.data.stride + this.offset + 1 ];
25581 getZ: function ( index ) {
25583 return this.data.array[ index * this.data.stride + this.offset + 2 ];
25587 getW: function ( index ) {
25589 return this.data.array[ index * this.data.stride + this.offset + 3 ];
25593 setXY: function ( index, x, y ) {
25595 index = index * this.data.stride + this.offset;
25597 this.data.array[ index + 0 ] = x;
25598 this.data.array[ index + 1 ] = y;
25604 setXYZ: function ( index, x, y, z ) {
25606 index = index * this.data.stride + this.offset;
25608 this.data.array[ index + 0 ] = x;
25609 this.data.array[ index + 1 ] = y;
25610 this.data.array[ index + 2 ] = z;
25616 setXYZW: function ( index, x, y, z, w ) {
25618 index = index * this.data.stride + this.offset;
25620 this.data.array[ index + 0 ] = x;
25621 this.data.array[ index + 1 ] = y;
25622 this.data.array[ index + 2 ] = z;
25623 this.data.array[ index + 3 ] = w;
25629 clone: function ( data ) {
25631 if ( data === undefined ) {
25633 console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' );
25637 for ( let i = 0; i < this.count; i ++ ) {
25639 const index = i * this.data.stride + this.offset;
25641 for ( let j = 0; j < this.itemSize; j ++ ) {
25643 array.push( this.data.array[ index + j ] );
25649 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
25653 if ( data.interleavedBuffers === undefined ) {
25655 data.interleavedBuffers = {};
25659 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
25661 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
25665 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
25671 toJSON: function ( data ) {
25673 if ( data === undefined ) {
25675 console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' );
25679 for ( let i = 0; i < this.count; i ++ ) {
25681 const index = i * this.data.stride + this.offset;
25683 for ( let j = 0; j < this.itemSize; j ++ ) {
25685 array.push( this.data.array[ index + j ] );
25691 // deinterleave data and save it as an ordinary buffer attribute for now
25694 itemSize: this.itemSize,
25695 type: this.array.constructor.name,
25697 normalized: this.normalized
25702 // save as true interlaved attribtue
25704 if ( data.interleavedBuffers === undefined ) {
25706 data.interleavedBuffers = {};
25710 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
25712 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
25717 isInterleavedBufferAttribute: true,
25718 itemSize: this.itemSize,
25719 data: this.data.uuid,
25720 offset: this.offset,
25721 normalized: this.normalized
25733 * map: new THREE.Texture( <Image> ),
25734 * alphaMap: new THREE.Texture( <Image> ),
25735 * rotation: <float>,
25736 * sizeAttenuation: <bool>
25740 function SpriteMaterial( parameters ) {
25742 Material.call( this );
25744 this.type = 'SpriteMaterial';
25746 this.color = new Color( 0xffffff );
25750 this.alphaMap = null;
25754 this.sizeAttenuation = true;
25756 this.transparent = true;
25758 this.setValues( parameters );
25762 SpriteMaterial.prototype = Object.create( Material.prototype );
25763 SpriteMaterial.prototype.constructor = SpriteMaterial;
25764 SpriteMaterial.prototype.isSpriteMaterial = true;
25766 SpriteMaterial.prototype.copy = function ( source ) {
25768 Material.prototype.copy.call( this, source );
25770 this.color.copy( source.color );
25772 this.map = source.map;
25774 this.alphaMap = source.alphaMap;
25776 this.rotation = source.rotation;
25778 this.sizeAttenuation = source.sizeAttenuation;
25786 const _intersectPoint = new Vector3();
25787 const _worldScale = new Vector3();
25788 const _mvPosition = new Vector3();
25790 const _alignedPosition = new Vector2();
25791 const _rotatedPosition = new Vector2();
25792 const _viewWorldMatrix = new Matrix4();
25794 const _vA$1 = new Vector3();
25795 const _vB$1 = new Vector3();
25796 const _vC$1 = new Vector3();
25798 const _uvA$1 = new Vector2();
25799 const _uvB$1 = new Vector2();
25800 const _uvC$1 = new Vector2();
25802 function Sprite( material ) {
25804 Object3D.call( this );
25806 this.type = 'Sprite';
25808 if ( _geometry === undefined ) {
25810 _geometry = new BufferGeometry();
25812 const float32Array = new Float32Array( [
25813 - 0.5, - 0.5, 0, 0, 0,
25814 0.5, - 0.5, 0, 1, 0,
25816 - 0.5, 0.5, 0, 0, 1
25819 const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
25821 _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
25822 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
25823 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
25827 this.geometry = _geometry;
25828 this.material = ( material !== undefined ) ? material : new SpriteMaterial();
25830 this.center = new Vector2( 0.5, 0.5 );
25834 Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
25836 constructor: Sprite,
25840 raycast: function ( raycaster, intersects ) {
25842 if ( raycaster.camera === null ) {
25844 console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
25848 _worldScale.setFromMatrixScale( this.matrixWorld );
25850 _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
25851 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
25853 _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
25855 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
25857 _worldScale.multiplyScalar( - _mvPosition.z );
25861 const rotation = this.material.rotation;
25864 if ( rotation !== 0 ) {
25866 cos = Math.cos( rotation );
25867 sin = Math.sin( rotation );
25871 const center = this.center;
25873 transformVertex( _vA$1.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25874 transformVertex( _vB$1.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25875 transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25877 _uvA$1.set( 0, 0 );
25878 _uvB$1.set( 1, 0 );
25879 _uvC$1.set( 1, 1 );
25881 // check first triangle
25882 let intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint );
25884 if ( intersect === null ) {
25886 // check second triangle
25887 transformVertex( _vB$1.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
25888 _uvB$1.set( 0, 1 );
25890 intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint );
25891 if ( intersect === null ) {
25899 const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
25901 if ( distance < raycaster.near || distance > raycaster.far ) return;
25905 distance: distance,
25906 point: _intersectPoint.clone(),
25907 uv: Triangle.getUV( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ),
25915 copy: function ( source ) {
25917 Object3D.prototype.copy.call( this, source );
25919 if ( source.center !== undefined ) this.center.copy( source.center );
25921 this.material = source.material;
25929 function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
25931 // compute position in camera space
25932 _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
25934 // to check if rotation is not zero
25935 if ( sin !== undefined ) {
25937 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
25938 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
25942 _rotatedPosition.copy( _alignedPosition );
25947 vertexPosition.copy( mvPosition );
25948 vertexPosition.x += _rotatedPosition.x;
25949 vertexPosition.y += _rotatedPosition.y;
25951 // transform to world space
25952 vertexPosition.applyMatrix4( _viewWorldMatrix );
25956 const _v1$4 = new Vector3();
25957 const _v2$2 = new Vector3();
25961 Object3D.call( this );
25963 this._currentLevel = 0;
25967 Object.defineProperties( this, {
25974 this.autoUpdate = true;
25978 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
25984 copy: function ( source ) {
25986 Object3D.prototype.copy.call( this, source, false );
25988 const levels = source.levels;
25990 for ( let i = 0, l = levels.length; i < l; i ++ ) {
25992 const level = levels[ i ];
25994 this.addLevel( level.object.clone(), level.distance );
25998 this.autoUpdate = source.autoUpdate;
26004 addLevel: function ( object, distance = 0 ) {
26006 distance = Math.abs( distance );
26008 const levels = this.levels;
26012 for ( l = 0; l < levels.length; l ++ ) {
26014 if ( distance < levels[ l ].distance ) {
26022 levels.splice( l, 0, { distance: distance, object: object } );
26024 this.add( object );
26030 getCurrentLevel: function () {
26032 return this._currentLevel;
26036 getObjectForDistance: function ( distance ) {
26038 const levels = this.levels;
26040 if ( levels.length > 0 ) {
26044 for ( i = 1, l = levels.length; i < l; i ++ ) {
26046 if ( distance < levels[ i ].distance ) {
26054 return levels[ i - 1 ].object;
26062 raycast: function ( raycaster, intersects ) {
26064 const levels = this.levels;
26066 if ( levels.length > 0 ) {
26068 _v1$4.setFromMatrixPosition( this.matrixWorld );
26070 const distance = raycaster.ray.origin.distanceTo( _v1$4 );
26072 this.getObjectForDistance( distance ).raycast( raycaster, intersects );
26078 update: function ( camera ) {
26080 const levels = this.levels;
26082 if ( levels.length > 1 ) {
26084 _v1$4.setFromMatrixPosition( camera.matrixWorld );
26085 _v2$2.setFromMatrixPosition( this.matrixWorld );
26087 const distance = _v1$4.distanceTo( _v2$2 ) / camera.zoom;
26089 levels[ 0 ].object.visible = true;
26093 for ( i = 1, l = levels.length; i < l; i ++ ) {
26095 if ( distance >= levels[ i ].distance ) {
26097 levels[ i - 1 ].object.visible = false;
26098 levels[ i ].object.visible = true;
26108 this._currentLevel = i - 1;
26110 for ( ; i < l; i ++ ) {
26112 levels[ i ].object.visible = false;
26120 toJSON: function ( meta ) {
26122 const data = Object3D.prototype.toJSON.call( this, meta );
26124 if ( this.autoUpdate === false ) data.object.autoUpdate = false;
26126 data.object.levels = [];
26128 const levels = this.levels;
26130 for ( let i = 0, l = levels.length; i < l; i ++ ) {
26132 const level = levels[ i ];
26134 data.object.levels.push( {
26135 object: level.object.uuid,
26136 distance: level.distance
26147 function SkinnedMesh( geometry, material ) {
26149 if ( geometry && geometry.isGeometry ) {
26151 console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
26155 Mesh.call( this, geometry, material );
26157 this.type = 'SkinnedMesh';
26159 this.bindMode = 'attached';
26160 this.bindMatrix = new Matrix4();
26161 this.bindMatrixInverse = new Matrix4();
26165 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
26167 constructor: SkinnedMesh,
26169 isSkinnedMesh: true,
26171 copy: function ( source ) {
26173 Mesh.prototype.copy.call( this, source );
26175 this.bindMode = source.bindMode;
26176 this.bindMatrix.copy( source.bindMatrix );
26177 this.bindMatrixInverse.copy( source.bindMatrixInverse );
26179 this.skeleton = source.skeleton;
26185 bind: function ( skeleton, bindMatrix ) {
26187 this.skeleton = skeleton;
26189 if ( bindMatrix === undefined ) {
26191 this.updateMatrixWorld( true );
26193 this.skeleton.calculateInverses();
26195 bindMatrix = this.matrixWorld;
26199 this.bindMatrix.copy( bindMatrix );
26200 this.bindMatrixInverse.copy( bindMatrix ).invert();
26204 pose: function () {
26206 this.skeleton.pose();
26210 normalizeSkinWeights: function () {
26212 const vector = new Vector4();
26214 const skinWeight = this.geometry.attributes.skinWeight;
26216 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
26218 vector.x = skinWeight.getX( i );
26219 vector.y = skinWeight.getY( i );
26220 vector.z = skinWeight.getZ( i );
26221 vector.w = skinWeight.getW( i );
26223 const scale = 1.0 / vector.manhattanLength();
26225 if ( scale !== Infinity ) {
26227 vector.multiplyScalar( scale );
26231 vector.set( 1, 0, 0, 0 ); // do something reasonable
26235 skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
26241 updateMatrixWorld: function ( force ) {
26243 Mesh.prototype.updateMatrixWorld.call( this, force );
26245 if ( this.bindMode === 'attached' ) {
26247 this.bindMatrixInverse.copy( this.matrixWorld ).invert();
26249 } else if ( this.bindMode === 'detached' ) {
26251 this.bindMatrixInverse.copy( this.bindMatrix ).invert();
26255 console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
26261 boneTransform: ( function () {
26263 const basePosition = new Vector3();
26265 const skinIndex = new Vector4();
26266 const skinWeight = new Vector4();
26268 const vector = new Vector3();
26269 const matrix = new Matrix4();
26271 return function ( index, target ) {
26273 const skeleton = this.skeleton;
26274 const geometry = this.geometry;
26276 skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
26277 skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
26279 basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
26281 target.set( 0, 0, 0 );
26283 for ( let i = 0; i < 4; i ++ ) {
26285 const weight = skinWeight.getComponent( i );
26287 if ( weight !== 0 ) {
26289 const boneIndex = skinIndex.getComponent( i );
26291 matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
26293 target.addScaledVector( vector.copy( basePosition ).applyMatrix4( matrix ), weight );
26299 return target.applyMatrix4( this.bindMatrixInverse );
26309 Object3D.call( this );
26311 this.type = 'Bone';
26315 Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
26323 const _offsetMatrix = new Matrix4();
26324 const _identityMatrix = new Matrix4();
26326 function Skeleton( bones = [], boneInverses = [] ) {
26328 this.uuid = MathUtils.generateUUID();
26330 this.bones = bones.slice( 0 );
26331 this.boneInverses = boneInverses;
26332 this.boneMatrices = null;
26334 this.boneTexture = null;
26335 this.boneTextureSize = 0;
26343 Object.assign( Skeleton.prototype, {
26345 init: function () {
26347 const bones = this.bones;
26348 const boneInverses = this.boneInverses;
26350 this.boneMatrices = new Float32Array( bones.length * 16 );
26352 // calculate inverse bone matrices if necessary
26354 if ( boneInverses.length === 0 ) {
26356 this.calculateInverses();
26360 // handle special case
26362 if ( bones.length !== boneInverses.length ) {
26364 console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
26366 this.boneInverses = [];
26368 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26370 this.boneInverses.push( new Matrix4() );
26380 calculateInverses: function () {
26382 this.boneInverses.length = 0;
26384 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26386 const inverse = new Matrix4();
26388 if ( this.bones[ i ] ) {
26390 inverse.copy( this.bones[ i ].matrixWorld ).invert();
26394 this.boneInverses.push( inverse );
26400 pose: function () {
26402 // recover the bind-time world matrices
26404 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26406 const bone = this.bones[ i ];
26410 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
26416 // compute the local matrices, positions, rotations and scales
26418 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26420 const bone = this.bones[ i ];
26424 if ( bone.parent && bone.parent.isBone ) {
26426 bone.matrix.copy( bone.parent.matrixWorld ).invert();
26427 bone.matrix.multiply( bone.matrixWorld );
26431 bone.matrix.copy( bone.matrixWorld );
26435 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
26443 update: function () {
26445 const bones = this.bones;
26446 const boneInverses = this.boneInverses;
26447 const boneMatrices = this.boneMatrices;
26448 const boneTexture = this.boneTexture;
26450 // flatten bone matrices to array
26452 for ( let i = 0, il = bones.length; i < il; i ++ ) {
26454 // compute the offset between the current and the original transform
26456 const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix;
26458 _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
26459 _offsetMatrix.toArray( boneMatrices, i * 16 );
26463 if ( boneTexture !== null ) {
26465 boneTexture.needsUpdate = true;
26471 clone: function () {
26473 return new Skeleton( this.bones, this.boneInverses );
26477 getBoneByName: function ( name ) {
26479 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
26481 const bone = this.bones[ i ];
26483 if ( bone.name === name ) {
26495 dispose: function ( ) {
26497 if ( this.boneTexture !== null ) {
26499 this.boneTexture.dispose();
26501 this.boneTexture = null;
26507 fromJSON: function ( json, bones ) {
26509 this.uuid = json.uuid;
26511 for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
26513 const uuid = json.bones[ i ];
26514 let bone = bones[ uuid ];
26516 if ( bone === undefined ) {
26518 console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
26523 this.bones.push( bone );
26524 this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
26534 toJSON: function () {
26540 generator: 'Skeleton.toJSON'
26546 data.uuid = this.uuid;
26548 const bones = this.bones;
26549 const boneInverses = this.boneInverses;
26551 for ( let i = 0, l = bones.length; i < l; i ++ ) {
26553 const bone = bones[ i ];
26554 data.bones.push( bone.uuid );
26556 const boneInverse = boneInverses[ i ];
26557 data.boneInverses.push( boneInverse.toArray() );
26567 const _instanceLocalMatrix = new Matrix4();
26568 const _instanceWorldMatrix = new Matrix4();
26570 const _instanceIntersects = [];
26572 const _mesh = new Mesh();
26574 function InstancedMesh( geometry, material, count ) {
26576 Mesh.call( this, geometry, material );
26578 this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
26579 this.instanceColor = null;
26581 this.count = count;
26583 this.frustumCulled = false;
26587 InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
26589 constructor: InstancedMesh,
26591 isInstancedMesh: true,
26593 copy: function ( source ) {
26595 Mesh.prototype.copy.call( this, source );
26597 this.instanceMatrix.copy( source.instanceMatrix );
26598 this.count = source.count;
26604 getColorAt: function ( index, color ) {
26606 color.fromArray( this.instanceColor.array, index * 3 );
26610 getMatrixAt: function ( index, matrix ) {
26612 matrix.fromArray( this.instanceMatrix.array, index * 16 );
26616 raycast: function ( raycaster, intersects ) {
26618 const matrixWorld = this.matrixWorld;
26619 const raycastTimes = this.count;
26621 _mesh.geometry = this.geometry;
26622 _mesh.material = this.material;
26624 if ( _mesh.material === undefined ) return;
26626 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
26628 // calculate the world matrix for each instance
26630 this.getMatrixAt( instanceId, _instanceLocalMatrix );
26632 _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
26634 // the mesh represents this single instance
26636 _mesh.matrixWorld = _instanceWorldMatrix;
26638 _mesh.raycast( raycaster, _instanceIntersects );
26640 // process the result of raycast
26642 for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
26644 const intersect = _instanceIntersects[ i ];
26645 intersect.instanceId = instanceId;
26646 intersect.object = this;
26647 intersects.push( intersect );
26651 _instanceIntersects.length = 0;
26657 setColorAt: function ( index, color ) {
26659 if ( this.instanceColor === null ) {
26661 this.instanceColor = new BufferAttribute( new Float32Array( this.count * 3 ), 3 );
26665 color.toArray( this.instanceColor.array, index * 3 );
26669 setMatrixAt: function ( index, matrix ) {
26671 matrix.toArray( this.instanceMatrix.array, index * 16 );
26675 updateMorphTargets: function () {
26684 * opacity: <float>,
26686 * linewidth: <float>,
26687 * linecap: "round",
26688 * linejoin: "round"
26692 function LineBasicMaterial( parameters ) {
26694 Material.call( this );
26696 this.type = 'LineBasicMaterial';
26698 this.color = new Color( 0xffffff );
26700 this.linewidth = 1;
26701 this.linecap = 'round';
26702 this.linejoin = 'round';
26704 this.morphTargets = false;
26706 this.setValues( parameters );
26710 LineBasicMaterial.prototype = Object.create( Material.prototype );
26711 LineBasicMaterial.prototype.constructor = LineBasicMaterial;
26713 LineBasicMaterial.prototype.isLineBasicMaterial = true;
26715 LineBasicMaterial.prototype.copy = function ( source ) {
26717 Material.prototype.copy.call( this, source );
26719 this.color.copy( source.color );
26721 this.linewidth = source.linewidth;
26722 this.linecap = source.linecap;
26723 this.linejoin = source.linejoin;
26725 this.morphTargets = source.morphTargets;
26731 const _start = new Vector3();
26732 const _end = new Vector3();
26733 const _inverseMatrix$1 = new Matrix4();
26734 const _ray$1 = new Ray();
26735 const _sphere$2 = new Sphere();
26737 function Line( geometry, material, mode ) {
26739 if ( mode === 1 ) {
26741 console.error( 'THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.' );
26745 Object3D.call( this );
26747 this.type = 'Line';
26749 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
26750 this.material = material !== undefined ? material : new LineBasicMaterial();
26752 this.updateMorphTargets();
26756 Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
26762 copy: function ( source ) {
26764 Object3D.prototype.copy.call( this, source );
26766 this.material = source.material;
26767 this.geometry = source.geometry;
26773 computeLineDistances: function () {
26775 const geometry = this.geometry;
26777 if ( geometry.isBufferGeometry ) {
26779 // we assume non-indexed geometry
26781 if ( geometry.index === null ) {
26783 const positionAttribute = geometry.attributes.position;
26784 const lineDistances = [ 0 ];
26786 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
26788 _start.fromBufferAttribute( positionAttribute, i - 1 );
26789 _end.fromBufferAttribute( positionAttribute, i );
26791 lineDistances[ i ] = lineDistances[ i - 1 ];
26792 lineDistances[ i ] += _start.distanceTo( _end );
26796 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
26800 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
26804 } else if ( geometry.isGeometry ) {
26806 const vertices = geometry.vertices;
26807 const lineDistances = geometry.lineDistances;
26809 lineDistances[ 0 ] = 0;
26811 for ( let i = 1, l = vertices.length; i < l; i ++ ) {
26813 lineDistances[ i ] = lineDistances[ i - 1 ];
26814 lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] );
26824 raycast: function ( raycaster, intersects ) {
26826 const geometry = this.geometry;
26827 const matrixWorld = this.matrixWorld;
26828 const threshold = raycaster.params.Line.threshold;
26830 // Checking boundingSphere distance to ray
26832 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
26834 _sphere$2.copy( geometry.boundingSphere );
26835 _sphere$2.applyMatrix4( matrixWorld );
26836 _sphere$2.radius += threshold;
26838 if ( raycaster.ray.intersectsSphere( _sphere$2 ) === false ) return;
26842 _inverseMatrix$1.copy( matrixWorld ).invert();
26843 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
26845 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
26846 const localThresholdSq = localThreshold * localThreshold;
26848 const vStart = new Vector3();
26849 const vEnd = new Vector3();
26850 const interSegment = new Vector3();
26851 const interRay = new Vector3();
26852 const step = this.isLineSegments ? 2 : 1;
26854 if ( geometry.isBufferGeometry ) {
26856 const index = geometry.index;
26857 const attributes = geometry.attributes;
26858 const positionAttribute = attributes.position;
26860 if ( index !== null ) {
26862 const indices = index.array;
26864 for ( let i = 0, l = indices.length - 1; i < l; i += step ) {
26866 const a = indices[ i ];
26867 const b = indices[ i + 1 ];
26869 vStart.fromBufferAttribute( positionAttribute, a );
26870 vEnd.fromBufferAttribute( positionAttribute, b );
26872 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
26874 if ( distSq > localThresholdSq ) continue;
26876 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
26878 const distance = raycaster.ray.origin.distanceTo( interRay );
26880 if ( distance < raycaster.near || distance > raycaster.far ) continue;
26884 distance: distance,
26885 // What do we want? intersection point on the ray or on the segment??
26886 // point: raycaster.ray.at( distance ),
26887 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
26899 for ( let i = 0, l = positionAttribute.count - 1; i < l; i += step ) {
26901 vStart.fromBufferAttribute( positionAttribute, i );
26902 vEnd.fromBufferAttribute( positionAttribute, i + 1 );
26904 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
26906 if ( distSq > localThresholdSq ) continue;
26908 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
26910 const distance = raycaster.ray.origin.distanceTo( interRay );
26912 if ( distance < raycaster.near || distance > raycaster.far ) continue;
26916 distance: distance,
26917 // What do we want? intersection point on the ray or on the segment??
26918 // point: raycaster.ray.at( distance ),
26919 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
26931 } else if ( geometry.isGeometry ) {
26933 const vertices = geometry.vertices;
26934 const nbVertices = vertices.length;
26936 for ( let i = 0; i < nbVertices - 1; i += step ) {
26938 const distSq = _ray$1.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
26940 if ( distSq > localThresholdSq ) continue;
26942 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
26944 const distance = raycaster.ray.origin.distanceTo( interRay );
26946 if ( distance < raycaster.near || distance > raycaster.far ) continue;
26950 distance: distance,
26951 // What do we want? intersection point on the ray or on the segment??
26952 // point: raycaster.ray.at( distance ),
26953 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
26967 updateMorphTargets: function () {
26969 const geometry = this.geometry;
26971 if ( geometry.isBufferGeometry ) {
26973 const morphAttributes = geometry.morphAttributes;
26974 const keys = Object.keys( morphAttributes );
26976 if ( keys.length > 0 ) {
26978 const morphAttribute = morphAttributes[ keys[ 0 ] ];
26980 if ( morphAttribute !== undefined ) {
26982 this.morphTargetInfluences = [];
26983 this.morphTargetDictionary = {};
26985 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
26987 const name = morphAttribute[ m ].name || String( m );
26989 this.morphTargetInfluences.push( 0 );
26990 this.morphTargetDictionary[ name ] = m;
27000 const morphTargets = geometry.morphTargets;
27002 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
27004 console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
27014 const _start$1 = new Vector3();
27015 const _end$1 = new Vector3();
27017 function LineSegments( geometry, material ) {
27019 Line.call( this, geometry, material );
27021 this.type = 'LineSegments';
27025 LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
27027 constructor: LineSegments,
27029 isLineSegments: true,
27031 computeLineDistances: function () {
27033 const geometry = this.geometry;
27035 if ( geometry.isBufferGeometry ) {
27037 // we assume non-indexed geometry
27039 if ( geometry.index === null ) {
27041 const positionAttribute = geometry.attributes.position;
27042 const lineDistances = [];
27044 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
27046 _start$1.fromBufferAttribute( positionAttribute, i );
27047 _end$1.fromBufferAttribute( positionAttribute, i + 1 );
27049 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
27050 lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
27054 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
27058 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
27062 } else if ( geometry.isGeometry ) {
27064 const vertices = geometry.vertices;
27065 const lineDistances = geometry.lineDistances;
27067 for ( let i = 0, l = vertices.length; i < l; i += 2 ) {
27069 _start$1.copy( vertices[ i ] );
27070 _end$1.copy( vertices[ i + 1 ] );
27072 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
27073 lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
27085 function LineLoop( geometry, material ) {
27087 Line.call( this, geometry, material );
27089 this.type = 'LineLoop';
27093 LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
27095 constructor: LineLoop,
27104 * opacity: <float>,
27105 * map: new THREE.Texture( <Image> ),
27106 * alphaMap: new THREE.Texture( <Image> ),
27109 * sizeAttenuation: <bool>
27111 * morphTargets: <bool>
27115 function PointsMaterial( parameters ) {
27117 Material.call( this );
27119 this.type = 'PointsMaterial';
27121 this.color = new Color( 0xffffff );
27125 this.alphaMap = null;
27128 this.sizeAttenuation = true;
27130 this.morphTargets = false;
27132 this.setValues( parameters );
27136 PointsMaterial.prototype = Object.create( Material.prototype );
27137 PointsMaterial.prototype.constructor = PointsMaterial;
27139 PointsMaterial.prototype.isPointsMaterial = true;
27141 PointsMaterial.prototype.copy = function ( source ) {
27143 Material.prototype.copy.call( this, source );
27145 this.color.copy( source.color );
27147 this.map = source.map;
27149 this.alphaMap = source.alphaMap;
27151 this.size = source.size;
27152 this.sizeAttenuation = source.sizeAttenuation;
27154 this.morphTargets = source.morphTargets;
27160 const _inverseMatrix$2 = new Matrix4();
27161 const _ray$2 = new Ray();
27162 const _sphere$3 = new Sphere();
27163 const _position$1 = new Vector3();
27165 function Points( geometry, material ) {
27167 Object3D.call( this );
27169 this.type = 'Points';
27171 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
27172 this.material = material !== undefined ? material : new PointsMaterial();
27174 this.updateMorphTargets();
27178 Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
27180 constructor: Points,
27184 copy: function ( source ) {
27186 Object3D.prototype.copy.call( this, source );
27188 this.material = source.material;
27189 this.geometry = source.geometry;
27195 raycast: function ( raycaster, intersects ) {
27197 const geometry = this.geometry;
27198 const matrixWorld = this.matrixWorld;
27199 const threshold = raycaster.params.Points.threshold;
27201 // Checking boundingSphere distance to ray
27203 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
27205 _sphere$3.copy( geometry.boundingSphere );
27206 _sphere$3.applyMatrix4( matrixWorld );
27207 _sphere$3.radius += threshold;
27209 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
27213 _inverseMatrix$2.copy( matrixWorld ).invert();
27214 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
27216 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
27217 const localThresholdSq = localThreshold * localThreshold;
27219 if ( geometry.isBufferGeometry ) {
27221 const index = geometry.index;
27222 const attributes = geometry.attributes;
27223 const positionAttribute = attributes.position;
27225 if ( index !== null ) {
27227 const indices = index.array;
27229 for ( let i = 0, il = indices.length; i < il; i ++ ) {
27231 const a = indices[ i ];
27233 _position$1.fromBufferAttribute( positionAttribute, a );
27235 testPoint( _position$1, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
27241 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
27243 _position$1.fromBufferAttribute( positionAttribute, i );
27245 testPoint( _position$1, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
27253 const vertices = geometry.vertices;
27255 for ( let i = 0, l = vertices.length; i < l; i ++ ) {
27257 testPoint( vertices[ i ], i, localThresholdSq, matrixWorld, raycaster, intersects, this );
27265 updateMorphTargets: function () {
27267 const geometry = this.geometry;
27269 if ( geometry.isBufferGeometry ) {
27271 const morphAttributes = geometry.morphAttributes;
27272 const keys = Object.keys( morphAttributes );
27274 if ( keys.length > 0 ) {
27276 const morphAttribute = morphAttributes[ keys[ 0 ] ];
27278 if ( morphAttribute !== undefined ) {
27280 this.morphTargetInfluences = [];
27281 this.morphTargetDictionary = {};
27283 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
27285 const name = morphAttribute[ m ].name || String( m );
27287 this.morphTargetInfluences.push( 0 );
27288 this.morphTargetDictionary[ name ] = m;
27298 const morphTargets = geometry.morphTargets;
27300 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
27302 console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
27312 function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
27314 const rayPointDistanceSq = _ray$2.distanceSqToPoint( point );
27316 if ( rayPointDistanceSq < localThresholdSq ) {
27318 const intersectPoint = new Vector3();
27320 _ray$2.closestPointToPoint( point, intersectPoint );
27321 intersectPoint.applyMatrix4( matrixWorld );
27323 const distance = raycaster.ray.origin.distanceTo( intersectPoint );
27325 if ( distance < raycaster.near || distance > raycaster.far ) return;
27329 distance: distance,
27330 distanceToRay: Math.sqrt( rayPointDistanceSq ),
27331 point: intersectPoint,
27342 function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
27344 Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
27346 this.format = format !== undefined ? format : RGBFormat;
27348 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
27349 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
27351 this.generateMipmaps = false;
27353 const scope = this;
27355 function updateVideo() {
27357 scope.needsUpdate = true;
27358 video.requestVideoFrameCallback( updateVideo );
27362 if ( 'requestVideoFrameCallback' in video ) {
27364 video.requestVideoFrameCallback( updateVideo );
27370 VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), {
27372 constructor: VideoTexture,
27374 clone: function () {
27376 return new this.constructor( this.image ).copy( this );
27380 isVideoTexture: true,
27382 update: function () {
27384 const video = this.image;
27385 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
27387 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
27389 this.needsUpdate = true;
27397 function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
27399 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
27401 this.image = { width: width, height: height };
27402 this.mipmaps = mipmaps;
27404 // no flipping for cube textures
27405 // (also flipping doesn't work for compressed textures )
27407 this.flipY = false;
27409 // can't generate mipmaps for compressed textures
27410 // mips must be embedded in DDS files
27412 this.generateMipmaps = false;
27416 CompressedTexture.prototype = Object.create( Texture.prototype );
27417 CompressedTexture.prototype.constructor = CompressedTexture;
27419 CompressedTexture.prototype.isCompressedTexture = true;
27421 function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
27423 Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
27425 this.needsUpdate = true;
27429 CanvasTexture.prototype = Object.create( Texture.prototype );
27430 CanvasTexture.prototype.constructor = CanvasTexture;
27431 CanvasTexture.prototype.isCanvasTexture = true;
27433 function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
27435 format = format !== undefined ? format : DepthFormat;
27437 if ( format !== DepthFormat && format !== DepthStencilFormat ) {
27439 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
27443 if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
27444 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
27446 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
27448 this.image = { width: width, height: height };
27450 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
27451 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
27453 this.flipY = false;
27454 this.generateMipmaps = false;
27458 DepthTexture.prototype = Object.create( Texture.prototype );
27459 DepthTexture.prototype.constructor = DepthTexture;
27460 DepthTexture.prototype.isDepthTexture = true;
27462 let _geometryId = 0; // Geometry uses even numbers as Id
27463 const _m1$3 = new Matrix4();
27464 const _obj$1 = new Object3D();
27465 const _offset$1 = new Vector3();
27467 function Geometry() {
27469 Object.defineProperty( this, 'id', { value: _geometryId += 2 } );
27471 this.uuid = MathUtils.generateUUID();
27474 this.type = 'Geometry';
27476 this.vertices = [];
27479 this.faceVertexUvs = [[]];
27481 this.morphTargets = [];
27482 this.morphNormals = [];
27484 this.skinWeights = [];
27485 this.skinIndices = [];
27487 this.lineDistances = [];
27489 this.boundingBox = null;
27490 this.boundingSphere = null;
27494 this.elementsNeedUpdate = false;
27495 this.verticesNeedUpdate = false;
27496 this.uvsNeedUpdate = false;
27497 this.normalsNeedUpdate = false;
27498 this.colorsNeedUpdate = false;
27499 this.lineDistancesNeedUpdate = false;
27500 this.groupsNeedUpdate = false;
27504 Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
27506 constructor: Geometry,
27510 applyMatrix4: function ( matrix ) {
27512 const normalMatrix = new Matrix3().getNormalMatrix( matrix );
27514 for ( let i = 0, il = this.vertices.length; i < il; i ++ ) {
27516 const vertex = this.vertices[ i ];
27517 vertex.applyMatrix4( matrix );
27521 for ( let i = 0, il = this.faces.length; i < il; i ++ ) {
27523 const face = this.faces[ i ];
27524 face.normal.applyMatrix3( normalMatrix ).normalize();
27526 for ( let j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
27528 face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
27534 if ( this.boundingBox !== null ) {
27536 this.computeBoundingBox();
27540 if ( this.boundingSphere !== null ) {
27542 this.computeBoundingSphere();
27546 this.verticesNeedUpdate = true;
27547 this.normalsNeedUpdate = true;
27553 rotateX: function ( angle ) {
27555 // rotate geometry around world x-axis
27557 _m1$3.makeRotationX( angle );
27559 this.applyMatrix4( _m1$3 );
27565 rotateY: function ( angle ) {
27567 // rotate geometry around world y-axis
27569 _m1$3.makeRotationY( angle );
27571 this.applyMatrix4( _m1$3 );
27577 rotateZ: function ( angle ) {
27579 // rotate geometry around world z-axis
27581 _m1$3.makeRotationZ( angle );
27583 this.applyMatrix4( _m1$3 );
27589 translate: function ( x, y, z ) {
27591 // translate geometry
27593 _m1$3.makeTranslation( x, y, z );
27595 this.applyMatrix4( _m1$3 );
27601 scale: function ( x, y, z ) {
27605 _m1$3.makeScale( x, y, z );
27607 this.applyMatrix4( _m1$3 );
27613 lookAt: function ( vector ) {
27615 _obj$1.lookAt( vector );
27617 _obj$1.updateMatrix();
27619 this.applyMatrix4( _obj$1.matrix );
27625 fromBufferGeometry: function ( geometry ) {
27627 const scope = this;
27629 const index = geometry.index !== null ? geometry.index : undefined;
27630 const attributes = geometry.attributes;
27632 if ( attributes.position === undefined ) {
27634 console.error( 'THREE.Geometry.fromBufferGeometry(): Position attribute required for conversion.' );
27639 const position = attributes.position;
27640 const normal = attributes.normal;
27641 const color = attributes.color;
27642 const uv = attributes.uv;
27643 const uv2 = attributes.uv2;
27645 if ( uv2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
27647 for ( let i = 0; i < position.count; i ++ ) {
27649 scope.vertices.push( new Vector3().fromBufferAttribute( position, i ) );
27651 if ( color !== undefined ) {
27653 scope.colors.push( new Color().fromBufferAttribute( color, i ) );
27659 function addFace( a, b, c, materialIndex ) {
27661 const vertexColors = ( color === undefined ) ? [] : [
27662 scope.colors[ a ].clone(),
27663 scope.colors[ b ].clone(),
27664 scope.colors[ c ].clone()
27667 const vertexNormals = ( normal === undefined ) ? [] : [
27668 new Vector3().fromBufferAttribute( normal, a ),
27669 new Vector3().fromBufferAttribute( normal, b ),
27670 new Vector3().fromBufferAttribute( normal, c )
27673 const face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
27675 scope.faces.push( face );
27677 if ( uv !== undefined ) {
27679 scope.faceVertexUvs[ 0 ].push( [
27680 new Vector2().fromBufferAttribute( uv, a ),
27681 new Vector2().fromBufferAttribute( uv, b ),
27682 new Vector2().fromBufferAttribute( uv, c )
27687 if ( uv2 !== undefined ) {
27689 scope.faceVertexUvs[ 1 ].push( [
27690 new Vector2().fromBufferAttribute( uv2, a ),
27691 new Vector2().fromBufferAttribute( uv2, b ),
27692 new Vector2().fromBufferAttribute( uv2, c )
27699 const groups = geometry.groups;
27701 if ( groups.length > 0 ) {
27703 for ( let i = 0; i < groups.length; i ++ ) {
27705 const group = groups[ i ];
27707 const start = group.start;
27708 const count = group.count;
27710 for ( let j = start, jl = start + count; j < jl; j += 3 ) {
27712 if ( index !== undefined ) {
27714 addFace( index.getX( j ), index.getX( j + 1 ), index.getX( j + 2 ), group.materialIndex );
27718 addFace( j, j + 1, j + 2, group.materialIndex );
27728 if ( index !== undefined ) {
27730 for ( let i = 0; i < index.count; i += 3 ) {
27732 addFace( index.getX( i ), index.getX( i + 1 ), index.getX( i + 2 ) );
27738 for ( let i = 0; i < position.count; i += 3 ) {
27740 addFace( i, i + 1, i + 2 );
27748 this.computeFaceNormals();
27750 if ( geometry.boundingBox !== null ) {
27752 this.boundingBox = geometry.boundingBox.clone();
27756 if ( geometry.boundingSphere !== null ) {
27758 this.boundingSphere = geometry.boundingSphere.clone();
27766 center: function () {
27768 this.computeBoundingBox();
27770 this.boundingBox.getCenter( _offset$1 ).negate();
27772 this.translate( _offset$1.x, _offset$1.y, _offset$1.z );
27778 normalize: function () {
27780 this.computeBoundingSphere();
27782 const center = this.boundingSphere.center;
27783 const radius = this.boundingSphere.radius;
27785 const s = radius === 0 ? 1 : 1.0 / radius;
27787 const matrix = new Matrix4();
27789 s, 0, 0, - s * center.x,
27790 0, s, 0, - s * center.y,
27791 0, 0, s, - s * center.z,
27795 this.applyMatrix4( matrix );
27801 computeFaceNormals: function () {
27803 const cb = new Vector3(), ab = new Vector3();
27805 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27807 const face = this.faces[ f ];
27809 const vA = this.vertices[ face.a ];
27810 const vB = this.vertices[ face.b ];
27811 const vC = this.vertices[ face.c ];
27813 cb.subVectors( vC, vB );
27814 ab.subVectors( vA, vB );
27819 face.normal.copy( cb );
27825 computeVertexNormals: function ( areaWeighted = true ) {
27827 const vertices = new Array( this.vertices.length );
27829 for ( let v = 0, vl = this.vertices.length; v < vl; v ++ ) {
27831 vertices[ v ] = new Vector3();
27835 if ( areaWeighted ) {
27837 // vertex normals weighted by triangle areas
27838 // http://www.iquilezles.org/www/articles/normals/normals.htm
27840 const cb = new Vector3(), ab = new Vector3();
27842 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27844 const face = this.faces[ f ];
27846 const vA = this.vertices[ face.a ];
27847 const vB = this.vertices[ face.b ];
27848 const vC = this.vertices[ face.c ];
27850 cb.subVectors( vC, vB );
27851 ab.subVectors( vA, vB );
27854 vertices[ face.a ].add( cb );
27855 vertices[ face.b ].add( cb );
27856 vertices[ face.c ].add( cb );
27862 this.computeFaceNormals();
27864 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27866 const face = this.faces[ f ];
27868 vertices[ face.a ].add( face.normal );
27869 vertices[ face.b ].add( face.normal );
27870 vertices[ face.c ].add( face.normal );
27876 for ( let v = 0, vl = this.vertices.length; v < vl; v ++ ) {
27878 vertices[ v ].normalize();
27882 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27884 const face = this.faces[ f ];
27886 const vertexNormals = face.vertexNormals;
27888 if ( vertexNormals.length === 3 ) {
27890 vertexNormals[ 0 ].copy( vertices[ face.a ] );
27891 vertexNormals[ 1 ].copy( vertices[ face.b ] );
27892 vertexNormals[ 2 ].copy( vertices[ face.c ] );
27896 vertexNormals[ 0 ] = vertices[ face.a ].clone();
27897 vertexNormals[ 1 ] = vertices[ face.b ].clone();
27898 vertexNormals[ 2 ] = vertices[ face.c ].clone();
27904 if ( this.faces.length > 0 ) {
27906 this.normalsNeedUpdate = true;
27912 computeFlatVertexNormals: function () {
27914 this.computeFaceNormals();
27916 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27918 const face = this.faces[ f ];
27920 const vertexNormals = face.vertexNormals;
27922 if ( vertexNormals.length === 3 ) {
27924 vertexNormals[ 0 ].copy( face.normal );
27925 vertexNormals[ 1 ].copy( face.normal );
27926 vertexNormals[ 2 ].copy( face.normal );
27930 vertexNormals[ 0 ] = face.normal.clone();
27931 vertexNormals[ 1 ] = face.normal.clone();
27932 vertexNormals[ 2 ] = face.normal.clone();
27938 if ( this.faces.length > 0 ) {
27940 this.normalsNeedUpdate = true;
27946 computeMorphNormals: function () {
27948 // save original normals
27949 // - create temp variables on first access
27950 // otherwise just copy (for faster repeated calls)
27952 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
27954 const face = this.faces[ f ];
27956 if ( ! face.__originalFaceNormal ) {
27958 face.__originalFaceNormal = face.normal.clone();
27962 face.__originalFaceNormal.copy( face.normal );
27966 if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
27968 for ( let i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
27970 if ( ! face.__originalVertexNormals[ i ] ) {
27972 face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
27976 face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
27984 // use temp geometry to compute face and vertex normals for each morph
27986 const tmpGeo = new Geometry();
27987 tmpGeo.faces = this.faces;
27989 for ( let i = 0, il = this.morphTargets.length; i < il; i ++ ) {
27991 // create on first access
27993 if ( ! this.morphNormals[ i ] ) {
27995 this.morphNormals[ i ] = {};
27996 this.morphNormals[ i ].faceNormals = [];
27997 this.morphNormals[ i ].vertexNormals = [];
27999 const dstNormalsFace = this.morphNormals[ i ].faceNormals;
28000 const dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
28002 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
28004 const faceNormal = new Vector3();
28005 const vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
28007 dstNormalsFace.push( faceNormal );
28008 dstNormalsVertex.push( vertexNormals );
28014 const morphNormals = this.morphNormals[ i ];
28016 // set vertices to morph target
28018 tmpGeo.vertices = this.morphTargets[ i ].vertices;
28020 // compute morph normals
28022 tmpGeo.computeFaceNormals();
28023 tmpGeo.computeVertexNormals();
28025 // store morph normals
28027 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
28029 const face = this.faces[ f ];
28031 const faceNormal = morphNormals.faceNormals[ f ];
28032 const vertexNormals = morphNormals.vertexNormals[ f ];
28034 faceNormal.copy( face.normal );
28036 vertexNormals.a.copy( face.vertexNormals[ 0 ] );
28037 vertexNormals.b.copy( face.vertexNormals[ 1 ] );
28038 vertexNormals.c.copy( face.vertexNormals[ 2 ] );
28044 // restore original normals
28046 for ( let f = 0, fl = this.faces.length; f < fl; f ++ ) {
28048 const face = this.faces[ f ];
28050 face.normal = face.__originalFaceNormal;
28051 face.vertexNormals = face.__originalVertexNormals;
28057 computeBoundingBox: function () {
28059 if ( this.boundingBox === null ) {
28061 this.boundingBox = new Box3();
28065 this.boundingBox.setFromPoints( this.vertices );
28069 computeBoundingSphere: function () {
28071 if ( this.boundingSphere === null ) {
28073 this.boundingSphere = new Sphere();
28077 this.boundingSphere.setFromPoints( this.vertices );
28081 merge: function ( geometry, matrix, materialIndexOffset = 0 ) {
28083 if ( ! ( geometry && geometry.isGeometry ) ) {
28085 console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
28091 const vertexOffset = this.vertices.length,
28092 vertices1 = this.vertices,
28093 vertices2 = geometry.vertices,
28094 faces1 = this.faces,
28095 faces2 = geometry.faces,
28096 colors1 = this.colors,
28097 colors2 = geometry.colors;
28099 if ( matrix !== undefined ) {
28101 normalMatrix = new Matrix3().getNormalMatrix( matrix );
28107 for ( let i = 0, il = vertices2.length; i < il; i ++ ) {
28109 const vertex = vertices2[ i ];
28111 const vertexCopy = vertex.clone();
28113 if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
28115 vertices1.push( vertexCopy );
28121 for ( let i = 0, il = colors2.length; i < il; i ++ ) {
28123 colors1.push( colors2[ i ].clone() );
28129 for ( let i = 0, il = faces2.length; i < il; i ++ ) {
28131 const face = faces2[ i ];
28133 const faceVertexNormals = face.vertexNormals,
28134 faceVertexColors = face.vertexColors;
28136 const faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
28137 faceCopy.normal.copy( face.normal );
28139 if ( normalMatrix !== undefined ) {
28141 faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
28145 for ( let j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
28147 normal = faceVertexNormals[ j ].clone();
28149 if ( normalMatrix !== undefined ) {
28151 normal.applyMatrix3( normalMatrix ).normalize();
28155 faceCopy.vertexNormals.push( normal );
28159 faceCopy.color.copy( face.color );
28161 for ( let j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
28163 color = faceVertexColors[ j ];
28164 faceCopy.vertexColors.push( color.clone() );
28168 faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
28170 faces1.push( faceCopy );
28176 for ( let i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
28178 const faceVertexUvs2 = geometry.faceVertexUvs[ i ];
28180 if ( this.faceVertexUvs[ i ] === undefined ) this.faceVertexUvs[ i ] = [];
28182 for ( let j = 0, jl = faceVertexUvs2.length; j < jl; j ++ ) {
28184 const uvs2 = faceVertexUvs2[ j ], uvsCopy = [];
28186 for ( let k = 0, kl = uvs2.length; k < kl; k ++ ) {
28188 uvsCopy.push( uvs2[ k ].clone() );
28192 this.faceVertexUvs[ i ].push( uvsCopy );
28200 mergeMesh: function ( mesh ) {
28202 if ( ! ( mesh && mesh.isMesh ) ) {
28204 console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
28209 if ( mesh.matrixAutoUpdate ) mesh.updateMatrix();
28211 this.merge( mesh.geometry, mesh.matrix );
28216 * Checks for duplicate vertices with hashmap.
28217 * Duplicated vertices are removed
28218 * and faces' vertices are updated.
28221 mergeVertices: function ( precisionPoints = 4 ) {
28223 const verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
28224 const unique = [], changes = [];
28226 const precision = Math.pow( 10, precisionPoints );
28228 for ( let i = 0, il = this.vertices.length; i < il; i ++ ) {
28230 const v = this.vertices[ i ];
28231 const key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
28233 if ( verticesMap[ key ] === undefined ) {
28235 verticesMap[ key ] = i;
28236 unique.push( this.vertices[ i ] );
28237 changes[ i ] = unique.length - 1;
28241 //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
28242 changes[ i ] = changes[ verticesMap[ key ] ];
28249 // if faces are completely degenerate after merging vertices, we
28250 // have to remove them from the geometry.
28251 const faceIndicesToRemove = [];
28253 for ( let i = 0, il = this.faces.length; i < il; i ++ ) {
28255 const face = this.faces[ i ];
28257 face.a = changes[ face.a ];
28258 face.b = changes[ face.b ];
28259 face.c = changes[ face.c ];
28261 const indices = [ face.a, face.b, face.c ];
28263 // if any duplicate vertices are found in a Face3
28264 // we have to remove the face as nothing can be saved
28265 for ( let n = 0; n < 3; n ++ ) {
28267 if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
28269 faceIndicesToRemove.push( i );
28278 for ( let i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
28280 const idx = faceIndicesToRemove[ i ];
28282 this.faces.splice( idx, 1 );
28284 for ( let j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
28286 this.faceVertexUvs[ j ].splice( idx, 1 );
28292 // Use unique set of vertices
28294 const diff = this.vertices.length - unique.length;
28295 this.vertices = unique;
28300 setFromPoints: function ( points ) {
28302 this.vertices = [];
28304 for ( let i = 0, l = points.length; i < l; i ++ ) {
28306 const point = points[ i ];
28307 this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
28315 sortFacesByMaterialIndex: function () {
28317 const faces = this.faces;
28318 const length = faces.length;
28322 for ( let i = 0; i < length; i ++ ) {
28324 faces[ i ]._id = i;
28330 function materialIndexSort( a, b ) {
28332 return a.materialIndex - b.materialIndex;
28336 faces.sort( materialIndexSort );
28340 const uvs1 = this.faceVertexUvs[ 0 ];
28341 const uvs2 = this.faceVertexUvs[ 1 ];
28343 let newUvs1, newUvs2;
28345 if ( uvs1 && uvs1.length === length ) newUvs1 = [];
28346 if ( uvs2 && uvs2.length === length ) newUvs2 = [];
28348 for ( let i = 0; i < length; i ++ ) {
28350 const id = faces[ i ]._id;
28352 if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
28353 if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
28357 if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
28358 if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
28362 toJSON: function () {
28368 generator: 'Geometry.toJSON'
28372 // standard Geometry serialization
28374 data.uuid = this.uuid;
28375 data.type = this.type;
28376 if ( this.name !== '' ) data.name = this.name;
28378 if ( this.parameters !== undefined ) {
28380 const parameters = this.parameters;
28382 for ( const key in parameters ) {
28384 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
28392 const vertices = [];
28394 for ( let i = 0; i < this.vertices.length; i ++ ) {
28396 const vertex = this.vertices[ i ];
28397 vertices.push( vertex.x, vertex.y, vertex.z );
28402 const normals = [];
28403 const normalsHash = {};
28405 const colorsHash = {};
28407 const uvsHash = {};
28409 for ( let i = 0; i < this.faces.length; i ++ ) {
28411 const face = this.faces[ i ];
28413 const hasMaterial = true;
28414 const hasFaceUv = false; // deprecated
28415 const hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
28416 const hasFaceNormal = face.normal.length() > 0;
28417 const hasFaceVertexNormal = face.vertexNormals.length > 0;
28418 const hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
28419 const hasFaceVertexColor = face.vertexColors.length > 0;
28423 faceType = setBit( faceType, 0, 0 ); // isQuad
28424 faceType = setBit( faceType, 1, hasMaterial );
28425 faceType = setBit( faceType, 2, hasFaceUv );
28426 faceType = setBit( faceType, 3, hasFaceVertexUv );
28427 faceType = setBit( faceType, 4, hasFaceNormal );
28428 faceType = setBit( faceType, 5, hasFaceVertexNormal );
28429 faceType = setBit( faceType, 6, hasFaceColor );
28430 faceType = setBit( faceType, 7, hasFaceVertexColor );
28432 faces.push( faceType );
28433 faces.push( face.a, face.b, face.c );
28434 faces.push( face.materialIndex );
28436 if ( hasFaceVertexUv ) {
28438 const faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
28441 getUvIndex( faceVertexUvs[ 0 ] ),
28442 getUvIndex( faceVertexUvs[ 1 ] ),
28443 getUvIndex( faceVertexUvs[ 2 ] )
28448 if ( hasFaceNormal ) {
28450 faces.push( getNormalIndex( face.normal ) );
28454 if ( hasFaceVertexNormal ) {
28456 const vertexNormals = face.vertexNormals;
28459 getNormalIndex( vertexNormals[ 0 ] ),
28460 getNormalIndex( vertexNormals[ 1 ] ),
28461 getNormalIndex( vertexNormals[ 2 ] )
28466 if ( hasFaceColor ) {
28468 faces.push( getColorIndex( face.color ) );
28472 if ( hasFaceVertexColor ) {
28474 const vertexColors = face.vertexColors;
28477 getColorIndex( vertexColors[ 0 ] ),
28478 getColorIndex( vertexColors[ 1 ] ),
28479 getColorIndex( vertexColors[ 2 ] )
28486 function setBit( value, position, enabled ) {
28488 return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
28492 function getNormalIndex( normal ) {
28494 const hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
28496 if ( normalsHash[ hash ] !== undefined ) {
28498 return normalsHash[ hash ];
28502 normalsHash[ hash ] = normals.length / 3;
28503 normals.push( normal.x, normal.y, normal.z );
28505 return normalsHash[ hash ];
28509 function getColorIndex( color ) {
28511 const hash = color.r.toString() + color.g.toString() + color.b.toString();
28513 if ( colorsHash[ hash ] !== undefined ) {
28515 return colorsHash[ hash ];
28519 colorsHash[ hash ] = colors.length;
28520 colors.push( color.getHex() );
28522 return colorsHash[ hash ];
28526 function getUvIndex( uv ) {
28528 const hash = uv.x.toString() + uv.y.toString();
28530 if ( uvsHash[ hash ] !== undefined ) {
28532 return uvsHash[ hash ];
28536 uvsHash[ hash ] = uvs.length / 2;
28537 uvs.push( uv.x, uv.y );
28539 return uvsHash[ hash ];
28545 data.data.vertices = vertices;
28546 data.data.normals = normals;
28547 if ( colors.length > 0 ) data.data.colors = colors;
28548 if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
28549 data.data.faces = faces;
28555 clone: function () {
28558 // Handle primitives
28560 const parameters = this.parameters;
28562 if ( parameters !== undefined ) {
28566 for ( const key in parameters ) {
28568 values.push( parameters[ key ] );
28572 const geometry = Object.create( this.constructor.prototype );
28573 this.constructor.apply( geometry, values );
28578 return new this.constructor().copy( this );
28581 return new Geometry().copy( this );
28585 copy: function ( source ) {
28589 this.vertices = [];
28592 this.faceVertexUvs = [[]];
28593 this.morphTargets = [];
28594 this.morphNormals = [];
28595 this.skinWeights = [];
28596 this.skinIndices = [];
28597 this.lineDistances = [];
28598 this.boundingBox = null;
28599 this.boundingSphere = null;
28603 this.name = source.name;
28607 const vertices = source.vertices;
28609 for ( let i = 0, il = vertices.length; i < il; i ++ ) {
28611 this.vertices.push( vertices[ i ].clone() );
28617 const colors = source.colors;
28619 for ( let i = 0, il = colors.length; i < il; i ++ ) {
28621 this.colors.push( colors[ i ].clone() );
28627 const faces = source.faces;
28629 for ( let i = 0, il = faces.length; i < il; i ++ ) {
28631 this.faces.push( faces[ i ].clone() );
28637 for ( let i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
28639 const faceVertexUvs = source.faceVertexUvs[ i ];
28641 if ( this.faceVertexUvs[ i ] === undefined ) {
28643 this.faceVertexUvs[ i ] = [];
28647 for ( let j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
28649 const uvs = faceVertexUvs[ j ], uvsCopy = [];
28651 for ( let k = 0, kl = uvs.length; k < kl; k ++ ) {
28653 const uv = uvs[ k ];
28655 uvsCopy.push( uv.clone() );
28659 this.faceVertexUvs[ i ].push( uvsCopy );
28667 const morphTargets = source.morphTargets;
28669 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
28671 const morphTarget = {};
28672 morphTarget.name = morphTargets[ i ].name;
28676 if ( morphTargets[ i ].vertices !== undefined ) {
28678 morphTarget.vertices = [];
28680 for ( let j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
28682 morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
28690 if ( morphTargets[ i ].normals !== undefined ) {
28692 morphTarget.normals = [];
28694 for ( let j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
28696 morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
28702 this.morphTargets.push( morphTarget );
28708 const morphNormals = source.morphNormals;
28710 for ( let i = 0, il = morphNormals.length; i < il; i ++ ) {
28712 const morphNormal = {};
28716 if ( morphNormals[ i ].vertexNormals !== undefined ) {
28718 morphNormal.vertexNormals = [];
28720 for ( let j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
28722 const srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
28723 const destVertexNormal = {};
28725 destVertexNormal.a = srcVertexNormal.a.clone();
28726 destVertexNormal.b = srcVertexNormal.b.clone();
28727 destVertexNormal.c = srcVertexNormal.c.clone();
28729 morphNormal.vertexNormals.push( destVertexNormal );
28737 if ( morphNormals[ i ].faceNormals !== undefined ) {
28739 morphNormal.faceNormals = [];
28741 for ( let j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
28743 morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
28749 this.morphNormals.push( morphNormal );
28755 const skinWeights = source.skinWeights;
28757 for ( let i = 0, il = skinWeights.length; i < il; i ++ ) {
28759 this.skinWeights.push( skinWeights[ i ].clone() );
28765 const skinIndices = source.skinIndices;
28767 for ( let i = 0, il = skinIndices.length; i < il; i ++ ) {
28769 this.skinIndices.push( skinIndices[ i ].clone() );
28775 const lineDistances = source.lineDistances;
28777 for ( let i = 0, il = lineDistances.length; i < il; i ++ ) {
28779 this.lineDistances.push( lineDistances[ i ] );
28785 const boundingBox = source.boundingBox;
28787 if ( boundingBox !== null ) {
28789 this.boundingBox = boundingBox.clone();
28795 const boundingSphere = source.boundingSphere;
28797 if ( boundingSphere !== null ) {
28799 this.boundingSphere = boundingSphere.clone();
28805 this.elementsNeedUpdate = source.elementsNeedUpdate;
28806 this.verticesNeedUpdate = source.verticesNeedUpdate;
28807 this.uvsNeedUpdate = source.uvsNeedUpdate;
28808 this.normalsNeedUpdate = source.normalsNeedUpdate;
28809 this.colorsNeedUpdate = source.colorsNeedUpdate;
28810 this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
28811 this.groupsNeedUpdate = source.groupsNeedUpdate;
28817 dispose: function () {
28819 this.dispatchEvent( { type: 'dispose' } );
28825 class BoxGeometry extends Geometry {
28827 constructor( width, height, depth, widthSegments, heightSegments, depthSegments ) {
28831 this.type = 'BoxGeometry';
28833 this.parameters = {
28837 widthSegments: widthSegments,
28838 heightSegments: heightSegments,
28839 depthSegments: depthSegments
28842 this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
28843 this.mergeVertices();
28849 class CircleBufferGeometry extends BufferGeometry {
28851 constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) {
28855 this.type = 'CircleBufferGeometry';
28857 this.parameters = {
28859 segments: segments,
28860 thetaStart: thetaStart,
28861 thetaLength: thetaLength
28864 segments = Math.max( 3, segments );
28868 const indices = [];
28869 const vertices = [];
28870 const normals = [];
28873 // helper variables
28875 const vertex = new Vector3();
28876 const uv = new Vector2();
28880 vertices.push( 0, 0, 0 );
28881 normals.push( 0, 0, 1 );
28882 uvs.push( 0.5, 0.5 );
28884 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
28886 const segment = thetaStart + s / segments * thetaLength;
28890 vertex.x = radius * Math.cos( segment );
28891 vertex.y = radius * Math.sin( segment );
28893 vertices.push( vertex.x, vertex.y, vertex.z );
28897 normals.push( 0, 0, 1 );
28901 uv.x = ( vertices[ i ] / radius + 1 ) / 2;
28902 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
28904 uvs.push( uv.x, uv.y );
28910 for ( let i = 1; i <= segments; i ++ ) {
28912 indices.push( i, i + 1, 0 );
28918 this.setIndex( indices );
28919 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28920 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28921 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28927 class CircleGeometry extends Geometry {
28929 constructor( radius, segments, thetaStart, thetaLength ) {
28932 this.type = 'CircleGeometry';
28934 this.parameters = {
28936 segments: segments,
28937 thetaStart: thetaStart,
28938 thetaLength: thetaLength
28941 this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
28942 this.mergeVertices();
28948 class CylinderBufferGeometry extends BufferGeometry {
28950 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
28953 this.type = 'CylinderBufferGeometry';
28955 this.parameters = {
28956 radiusTop: radiusTop,
28957 radiusBottom: radiusBottom,
28959 radialSegments: radialSegments,
28960 heightSegments: heightSegments,
28961 openEnded: openEnded,
28962 thetaStart: thetaStart,
28963 thetaLength: thetaLength
28966 const scope = this;
28968 radialSegments = Math.floor( radialSegments );
28969 heightSegments = Math.floor( heightSegments );
28973 const indices = [];
28974 const vertices = [];
28975 const normals = [];
28978 // helper variables
28981 const indexArray = [];
28982 const halfHeight = height / 2;
28983 let groupStart = 0;
28985 // generate geometry
28989 if ( openEnded === false ) {
28991 if ( radiusTop > 0 ) generateCap( true );
28992 if ( radiusBottom > 0 ) generateCap( false );
28998 this.setIndex( indices );
28999 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29000 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
29001 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
29003 function generateTorso() {
29005 const normal = new Vector3();
29006 const vertex = new Vector3();
29008 let groupCount = 0;
29010 // this will be used to calculate the normal
29011 const slope = ( radiusBottom - radiusTop ) / height;
29013 // generate vertices, normals and uvs
29015 for ( let y = 0; y <= heightSegments; y ++ ) {
29017 const indexRow = [];
29019 const v = y / heightSegments;
29021 // calculate the radius of the current row
29023 const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
29025 for ( let x = 0; x <= radialSegments; x ++ ) {
29027 const u = x / radialSegments;
29029 const theta = u * thetaLength + thetaStart;
29031 const sinTheta = Math.sin( theta );
29032 const cosTheta = Math.cos( theta );
29036 vertex.x = radius * sinTheta;
29037 vertex.y = - v * height + halfHeight;
29038 vertex.z = radius * cosTheta;
29039 vertices.push( vertex.x, vertex.y, vertex.z );
29043 normal.set( sinTheta, slope, cosTheta ).normalize();
29044 normals.push( normal.x, normal.y, normal.z );
29048 uvs.push( u, 1 - v );
29050 // save index of vertex in respective row
29052 indexRow.push( index ++ );
29056 // now save vertices of the row in our index array
29058 indexArray.push( indexRow );
29062 // generate indices
29064 for ( let x = 0; x < radialSegments; x ++ ) {
29066 for ( let y = 0; y < heightSegments; y ++ ) {
29068 // we use the index array to access the correct indices
29070 const a = indexArray[ y ][ x ];
29071 const b = indexArray[ y + 1 ][ x ];
29072 const c = indexArray[ y + 1 ][ x + 1 ];
29073 const d = indexArray[ y ][ x + 1 ];
29077 indices.push( a, b, d );
29078 indices.push( b, c, d );
29080 // update group counter
29088 // add a group to the geometry. this will ensure multi material support
29090 scope.addGroup( groupStart, groupCount, 0 );
29092 // calculate new start value for groups
29094 groupStart += groupCount;
29098 function generateCap( top ) {
29100 // save the index of the first center vertex
29101 const centerIndexStart = index;
29103 const uv = new Vector2();
29104 const vertex = new Vector3();
29106 let groupCount = 0;
29108 const radius = ( top === true ) ? radiusTop : radiusBottom;
29109 const sign = ( top === true ) ? 1 : - 1;
29111 // first we generate the center vertex data of the cap.
29112 // because the geometry needs one set of uvs per face,
29113 // we must generate a center vertex per face/segment
29115 for ( let x = 1; x <= radialSegments; x ++ ) {
29119 vertices.push( 0, halfHeight * sign, 0 );
29123 normals.push( 0, sign, 0 );
29127 uvs.push( 0.5, 0.5 );
29135 // save the index of the last center vertex
29136 const centerIndexEnd = index;
29138 // now we generate the surrounding vertices, normals and uvs
29140 for ( let x = 0; x <= radialSegments; x ++ ) {
29142 const u = x / radialSegments;
29143 const theta = u * thetaLength + thetaStart;
29145 const cosTheta = Math.cos( theta );
29146 const sinTheta = Math.sin( theta );
29150 vertex.x = radius * sinTheta;
29151 vertex.y = halfHeight * sign;
29152 vertex.z = radius * cosTheta;
29153 vertices.push( vertex.x, vertex.y, vertex.z );
29157 normals.push( 0, sign, 0 );
29161 uv.x = ( cosTheta * 0.5 ) + 0.5;
29162 uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
29163 uvs.push( uv.x, uv.y );
29171 // generate indices
29173 for ( let x = 0; x < radialSegments; x ++ ) {
29175 const c = centerIndexStart + x;
29176 const i = centerIndexEnd + x;
29178 if ( top === true ) {
29182 indices.push( i, i + 1, c );
29188 indices.push( i + 1, i, c );
29196 // add a group to the geometry. this will ensure multi material support
29198 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
29200 // calculate new start value for groups
29202 groupStart += groupCount;
29210 class CylinderGeometry extends Geometry {
29212 constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
29215 this.type = 'CylinderGeometry';
29217 this.parameters = {
29218 radiusTop: radiusTop,
29219 radiusBottom: radiusBottom,
29221 radialSegments: radialSegments,
29222 heightSegments: heightSegments,
29223 openEnded: openEnded,
29224 thetaStart: thetaStart,
29225 thetaLength: thetaLength
29228 this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
29229 this.mergeVertices();
29235 class ConeGeometry extends CylinderGeometry {
29237 constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
29239 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
29240 this.type = 'ConeGeometry';
29242 this.parameters = {
29245 radialSegments: radialSegments,
29246 heightSegments: heightSegments,
29247 openEnded: openEnded,
29248 thetaStart: thetaStart,
29249 thetaLength: thetaLength
29256 class ConeBufferGeometry extends CylinderBufferGeometry {
29258 constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
29260 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
29262 this.type = 'ConeBufferGeometry';
29264 this.parameters = {
29267 radialSegments: radialSegments,
29268 heightSegments: heightSegments,
29269 openEnded: openEnded,
29270 thetaStart: thetaStart,
29271 thetaLength: thetaLength
29278 class PolyhedronBufferGeometry extends BufferGeometry {
29280 constructor( vertices, indices, radius = 1, detail = 0 ) {
29284 this.type = 'PolyhedronBufferGeometry';
29286 this.parameters = {
29287 vertices: vertices,
29293 // default buffer data
29295 const vertexBuffer = [];
29296 const uvBuffer = [];
29298 // the subdivision creates the vertex buffer data
29300 subdivide( detail );
29302 // all vertices should lie on a conceptual sphere with a given radius
29304 applyRadius( radius );
29306 // finally, create the uv data
29310 // build non-indexed geometry
29312 this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
29313 this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
29314 this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
29316 if ( detail === 0 ) {
29318 this.computeVertexNormals(); // flat normals
29322 this.normalizeNormals(); // smooth normals
29326 // helper functions
29328 function subdivide( detail ) {
29330 const a = new Vector3();
29331 const b = new Vector3();
29332 const c = new Vector3();
29334 // iterate over all faces and apply a subdivison with the given detail value
29336 for ( let i = 0; i < indices.length; i += 3 ) {
29338 // get the vertices of the face
29340 getVertexByIndex( indices[ i + 0 ], a );
29341 getVertexByIndex( indices[ i + 1 ], b );
29342 getVertexByIndex( indices[ i + 2 ], c );
29344 // perform subdivision
29346 subdivideFace( a, b, c, detail );
29352 function subdivideFace( a, b, c, detail ) {
29354 const cols = detail + 1;
29356 // we use this multidimensional array as a data structure for creating the subdivision
29360 // construct all of the vertices for this subdivision
29362 for ( let i = 0; i <= cols; i ++ ) {
29366 const aj = a.clone().lerp( c, i / cols );
29367 const bj = b.clone().lerp( c, i / cols );
29369 const rows = cols - i;
29371 for ( let j = 0; j <= rows; j ++ ) {
29373 if ( j === 0 && i === cols ) {
29379 v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
29387 // construct all of the faces
29389 for ( let i = 0; i < cols; i ++ ) {
29391 for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
29393 const k = Math.floor( j / 2 );
29395 if ( j % 2 === 0 ) {
29397 pushVertex( v[ i ][ k + 1 ] );
29398 pushVertex( v[ i + 1 ][ k ] );
29399 pushVertex( v[ i ][ k ] );
29403 pushVertex( v[ i ][ k + 1 ] );
29404 pushVertex( v[ i + 1 ][ k + 1 ] );
29405 pushVertex( v[ i + 1 ][ k ] );
29415 function applyRadius( radius ) {
29417 const vertex = new Vector3();
29419 // iterate over the entire buffer and apply the radius to each vertex
29421 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
29423 vertex.x = vertexBuffer[ i + 0 ];
29424 vertex.y = vertexBuffer[ i + 1 ];
29425 vertex.z = vertexBuffer[ i + 2 ];
29427 vertex.normalize().multiplyScalar( radius );
29429 vertexBuffer[ i + 0 ] = vertex.x;
29430 vertexBuffer[ i + 1 ] = vertex.y;
29431 vertexBuffer[ i + 2 ] = vertex.z;
29437 function generateUVs() {
29439 const vertex = new Vector3();
29441 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
29443 vertex.x = vertexBuffer[ i + 0 ];
29444 vertex.y = vertexBuffer[ i + 1 ];
29445 vertex.z = vertexBuffer[ i + 2 ];
29447 const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
29448 const v = inclination( vertex ) / Math.PI + 0.5;
29449 uvBuffer.push( u, 1 - v );
29459 function correctSeam() {
29461 // handle case when face straddles the seam, see #3269
29463 for ( let i = 0; i < uvBuffer.length; i += 6 ) {
29465 // uv data of a single face
29467 const x0 = uvBuffer[ i + 0 ];
29468 const x1 = uvBuffer[ i + 2 ];
29469 const x2 = uvBuffer[ i + 4 ];
29471 const max = Math.max( x0, x1, x2 );
29472 const min = Math.min( x0, x1, x2 );
29474 // 0.9 is somewhat arbitrary
29476 if ( max > 0.9 && min < 0.1 ) {
29478 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
29479 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
29480 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
29488 function pushVertex( vertex ) {
29490 vertexBuffer.push( vertex.x, vertex.y, vertex.z );
29494 function getVertexByIndex( index, vertex ) {
29496 const stride = index * 3;
29498 vertex.x = vertices[ stride + 0 ];
29499 vertex.y = vertices[ stride + 1 ];
29500 vertex.z = vertices[ stride + 2 ];
29504 function correctUVs() {
29506 const a = new Vector3();
29507 const b = new Vector3();
29508 const c = new Vector3();
29510 const centroid = new Vector3();
29512 const uvA = new Vector2();
29513 const uvB = new Vector2();
29514 const uvC = new Vector2();
29516 for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
29518 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
29519 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
29520 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
29522 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
29523 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
29524 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
29526 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
29528 const azi = azimuth( centroid );
29530 correctUV( uvA, j + 0, a, azi );
29531 correctUV( uvB, j + 2, b, azi );
29532 correctUV( uvC, j + 4, c, azi );
29538 function correctUV( uv, stride, vector, azimuth ) {
29540 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
29542 uvBuffer[ stride ] = uv.x - 1;
29546 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
29548 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
29554 // Angle around the Y axis, counter-clockwise when looking from above.
29556 function azimuth( vector ) {
29558 return Math.atan2( vector.z, - vector.x );
29563 // Angle above the XZ plane.
29565 function inclination( vector ) {
29567 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
29575 class DodecahedronBufferGeometry extends PolyhedronBufferGeometry {
29577 constructor( radius = 1, detail = 0 ) {
29579 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
29585 - 1, - 1, - 1, - 1, - 1, 1,
29586 - 1, 1, - 1, - 1, 1, 1,
29587 1, - 1, - 1, 1, - 1, 1,
29588 1, 1, - 1, 1, 1, 1,
29590 // (0, ±1/φ, ±φ)
29591 0, - r, - t, 0, - r, t,
29592 0, r, - t, 0, r, t,
29594 // (±1/φ, ±φ, 0)
29595 - r, - t, 0, - r, t, 0,
29596 r, - t, 0, r, t, 0,
29598 // (±φ, 0, ±1/φ)
29599 - t, 0, - r, t, 0, - r,
29604 3, 11, 7, 3, 7, 15, 3, 15, 13,
29605 7, 19, 17, 7, 17, 6, 7, 6, 15,
29606 17, 4, 8, 17, 8, 10, 17, 10, 6,
29607 8, 0, 16, 8, 16, 2, 8, 2, 10,
29608 0, 12, 1, 0, 1, 18, 0, 18, 16,
29609 6, 10, 2, 6, 2, 13, 6, 13, 15,
29610 2, 16, 18, 2, 18, 3, 2, 3, 13,
29611 18, 1, 9, 18, 9, 11, 18, 11, 3,
29612 4, 14, 12, 4, 12, 0, 4, 0, 8,
29613 11, 9, 5, 11, 5, 19, 11, 19, 7,
29614 19, 5, 14, 19, 14, 4, 19, 4, 17,
29615 1, 12, 14, 1, 14, 5, 1, 5, 9
29618 super( vertices, indices, radius, detail );
29620 this.type = 'DodecahedronBufferGeometry';
29622 this.parameters = {
29631 class DodecahedronGeometry extends Geometry {
29633 constructor( radius, detail ) {
29636 this.type = 'DodecahedronGeometry';
29638 this.parameters = {
29643 this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
29644 this.mergeVertices();
29650 const _v0$2 = new Vector3();
29651 const _v1$5 = new Vector3();
29652 const _normal$1 = new Vector3();
29653 const _triangle = new Triangle();
29655 class EdgesGeometry extends BufferGeometry {
29657 constructor( geometry, thresholdAngle ) {
29661 this.type = 'EdgesGeometry';
29663 this.parameters = {
29664 thresholdAngle: thresholdAngle
29667 thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
29669 if ( geometry.isGeometry ) {
29671 geometry = new BufferGeometry().fromGeometry( geometry );
29675 const precisionPoints = 4;
29676 const precision = Math.pow( 10, precisionPoints );
29677 const thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle );
29679 const indexAttr = geometry.getIndex();
29680 const positionAttr = geometry.getAttribute( 'position' );
29681 const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
29683 const indexArr = [ 0, 0, 0 ];
29684 const vertKeys = [ 'a', 'b', 'c' ];
29685 const hashes = new Array( 3 );
29687 const edgeData = {};
29688 const vertices = [];
29689 for ( let i = 0; i < indexCount; i += 3 ) {
29693 indexArr[ 0 ] = indexAttr.getX( i );
29694 indexArr[ 1 ] = indexAttr.getX( i + 1 );
29695 indexArr[ 2 ] = indexAttr.getX( i + 2 );
29700 indexArr[ 1 ] = i + 1;
29701 indexArr[ 2 ] = i + 2;
29705 const { a, b, c } = _triangle;
29706 a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
29707 b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
29708 c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
29709 _triangle.getNormal( _normal$1 );
29711 // create hashes for the edge from the vertices
29712 hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
29713 hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
29714 hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
29716 // skip degenerate triangles
29717 if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
29723 // iterate over every edge
29724 for ( let j = 0; j < 3; j ++ ) {
29726 // get the first and next vertex making up the edge
29727 const jNext = ( j + 1 ) % 3;
29728 const vecHash0 = hashes[ j ];
29729 const vecHash1 = hashes[ jNext ];
29730 const v0 = _triangle[ vertKeys[ j ] ];
29731 const v1 = _triangle[ vertKeys[ jNext ] ];
29733 const hash = `${ vecHash0 }_${ vecHash1 }`;
29734 const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
29736 if ( reverseHash in edgeData && edgeData[ reverseHash ] ) {
29738 // if we found a sibling edge add it into the vertex array if
29739 // it meets the angle threshold and delete the edge from the map.
29740 if ( _normal$1.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
29742 vertices.push( v0.x, v0.y, v0.z );
29743 vertices.push( v1.x, v1.y, v1.z );
29747 edgeData[ reverseHash ] = null;
29749 } else if ( ! ( hash in edgeData ) ) {
29751 // if we've already got an edge here then skip adding a new one
29752 edgeData[ hash ] = {
29754 index0: indexArr[ j ],
29755 index1: indexArr[ jNext ],
29756 normal: _normal$1.clone(),
29766 // iterate over all remaining, unmatched edges and add them to the vertex array
29767 for ( const key in edgeData ) {
29769 if ( edgeData[ key ] ) {
29771 const { index0, index1 } = edgeData[ key ];
29772 _v0$2.fromBufferAttribute( positionAttr, index0 );
29773 _v1$5.fromBufferAttribute( positionAttr, index1 );
29775 vertices.push( _v0$2.x, _v0$2.y, _v0$2.z );
29776 vertices.push( _v1$5.x, _v1$5.y, _v1$5.z );
29782 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29789 * Port from https://github.com/mapbox/earcut (v2.2.2)
29794 triangulate: function ( data, holeIndices, dim ) {
29798 const hasHoles = holeIndices && holeIndices.length;
29799 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
29800 let outerNode = linkedList( data, 0, outerLen, dim, true );
29801 const triangles = [];
29803 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
29805 let minX, minY, maxX, maxY, x, y, invSize;
29807 if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
29809 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
29810 if ( data.length > 80 * dim ) {
29812 minX = maxX = data[ 0 ];
29813 minY = maxY = data[ 1 ];
29815 for ( let i = dim; i < outerLen; i += dim ) {
29819 if ( x < minX ) minX = x;
29820 if ( y < minY ) minY = y;
29821 if ( x > maxX ) maxX = x;
29822 if ( y > maxY ) maxY = y;
29826 // minX, minY and invSize are later used to transform coords into integers for z-order calculation
29827 invSize = Math.max( maxX - minX, maxY - minY );
29828 invSize = invSize !== 0 ? 1 / invSize : 0;
29832 earcutLinked( outerNode, triangles, dim, minX, minY, invSize );
29840 // create a circular doubly linked list from polygon points in the specified winding order
29841 function linkedList( data, start, end, dim, clockwise ) {
29845 if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
29847 for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
29851 for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
29855 if ( last && equals( last, last.next ) ) {
29857 removeNode( last );
29866 // eliminate colinear or duplicate points
29867 function filterPoints( start, end ) {
29869 if ( ! start ) return start;
29870 if ( ! end ) end = start;
29878 if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
29882 if ( p === p.next ) break;
29891 } while ( again || p !== end );
29897 // main ear slicing loop which triangulates a polygon (given as a linked list)
29898 function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
29900 if ( ! ear ) return;
29902 // interlink polygon nodes in z-order
29903 if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
29908 // iterate through ears, slicing them one by one
29909 while ( ear.prev !== ear.next ) {
29914 if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
29916 // cut off the triangle
29917 triangles.push( prev.i / dim );
29918 triangles.push( ear.i / dim );
29919 triangles.push( next.i / dim );
29923 // skipping the next vertex leads to less sliver triangles
29933 // if we looped through the whole remaining polygon and can't find any more ears
29934 if ( ear === stop ) {
29936 // try filtering points and slicing again
29939 earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
29941 // if this didn't work, try curing all small self-intersections locally
29943 } else if ( pass === 1 ) {
29945 ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
29946 earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
29948 // as a last resort, try splitting the remaining polygon into two
29950 } else if ( pass === 2 ) {
29952 splitEarcut( ear, triangles, dim, minX, minY, invSize );
29964 // check whether a polygon node forms a valid ear with adjacent nodes
29965 function isEar( ear ) {
29967 const a = ear.prev,
29971 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
29973 // now make sure we don't have other points inside the potential ear
29974 let p = ear.next.next;
29976 while ( p !== ear.prev ) {
29978 if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
29979 area( p.prev, p, p.next ) >= 0 ) return false;
29988 function isEarHashed( ear, minX, minY, invSize ) {
29990 const a = ear.prev,
29994 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
29996 // triangle bbox; min & max are calculated like this for speed
29997 const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
29998 minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
29999 maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
30000 maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
30002 // z-order range for the current triangle bbox;
30003 const minZ = zOrder( minTX, minTY, minX, minY, invSize ),
30004 maxZ = zOrder( maxTX, maxTY, minX, minY, invSize );
30009 // look for points inside the triangle in both directions
30010 while ( p && p.z >= minZ && n && n.z <= maxZ ) {
30012 if ( p !== ear.prev && p !== ear.next &&
30013 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
30014 area( p.prev, p, p.next ) >= 0 ) return false;
30017 if ( n !== ear.prev && n !== ear.next &&
30018 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
30019 area( n.prev, n, n.next ) >= 0 ) return false;
30024 // look for remaining points in decreasing z-order
30025 while ( p && p.z >= minZ ) {
30027 if ( p !== ear.prev && p !== ear.next &&
30028 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
30029 area( p.prev, p, p.next ) >= 0 ) return false;
30034 // look for remaining points in increasing z-order
30035 while ( n && n.z <= maxZ ) {
30037 if ( n !== ear.prev && n !== ear.next &&
30038 pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
30039 area( n.prev, n, n.next ) >= 0 ) return false;
30048 // go through all polygon nodes and cure small local self-intersections
30049 function cureLocalIntersections( start, triangles, dim ) {
30057 if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
30059 triangles.push( a.i / dim );
30060 triangles.push( p.i / dim );
30061 triangles.push( b.i / dim );
30063 // remove two nodes involved
30065 removeNode( p.next );
30073 } while ( p !== start );
30075 return filterPoints( p );
30079 // try splitting polygon into two and triangulate them independently
30080 function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
30082 // look for a valid diagonal that divides the polygon into two
30086 let b = a.next.next;
30087 while ( b !== a.prev ) {
30089 if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
30091 // split the polygon in two by the diagonal
30092 let c = splitPolygon( a, b );
30094 // filter colinear points around the cuts
30095 a = filterPoints( a, a.next );
30096 c = filterPoints( c, c.next );
30098 // run earcut on each half
30099 earcutLinked( a, triangles, dim, minX, minY, invSize );
30100 earcutLinked( c, triangles, dim, minX, minY, invSize );
30111 } while ( a !== start );
30115 // link every hole into the outer loop, producing a single-ring polygon without holes
30116 function eliminateHoles( data, holeIndices, outerNode, dim ) {
30119 let i, len, start, end, list;
30121 for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
30123 start = holeIndices[ i ] * dim;
30124 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
30125 list = linkedList( data, start, end, dim, false );
30126 if ( list === list.next ) list.steiner = true;
30127 queue.push( getLeftmost( list ) );
30131 queue.sort( compareX );
30133 // process holes from left to right
30134 for ( i = 0; i < queue.length; i ++ ) {
30136 eliminateHole( queue[ i ], outerNode );
30137 outerNode = filterPoints( outerNode, outerNode.next );
30145 function compareX( a, b ) {
30151 // find a bridge between vertices that connects hole with an outer ring and and link it
30152 function eliminateHole( hole, outerNode ) {
30154 outerNode = findHoleBridge( hole, outerNode );
30157 const b = splitPolygon( outerNode, hole );
30159 // filter collinear points around the cuts
30160 filterPoints( outerNode, outerNode.next );
30161 filterPoints( b, b.next );
30167 // David Eberly's algorithm for finding a bridge between hole and outer polygon
30168 function findHoleBridge( hole, outerNode ) {
30173 let qx = - Infinity, m;
30175 // find a segment intersected by a ray from the hole's leftmost point to the left;
30176 // segment's endpoint with lesser x will be potential connection point
30179 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
30181 const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
30182 if ( x <= hx && x > qx ) {
30187 if ( hy === p.y ) return p;
30188 if ( hy === p.next.y ) return p.next;
30192 m = p.x < p.next.x ? p : p.next;
30200 } while ( p !== outerNode );
30202 if ( ! m ) return null;
30204 if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
30206 // look for points inside the triangle of hole point, segment intersection and endpoint;
30207 // if there are no points found, we have a valid connection;
30208 // otherwise choose the point of the minimum angle with the ray as connection point
30213 let tanMin = Infinity, tan;
30219 if ( hx >= p.x && p.x >= mx && hx !== p.x &&
30220 pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
30222 tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
30224 if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
30235 } while ( p !== stop );
30241 // whether sector in vertex m contains sector in vertex p in the same coordinates
30242 function sectorContainsSector( m, p ) {
30244 return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
30248 // interlink polygon nodes in z-order
30249 function indexCurve( start, minX, minY, invSize ) {
30254 if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
30259 } while ( p !== start );
30261 p.prevZ.nextZ = null;
30268 // Simon Tatham's linked list merge sort algorithm
30269 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
30270 function sortLinked( list ) {
30272 let i, p, q, e, tail, numMerges, pSize, qSize,
30287 for ( i = 0; i < inSize; i ++ ) {
30297 while ( pSize > 0 || ( qSize > 0 && q ) ) {
30299 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
30313 if ( tail ) tail.nextZ = e;
30328 } while ( numMerges > 1 );
30334 // z-order of a point given coords and inverse of the longer side of data bbox
30335 function zOrder( x, y, minX, minY, invSize ) {
30337 // coords are transformed into non-negative 15-bit integer range
30338 x = 32767 * ( x - minX ) * invSize;
30339 y = 32767 * ( y - minY ) * invSize;
30341 x = ( x | ( x << 8 ) ) & 0x00FF00FF;
30342 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
30343 x = ( x | ( x << 2 ) ) & 0x33333333;
30344 x = ( x | ( x << 1 ) ) & 0x55555555;
30346 y = ( y | ( y << 8 ) ) & 0x00FF00FF;
30347 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
30348 y = ( y | ( y << 2 ) ) & 0x33333333;
30349 y = ( y | ( y << 1 ) ) & 0x55555555;
30351 return x | ( y << 1 );
30355 // find the leftmost node of a polygon ring
30356 function getLeftmost( start ) {
30362 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
30365 } while ( p !== start );
30371 // check if a point lies within a convex triangle
30372 function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
30374 return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
30375 ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
30376 ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
30380 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
30381 function isValidDiagonal( a, b ) {
30383 return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
30384 ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
30385 ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
30386 equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
30390 // signed area of a triangle
30391 function area( p, q, r ) {
30393 return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
30397 // check if two points are equal
30398 function equals( p1, p2 ) {
30400 return p1.x === p2.x && p1.y === p2.y;
30404 // check if two segments intersect
30405 function intersects( p1, q1, p2, q2 ) {
30407 const o1 = sign( area( p1, q1, p2 ) );
30408 const o2 = sign( area( p1, q1, q2 ) );
30409 const o3 = sign( area( p2, q2, p1 ) );
30410 const o4 = sign( area( p2, q2, q1 ) );
30412 if ( o1 !== o2 && o3 !== o4 ) return true; // general case
30414 if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
30415 if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
30416 if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
30417 if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
30423 // for collinear points p, q, r, check if point q lies on segment pr
30424 function onSegment( p, q, r ) {
30426 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 );
30430 function sign( num ) {
30432 return num > 0 ? 1 : num < 0 ? - 1 : 0;
30436 // check if a polygon diagonal intersects any polygon segments
30437 function intersectsPolygon( a, b ) {
30442 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
30443 intersects( p, p.next, a, b ) ) return true;
30446 } while ( p !== a );
30452 // check if a polygon diagonal is locally inside the polygon
30453 function locallyInside( a, b ) {
30455 return area( a.prev, a, a.next ) < 0 ?
30456 area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
30457 area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
30461 // check if the middle point of a polygon diagonal is inside the polygon
30462 function middleInside( a, b ) {
30466 const px = ( a.x + b.x ) / 2,
30467 py = ( a.y + b.y ) / 2;
30470 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
30471 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
30475 } while ( p !== a );
30481 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
30482 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
30483 function splitPolygon( a, b ) {
30485 const a2 = new Node( a.i, a.x, a.y ),
30486 b2 = new Node( b.i, b.x, b.y ),
30506 // create a node and optionally link it with previous one (in a circular doubly linked list)
30507 function insertNode( i, x, y, last ) {
30509 const p = new Node( i, x, y );
30518 p.next = last.next;
30520 last.next.prev = p;
30529 function removeNode( p ) {
30531 p.next.prev = p.prev;
30532 p.prev.next = p.next;
30534 if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
30535 if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
30539 function Node( i, x, y ) {
30541 // vertex index in coordinates array
30544 // vertex coordinates
30548 // previous and next vertex nodes in a polygon ring
30552 // z-order curve value
30555 // previous and next nodes in z-order
30559 // indicates whether this is a steiner point
30560 this.steiner = false;
30564 function signedArea( data, start, end, dim ) {
30567 for ( let i = start, j = end - dim; i < end; i += dim ) {
30569 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
30578 const ShapeUtils = {
30580 // calculate area of the contour polygon
30582 area: function ( contour ) {
30584 const n = contour.length;
30587 for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
30589 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
30597 isClockWise: function ( pts ) {
30599 return ShapeUtils.area( pts ) < 0;
30603 triangulateShape: function ( contour, holes ) {
30605 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
30606 const holeIndices = []; // array of hole indices
30607 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
30609 removeDupEndPts( contour );
30610 addContour( vertices, contour );
30614 let holeIndex = contour.length;
30616 holes.forEach( removeDupEndPts );
30618 for ( let i = 0; i < holes.length; i ++ ) {
30620 holeIndices.push( holeIndex );
30621 holeIndex += holes[ i ].length;
30622 addContour( vertices, holes[ i ] );
30628 const triangles = Earcut.triangulate( vertices, holeIndices );
30632 for ( let i = 0; i < triangles.length; i += 3 ) {
30634 faces.push( triangles.slice( i, i + 3 ) );
30644 function removeDupEndPts( points ) {
30646 const l = points.length;
30648 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
30656 function addContour( vertices, contour ) {
30658 for ( let i = 0; i < contour.length; i ++ ) {
30660 vertices.push( contour[ i ].x );
30661 vertices.push( contour[ i ].y );
30668 * Creates extruded geometry from a path shape.
30672 * curveSegments: <int>, // number of points on the curves
30673 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
30674 * depth: <float>, // Depth to extrude the shape
30676 * bevelEnabled: <bool>, // turn on bevel
30677 * bevelThickness: <float>, // how deep into the original shape bevel goes
30678 * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
30679 * bevelOffset: <float>, // how far from shape outline does bevel start
30680 * bevelSegments: <int>, // number of bevel layers
30682 * extrudePath: <THREE.Curve> // curve to extrude shape along
30684 * UVGenerator: <Object> // object that provides UV generator functions
30689 class ExtrudeBufferGeometry extends BufferGeometry {
30691 constructor( shapes, options ) {
30695 this.type = 'ExtrudeBufferGeometry';
30697 this.parameters = {
30702 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
30704 const scope = this;
30706 const verticesArray = [];
30707 const uvArray = [];
30709 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
30711 const shape = shapes[ i ];
30718 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
30719 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
30721 this.computeVertexNormals();
30725 function addShape( shape ) {
30727 const placeholder = [];
30731 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
30732 const steps = options.steps !== undefined ? options.steps : 1;
30733 let depth = options.depth !== undefined ? options.depth : 100;
30735 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
30736 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
30737 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
30738 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
30739 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
30741 const extrudePath = options.extrudePath;
30743 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
30745 // deprecated options
30747 if ( options.amount !== undefined ) {
30749 console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
30750 depth = options.amount;
30756 let extrudePts, extrudeByPath = false;
30757 let splineTube, binormal, normal, position2;
30759 if ( extrudePath ) {
30761 extrudePts = extrudePath.getSpacedPoints( steps );
30763 extrudeByPath = true;
30764 bevelEnabled = false; // bevels not supported for path extrusion
30766 // SETUP TNB variables
30768 // TODO1 - have a .isClosed in spline?
30770 splineTube = extrudePath.computeFrenetFrames( steps, false );
30772 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
30774 binormal = new Vector3();
30775 normal = new Vector3();
30776 position2 = new Vector3();
30780 // Safeguards if bevels are not enabled
30782 if ( ! bevelEnabled ) {
30785 bevelThickness = 0;
30791 // Variables initialization
30793 const shapePoints = shape.extractPoints( curveSegments );
30795 let vertices = shapePoints.shape;
30796 const holes = shapePoints.holes;
30798 const reverse = ! ShapeUtils.isClockWise( vertices );
30802 vertices = vertices.reverse();
30804 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
30806 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
30808 const ahole = holes[ h ];
30810 if ( ShapeUtils.isClockWise( ahole ) ) {
30812 holes[ h ] = ahole.reverse();
30821 const faces = ShapeUtils.triangulateShape( vertices, holes );
30825 const contour = vertices; // vertices has all points but contour has only points of circumference
30827 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
30829 const ahole = holes[ h ];
30831 vertices = vertices.concat( ahole );
30836 function scalePt2( pt, vec, size ) {
30838 if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" );
30840 return vec.clone().multiplyScalar( size ).add( pt );
30844 const vlen = vertices.length, flen = faces.length;
30847 // Find directions for point movement
30850 function getBevelVec( inPt, inPrev, inNext ) {
30852 // computes for inPt the corresponding point inPt' on a new contour
30853 // shifted by 1 unit (length of normalized vector) to the left
30854 // if we walk along contour clockwise, this new contour is outside the old one
30856 // inPt' is the intersection of the two lines parallel to the two
30857 // adjacent edges of inPt at a distance of 1 unit on the left side.
30859 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
30861 // good reading for geometry algorithms (here: line-line intersection)
30862 // http://geomalgorithms.com/a05-_intersect-1.html
30864 const v_prev_x = inPt.x - inPrev.x,
30865 v_prev_y = inPt.y - inPrev.y;
30866 const v_next_x = inNext.x - inPt.x,
30867 v_next_y = inNext.y - inPt.y;
30869 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
30871 // check for collinear edges
30872 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
30874 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
30878 // length of vectors for normalizing
30880 const v_prev_len = Math.sqrt( v_prev_lensq );
30881 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
30883 // shift adjacent points by unit vectors to the left
30885 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
30886 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
30888 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
30889 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
30891 // scaling factor for v_prev to intersection point
30893 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
30894 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
30895 ( v_prev_x * v_next_y - v_prev_y * v_next_x );
30897 // vector from inPt to intersection point
30899 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
30900 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
30902 // Don't normalize!, otherwise sharp corners become ugly
30903 // but prevent crazy spikes
30904 const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
30905 if ( v_trans_lensq <= 2 ) {
30907 return new Vector2( v_trans_x, v_trans_y );
30911 shrink_by = Math.sqrt( v_trans_lensq / 2 );
30917 // handle special case of collinear edges
30919 let direction_eq = false; // assumes: opposite
30921 if ( v_prev_x > Number.EPSILON ) {
30923 if ( v_next_x > Number.EPSILON ) {
30925 direction_eq = true;
30931 if ( v_prev_x < - Number.EPSILON ) {
30933 if ( v_next_x < - Number.EPSILON ) {
30935 direction_eq = true;
30941 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
30943 direction_eq = true;
30951 if ( direction_eq ) {
30953 // console.log("Warning: lines are a straight sequence");
30954 v_trans_x = - v_prev_y;
30955 v_trans_y = v_prev_x;
30956 shrink_by = Math.sqrt( v_prev_lensq );
30960 // console.log("Warning: lines are a straight spike");
30961 v_trans_x = v_prev_x;
30962 v_trans_y = v_prev_y;
30963 shrink_by = Math.sqrt( v_prev_lensq / 2 );
30969 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
30974 const contourMovements = [];
30976 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
30978 if ( j === il ) j = 0;
30979 if ( k === il ) k = 0;
30982 // console.log('i,j,k', i, j , k)
30984 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
30988 const holesMovements = [];
30989 let oneHoleMovements, verticesMovements = contourMovements.concat();
30991 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
30993 const ahole = holes[ h ];
30995 oneHoleMovements = [];
30997 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
30999 if ( j === il ) j = 0;
31000 if ( k === il ) k = 0;
31003 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
31007 holesMovements.push( oneHoleMovements );
31008 verticesMovements = verticesMovements.concat( oneHoleMovements );
31013 // Loop bevelSegments, 1 for the front, 1 for the back
31015 for ( let b = 0; b < bevelSegments; b ++ ) {
31017 //for ( b = bevelSegments; b > 0; b -- ) {
31019 const t = b / bevelSegments;
31020 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
31021 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
31025 for ( let i = 0, il = contour.length; i < il; i ++ ) {
31027 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
31029 v( vert.x, vert.y, - z );
31035 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
31037 const ahole = holes[ h ];
31038 oneHoleMovements = holesMovements[ h ];
31040 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
31042 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
31044 v( vert.x, vert.y, - z );
31052 const bs = bevelSize + bevelOffset;
31054 // Back facing vertices
31056 for ( let i = 0; i < vlen; i ++ ) {
31058 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
31060 if ( ! extrudeByPath ) {
31062 v( vert.x, vert.y, 0 );
31066 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
31068 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
31069 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
31071 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
31073 v( position2.x, position2.y, position2.z );
31079 // Add stepped vertices...
31080 // Including front facing vertices
31082 for ( let s = 1; s <= steps; s ++ ) {
31084 for ( let i = 0; i < vlen; i ++ ) {
31086 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
31088 if ( ! extrudeByPath ) {
31090 v( vert.x, vert.y, depth / steps * s );
31094 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
31096 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
31097 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
31099 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
31101 v( position2.x, position2.y, position2.z );
31110 // Add bevel segments planes
31112 //for ( b = 1; b <= bevelSegments; b ++ ) {
31113 for ( let b = bevelSegments - 1; b >= 0; b -- ) {
31115 const t = b / bevelSegments;
31116 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
31117 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
31121 for ( let i = 0, il = contour.length; i < il; i ++ ) {
31123 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
31124 v( vert.x, vert.y, depth + z );
31130 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
31132 const ahole = holes[ h ];
31133 oneHoleMovements = holesMovements[ h ];
31135 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
31137 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
31139 if ( ! extrudeByPath ) {
31141 v( vert.x, vert.y, depth + z );
31145 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
31157 // Top and bottom faces
31166 ///// Internal functions
31168 function buildLidFaces() {
31170 const start = verticesArray.length / 3;
31172 if ( bevelEnabled ) {
31174 let layer = 0; // steps + 1
31175 let offset = vlen * layer;
31179 for ( let i = 0; i < flen; i ++ ) {
31181 const face = faces[ i ];
31182 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
31186 layer = steps + bevelSegments * 2;
31187 offset = vlen * layer;
31191 for ( let i = 0; i < flen; i ++ ) {
31193 const face = faces[ i ];
31194 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
31202 for ( let i = 0; i < flen; i ++ ) {
31204 const face = faces[ i ];
31205 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
31211 for ( let i = 0; i < flen; i ++ ) {
31213 const face = faces[ i ];
31214 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
31220 scope.addGroup( start, verticesArray.length / 3 - start, 0 );
31224 // Create faces for the z-sides of the shape
31226 function buildSideFaces() {
31228 const start = verticesArray.length / 3;
31229 let layeroffset = 0;
31230 sidewalls( contour, layeroffset );
31231 layeroffset += contour.length;
31233 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
31235 const ahole = holes[ h ];
31236 sidewalls( ahole, layeroffset );
31239 layeroffset += ahole.length;
31244 scope.addGroup( start, verticesArray.length / 3 - start, 1 );
31249 function sidewalls( contour, layeroffset ) {
31251 let i = contour.length;
31253 while ( -- i >= 0 ) {
31257 if ( k < 0 ) k = contour.length - 1;
31259 //console.log('b', i,j, i-1, k,vertices.length);
31261 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
31263 const slen1 = vlen * s;
31264 const slen2 = vlen * ( s + 1 );
31266 const a = layeroffset + j + slen1,
31267 b = layeroffset + k + slen1,
31268 c = layeroffset + k + slen2,
31269 d = layeroffset + j + slen2;
31279 function v( x, y, z ) {
31281 placeholder.push( x );
31282 placeholder.push( y );
31283 placeholder.push( z );
31288 function f3( a, b, c ) {
31294 const nextIndex = verticesArray.length / 3;
31295 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
31303 function f4( a, b, c, d ) {
31314 const nextIndex = verticesArray.length / 3;
31315 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
31327 function addVertex( index ) {
31329 verticesArray.push( placeholder[ index * 3 + 0 ] );
31330 verticesArray.push( placeholder[ index * 3 + 1 ] );
31331 verticesArray.push( placeholder[ index * 3 + 2 ] );
31336 function addUV( vector2 ) {
31338 uvArray.push( vector2.x );
31339 uvArray.push( vector2.y );
31349 const data = BufferGeometry.prototype.toJSON.call( this );
31351 const shapes = this.parameters.shapes;
31352 const options = this.parameters.options;
31354 return toJSON( shapes, options, data );
31360 const WorldUVGenerator = {
31362 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
31364 const a_x = vertices[ indexA * 3 ];
31365 const a_y = vertices[ indexA * 3 + 1 ];
31366 const b_x = vertices[ indexB * 3 ];
31367 const b_y = vertices[ indexB * 3 + 1 ];
31368 const c_x = vertices[ indexC * 3 ];
31369 const c_y = vertices[ indexC * 3 + 1 ];
31372 new Vector2( a_x, a_y ),
31373 new Vector2( b_x, b_y ),
31374 new Vector2( c_x, c_y )
31379 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
31381 const a_x = vertices[ indexA * 3 ];
31382 const a_y = vertices[ indexA * 3 + 1 ];
31383 const a_z = vertices[ indexA * 3 + 2 ];
31384 const b_x = vertices[ indexB * 3 ];
31385 const b_y = vertices[ indexB * 3 + 1 ];
31386 const b_z = vertices[ indexB * 3 + 2 ];
31387 const c_x = vertices[ indexC * 3 ];
31388 const c_y = vertices[ indexC * 3 + 1 ];
31389 const c_z = vertices[ indexC * 3 + 2 ];
31390 const d_x = vertices[ indexD * 3 ];
31391 const d_y = vertices[ indexD * 3 + 1 ];
31392 const d_z = vertices[ indexD * 3 + 2 ];
31394 if ( Math.abs( a_y - b_y ) < 0.01 ) {
31397 new Vector2( a_x, 1 - a_z ),
31398 new Vector2( b_x, 1 - b_z ),
31399 new Vector2( c_x, 1 - c_z ),
31400 new Vector2( d_x, 1 - d_z )
31406 new Vector2( a_y, 1 - a_z ),
31407 new Vector2( b_y, 1 - b_z ),
31408 new Vector2( c_y, 1 - c_z ),
31409 new Vector2( d_y, 1 - d_z )
31418 function toJSON( shapes, options, data ) {
31422 if ( Array.isArray( shapes ) ) {
31424 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
31426 const shape = shapes[ i ];
31428 data.shapes.push( shape.uuid );
31434 data.shapes.push( shapes.uuid );
31438 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
31445 * Creates extruded geometry from a path shape.
31449 * curveSegments: <int>, // number of points on the curves
31450 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
31451 * depth: <float>, // Depth to extrude the shape
31453 * bevelEnabled: <bool>, // turn on bevel
31454 * bevelThickness: <float>, // how deep into the original shape bevel goes
31455 * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
31456 * bevelOffset: <float>, // how far from shape outline does bevel start
31457 * bevelSegments: <int>, // number of bevel layers
31459 * extrudePath: <THREE.Curve> // curve to extrude shape along
31461 * UVGenerator: <Object> // object that provides UV generator functions
31466 class ExtrudeGeometry extends Geometry {
31468 constructor( shapes, options ) {
31472 this.type = 'ExtrudeGeometry';
31474 this.parameters = {
31479 this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
31480 this.mergeVertices();
31486 const data = super.toJSON();
31488 const shapes = this.parameters.shapes;
31489 const options = this.parameters.options;
31491 return toJSON$1( shapes, options, data );
31497 function toJSON$1( shapes, options, data ) {
31501 if ( Array.isArray( shapes ) ) {
31503 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
31505 const shape = shapes[ i ];
31507 data.shapes.push( shape.uuid );
31513 data.shapes.push( shapes.uuid );
31517 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
31523 class IcosahedronBufferGeometry extends PolyhedronBufferGeometry {
31525 constructor( radius = 1, detail = 0 ) {
31527 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
31530 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
31531 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
31532 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
31536 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
31537 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
31538 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
31539 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
31542 super( vertices, indices, radius, detail );
31544 this.type = 'IcosahedronBufferGeometry';
31546 this.parameters = {
31555 class IcosahedronGeometry extends Geometry {
31557 constructor( radius, detail ) {
31561 this.type = 'IcosahedronGeometry';
31563 this.parameters = {
31568 this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
31569 this.mergeVertices();
31575 class LatheBufferGeometry extends BufferGeometry {
31577 constructor( points, segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {
31581 this.type = 'LatheBufferGeometry';
31583 this.parameters = {
31585 segments: segments,
31586 phiStart: phiStart,
31587 phiLength: phiLength
31590 segments = Math.floor( segments );
31592 // clamp phiLength so it's in range of [ 0, 2PI ]
31594 phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 );
31598 const indices = [];
31599 const vertices = [];
31602 // helper variables
31604 const inverseSegments = 1.0 / segments;
31605 const vertex = new Vector3();
31606 const uv = new Vector2();
31608 // generate vertices and uvs
31610 for ( let i = 0; i <= segments; i ++ ) {
31612 const phi = phiStart + i * inverseSegments * phiLength;
31614 const sin = Math.sin( phi );
31615 const cos = Math.cos( phi );
31617 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
31621 vertex.x = points[ j ].x * sin;
31622 vertex.y = points[ j ].y;
31623 vertex.z = points[ j ].x * cos;
31625 vertices.push( vertex.x, vertex.y, vertex.z );
31629 uv.x = i / segments;
31630 uv.y = j / ( points.length - 1 );
31632 uvs.push( uv.x, uv.y );
31641 for ( let i = 0; i < segments; i ++ ) {
31643 for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
31645 const base = j + i * points.length;
31648 const b = base + points.length;
31649 const c = base + points.length + 1;
31650 const d = base + 1;
31654 indices.push( a, b, d );
31655 indices.push( b, c, d );
31663 this.setIndex( indices );
31664 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
31665 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
31667 // generate normals
31669 this.computeVertexNormals();
31671 // if the geometry is closed, we need to average the normals along the seam.
31672 // because the corresponding vertices are identical (but still have different UVs).
31674 if ( phiLength === Math.PI * 2 ) {
31676 const normals = this.attributes.normal.array;
31677 const n1 = new Vector3();
31678 const n2 = new Vector3();
31679 const n = new Vector3();
31681 // this is the buffer offset for the last line of vertices
31683 const base = segments * points.length * 3;
31685 for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
31687 // select the normal of the vertex in the first line
31689 n1.x = normals[ j + 0 ];
31690 n1.y = normals[ j + 1 ];
31691 n1.z = normals[ j + 2 ];
31693 // select the normal of the vertex in the last line
31695 n2.x = normals[ base + j + 0 ];
31696 n2.y = normals[ base + j + 1 ];
31697 n2.z = normals[ base + j + 2 ];
31701 n.addVectors( n1, n2 ).normalize();
31703 // assign the new values to both normals
31705 normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
31706 normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
31707 normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
31717 class LatheGeometry extends Geometry {
31719 constructor( points, segments, phiStart, phiLength ) {
31723 this.type = 'LatheGeometry';
31725 this.parameters = {
31727 segments: segments,
31728 phiStart: phiStart,
31729 phiLength: phiLength
31732 this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
31733 this.mergeVertices();
31739 class OctahedronBufferGeometry extends PolyhedronBufferGeometry {
31741 constructor( radius = 1, detail = 0 ) {
31744 1, 0, 0, - 1, 0, 0, 0, 1, 0,
31745 0, - 1, 0, 0, 0, 1, 0, 0, - 1
31749 0, 2, 4, 0, 4, 3, 0, 3, 5,
31750 0, 5, 2, 1, 2, 5, 1, 5, 3,
31754 super( vertices, indices, radius, detail );
31756 this.type = 'OctahedronBufferGeometry';
31758 this.parameters = {
31767 class OctahedronGeometry extends Geometry {
31769 constructor( radius, detail ) {
31773 this.type = 'OctahedronGeometry';
31775 this.parameters = {
31780 this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
31781 this.mergeVertices();
31788 * Parametric Surfaces Geometry
31789 * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
31792 function ParametricBufferGeometry( func, slices, stacks ) {
31794 BufferGeometry.call( this );
31796 this.type = 'ParametricBufferGeometry';
31798 this.parameters = {
31806 const indices = [];
31807 const vertices = [];
31808 const normals = [];
31811 const EPS = 0.00001;
31813 const normal = new Vector3();
31815 const p0 = new Vector3(), p1 = new Vector3();
31816 const pu = new Vector3(), pv = new Vector3();
31818 if ( func.length < 3 ) {
31820 console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
31824 // generate vertices, normals and uvs
31826 const sliceCount = slices + 1;
31828 for ( let i = 0; i <= stacks; i ++ ) {
31830 const v = i / stacks;
31832 for ( let j = 0; j <= slices; j ++ ) {
31834 const u = j / slices;
31839 vertices.push( p0.x, p0.y, p0.z );
31843 // approximate tangent vectors via finite differences
31845 if ( u - EPS >= 0 ) {
31847 func( u - EPS, v, p1 );
31848 pu.subVectors( p0, p1 );
31852 func( u + EPS, v, p1 );
31853 pu.subVectors( p1, p0 );
31857 if ( v - EPS >= 0 ) {
31859 func( u, v - EPS, p1 );
31860 pv.subVectors( p0, p1 );
31864 func( u, v + EPS, p1 );
31865 pv.subVectors( p1, p0 );
31869 // cross product of tangent vectors returns surface normal
31871 normal.crossVectors( pu, pv ).normalize();
31872 normals.push( normal.x, normal.y, normal.z );
31882 // generate indices
31884 for ( let i = 0; i < stacks; i ++ ) {
31886 for ( let j = 0; j < slices; j ++ ) {
31888 const a = i * sliceCount + j;
31889 const b = i * sliceCount + j + 1;
31890 const c = ( i + 1 ) * sliceCount + j + 1;
31891 const d = ( i + 1 ) * sliceCount + j;
31893 // faces one and two
31895 indices.push( a, b, d );
31896 indices.push( b, c, d );
31904 this.setIndex( indices );
31905 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
31906 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
31907 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
31911 ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
31912 ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
31915 * Parametric Surfaces Geometry
31916 * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
31919 function ParametricGeometry( func, slices, stacks ) {
31921 Geometry.call( this );
31923 this.type = 'ParametricGeometry';
31925 this.parameters = {
31931 this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
31932 this.mergeVertices();
31936 ParametricGeometry.prototype = Object.create( Geometry.prototype );
31937 ParametricGeometry.prototype.constructor = ParametricGeometry;
31939 class PlaneGeometry extends Geometry {
31941 constructor( width, height, widthSegments, heightSegments ) {
31945 this.type = 'PlaneGeometry';
31947 this.parameters = {
31950 widthSegments: widthSegments,
31951 heightSegments: heightSegments
31954 this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
31955 this.mergeVertices();
31961 class PolyhedronGeometry extends Geometry {
31963 constructor( vertices, indices, radius, detail ) {
31967 this.type = 'PolyhedronGeometry';
31969 this.parameters = {
31970 vertices: vertices,
31976 this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
31977 this.mergeVertices();
31983 class RingBufferGeometry extends BufferGeometry {
31985 constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
31989 this.type = 'RingBufferGeometry';
31991 this.parameters = {
31992 innerRadius: innerRadius,
31993 outerRadius: outerRadius,
31994 thetaSegments: thetaSegments,
31995 phiSegments: phiSegments,
31996 thetaStart: thetaStart,
31997 thetaLength: thetaLength
32000 thetaSegments = Math.max( 3, thetaSegments );
32001 phiSegments = Math.max( 1, phiSegments );
32005 const indices = [];
32006 const vertices = [];
32007 const normals = [];
32010 // some helper variables
32012 let radius = innerRadius;
32013 const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
32014 const vertex = new Vector3();
32015 const uv = new Vector2();
32017 // generate vertices, normals and uvs
32019 for ( let j = 0; j <= phiSegments; j ++ ) {
32021 for ( let i = 0; i <= thetaSegments; i ++ ) {
32023 // values are generate from the inside of the ring to the outside
32025 const segment = thetaStart + i / thetaSegments * thetaLength;
32029 vertex.x = radius * Math.cos( segment );
32030 vertex.y = radius * Math.sin( segment );
32032 vertices.push( vertex.x, vertex.y, vertex.z );
32036 normals.push( 0, 0, 1 );
32040 uv.x = ( vertex.x / outerRadius + 1 ) / 2;
32041 uv.y = ( vertex.y / outerRadius + 1 ) / 2;
32043 uvs.push( uv.x, uv.y );
32047 // increase the radius for next row of vertices
32049 radius += radiusStep;
32055 for ( let j = 0; j < phiSegments; j ++ ) {
32057 const thetaSegmentLevel = j * ( thetaSegments + 1 );
32059 for ( let i = 0; i < thetaSegments; i ++ ) {
32061 const segment = i + thetaSegmentLevel;
32064 const b = segment + thetaSegments + 1;
32065 const c = segment + thetaSegments + 2;
32066 const d = segment + 1;
32070 indices.push( a, b, d );
32071 indices.push( b, c, d );
32079 this.setIndex( indices );
32080 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32081 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32082 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32088 class RingGeometry extends Geometry {
32090 constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
32094 this.type = 'RingGeometry';
32096 this.parameters = {
32097 innerRadius: innerRadius,
32098 outerRadius: outerRadius,
32099 thetaSegments: thetaSegments,
32100 phiSegments: phiSegments,
32101 thetaStart: thetaStart,
32102 thetaLength: thetaLength
32105 this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
32106 this.mergeVertices();
32112 class ShapeBufferGeometry extends BufferGeometry {
32114 constructor( shapes, curveSegments = 12 ) {
32117 this.type = 'ShapeBufferGeometry';
32119 this.parameters = {
32121 curveSegments: curveSegments
32126 const indices = [];
32127 const vertices = [];
32128 const normals = [];
32131 // helper variables
32133 let groupStart = 0;
32134 let groupCount = 0;
32136 // allow single and array values for "shapes" parameter
32138 if ( Array.isArray( shapes ) === false ) {
32140 addShape( shapes );
32144 for ( let i = 0; i < shapes.length; i ++ ) {
32146 addShape( shapes[ i ] );
32148 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
32150 groupStart += groupCount;
32159 this.setIndex( indices );
32160 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32161 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32162 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32165 // helper functions
32167 function addShape( shape ) {
32169 const indexOffset = vertices.length / 3;
32170 const points = shape.extractPoints( curveSegments );
32172 let shapeVertices = points.shape;
32173 const shapeHoles = points.holes;
32175 // check direction of vertices
32177 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
32179 shapeVertices = shapeVertices.reverse();
32183 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
32185 const shapeHole = shapeHoles[ i ];
32187 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
32189 shapeHoles[ i ] = shapeHole.reverse();
32195 const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
32197 // join vertices of inner and outer paths to a single array
32199 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
32201 const shapeHole = shapeHoles[ i ];
32202 shapeVertices = shapeVertices.concat( shapeHole );
32206 // vertices, normals, uvs
32208 for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
32210 const vertex = shapeVertices[ i ];
32212 vertices.push( vertex.x, vertex.y, 0 );
32213 normals.push( 0, 0, 1 );
32214 uvs.push( vertex.x, vertex.y ); // world uvs
32220 for ( let i = 0, l = faces.length; i < l; i ++ ) {
32222 const face = faces[ i ];
32224 const a = face[ 0 ] + indexOffset;
32225 const b = face[ 1 ] + indexOffset;
32226 const c = face[ 2 ] + indexOffset;
32228 indices.push( a, b, c );
32239 const data = BufferGeometry.prototype.toJSON.call( this );
32241 const shapes = this.parameters.shapes;
32243 return toJSON$2( shapes, data );
32249 function toJSON$2( shapes, data ) {
32253 if ( Array.isArray( shapes ) ) {
32255 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
32257 const shape = shapes[ i ];
32259 data.shapes.push( shape.uuid );
32265 data.shapes.push( shapes.uuid );
32273 class ShapeGeometry extends Geometry {
32275 constructor( shapes, curveSegments ) {
32278 this.type = 'ShapeGeometry';
32280 if ( typeof curveSegments === 'object' ) {
32282 console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
32284 curveSegments = curveSegments.curveSegments;
32288 this.parameters = {
32290 curveSegments: curveSegments
32293 this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
32294 this.mergeVertices();
32300 const data = Geometry.prototype.toJSON.call( this );
32302 const shapes = this.parameters.shapes;
32304 return toJSON$3( shapes, data );
32310 function toJSON$3( shapes, data ) {
32314 if ( Array.isArray( shapes ) ) {
32316 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
32318 const shape = shapes[ i ];
32320 data.shapes.push( shape.uuid );
32326 data.shapes.push( shapes.uuid );
32334 class SphereBufferGeometry extends BufferGeometry {
32336 constructor( radius = 1, widthSegments = 8, heightSegments = 6, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
32339 this.type = 'SphereBufferGeometry';
32341 this.parameters = {
32343 widthSegments: widthSegments,
32344 heightSegments: heightSegments,
32345 phiStart: phiStart,
32346 phiLength: phiLength,
32347 thetaStart: thetaStart,
32348 thetaLength: thetaLength
32351 widthSegments = Math.max( 3, Math.floor( widthSegments ) );
32352 heightSegments = Math.max( 2, Math.floor( heightSegments ) );
32354 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
32359 const vertex = new Vector3();
32360 const normal = new Vector3();
32364 const indices = [];
32365 const vertices = [];
32366 const normals = [];
32369 // generate vertices, normals and uvs
32371 for ( let iy = 0; iy <= heightSegments; iy ++ ) {
32373 const verticesRow = [];
32375 const v = iy / heightSegments;
32377 // special case for the poles
32381 if ( iy == 0 && thetaStart == 0 ) {
32383 uOffset = 0.5 / widthSegments;
32385 } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
32387 uOffset = - 0.5 / widthSegments;
32391 for ( let ix = 0; ix <= widthSegments; ix ++ ) {
32393 const u = ix / widthSegments;
32397 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
32398 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
32399 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
32401 vertices.push( vertex.x, vertex.y, vertex.z );
32405 normal.copy( vertex ).normalize();
32406 normals.push( normal.x, normal.y, normal.z );
32410 uvs.push( u + uOffset, 1 - v );
32412 verticesRow.push( index ++ );
32416 grid.push( verticesRow );
32422 for ( let iy = 0; iy < heightSegments; iy ++ ) {
32424 for ( let ix = 0; ix < widthSegments; ix ++ ) {
32426 const a = grid[ iy ][ ix + 1 ];
32427 const b = grid[ iy ][ ix ];
32428 const c = grid[ iy + 1 ][ ix ];
32429 const d = grid[ iy + 1 ][ ix + 1 ];
32431 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
32432 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
32440 this.setIndex( indices );
32441 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32442 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32443 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32449 class SphereGeometry extends Geometry {
32451 constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
32454 this.type = 'SphereGeometry';
32456 this.parameters = {
32458 widthSegments: widthSegments,
32459 heightSegments: heightSegments,
32460 phiStart: phiStart,
32461 phiLength: phiLength,
32462 thetaStart: thetaStart,
32463 thetaLength: thetaLength
32466 this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
32467 this.mergeVertices();
32473 class TetrahedronBufferGeometry extends PolyhedronBufferGeometry {
32475 constructor( radius = 1, detail = 0 ) {
32478 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
32482 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
32485 super( vertices, indices, radius, detail );
32487 this.type = 'TetrahedronBufferGeometry';
32489 this.parameters = {
32498 class TetrahedronGeometry extends Geometry {
32500 constructor( radius, detail ) {
32503 this.type = 'TetrahedronGeometry';
32505 this.parameters = {
32510 this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
32511 this.mergeVertices();
32521 * font: <THREE.Font>, // font
32523 * size: <float>, // size of the text
32524 * height: <float>, // thickness to extrude text
32525 * curveSegments: <int>, // number of points on the curves
32527 * bevelEnabled: <bool>, // turn on bevel
32528 * bevelThickness: <float>, // how deep into text bevel goes
32529 * bevelSize: <float>, // how far from text outline (including bevelOffset) is bevel
32530 * bevelOffset: <float> // how far from text outline does bevel start
32534 class TextBufferGeometry extends ExtrudeBufferGeometry {
32536 constructor( text, parameters = {} ) {
32538 const font = parameters.font;
32540 if ( ! ( font && font.isFont ) ) {
32542 console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
32543 return new BufferGeometry();
32547 const shapes = font.generateShapes( text, parameters.size );
32549 // translate parameters to ExtrudeGeometry API
32551 parameters.depth = parameters.height !== undefined ? parameters.height : 50;
32555 if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
32556 if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
32557 if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
32559 super( shapes, parameters );
32561 this.type = 'TextBufferGeometry';
32571 * font: <THREE.Font>, // font
32573 * size: <float>, // size of the text
32574 * height: <float>, // thickness to extrude text
32575 * curveSegments: <int>, // number of points on the curves
32577 * bevelEnabled: <bool>, // turn on bevel
32578 * bevelThickness: <float>, // how deep into text bevel goes
32579 * bevelSize: <float>, // how far from text outline (including bevelOffset) is bevel
32580 * bevelOffset: <float> // how far from text outline does bevel start
32584 class TextGeometry extends Geometry {
32586 constructor( text, parameters ) {
32589 this.type = 'TextGeometry';
32591 this.parameters = {
32593 parameters: parameters
32596 this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
32597 this.mergeVertices();
32603 class TorusBufferGeometry extends BufferGeometry {
32605 constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) {
32608 this.type = 'TorusBufferGeometry';
32610 this.parameters = {
32613 radialSegments: radialSegments,
32614 tubularSegments: tubularSegments,
32618 radialSegments = Math.floor( radialSegments );
32619 tubularSegments = Math.floor( tubularSegments );
32623 const indices = [];
32624 const vertices = [];
32625 const normals = [];
32628 // helper variables
32630 const center = new Vector3();
32631 const vertex = new Vector3();
32632 const normal = new Vector3();
32634 // generate vertices, normals and uvs
32636 for ( let j = 0; j <= radialSegments; j ++ ) {
32638 for ( let i = 0; i <= tubularSegments; i ++ ) {
32640 const u = i / tubularSegments * arc;
32641 const v = j / radialSegments * Math.PI * 2;
32645 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
32646 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
32647 vertex.z = tube * Math.sin( v );
32649 vertices.push( vertex.x, vertex.y, vertex.z );
32653 center.x = radius * Math.cos( u );
32654 center.y = radius * Math.sin( u );
32655 normal.subVectors( vertex, center ).normalize();
32657 normals.push( normal.x, normal.y, normal.z );
32661 uvs.push( i / tubularSegments );
32662 uvs.push( j / radialSegments );
32668 // generate indices
32670 for ( let j = 1; j <= radialSegments; j ++ ) {
32672 for ( let i = 1; i <= tubularSegments; i ++ ) {
32676 const a = ( tubularSegments + 1 ) * j + i - 1;
32677 const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
32678 const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
32679 const d = ( tubularSegments + 1 ) * j + i;
32683 indices.push( a, b, d );
32684 indices.push( b, c, d );
32692 this.setIndex( indices );
32693 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32694 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32695 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32701 class TorusGeometry extends Geometry {
32703 constructor( radius, tube, radialSegments, tubularSegments, arc ) {
32706 this.type = 'TorusGeometry';
32708 this.parameters = {
32711 radialSegments: radialSegments,
32712 tubularSegments: tubularSegments,
32716 this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
32717 this.mergeVertices();
32723 class TorusKnotBufferGeometry extends BufferGeometry {
32725 constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
32728 this.type = 'TorusKnotBufferGeometry';
32730 this.parameters = {
32733 tubularSegments: tubularSegments,
32734 radialSegments: radialSegments,
32739 tubularSegments = Math.floor( tubularSegments );
32740 radialSegments = Math.floor( radialSegments );
32744 const indices = [];
32745 const vertices = [];
32746 const normals = [];
32749 // helper variables
32751 const vertex = new Vector3();
32752 const normal = new Vector3();
32754 const P1 = new Vector3();
32755 const P2 = new Vector3();
32757 const B = new Vector3();
32758 const T = new Vector3();
32759 const N = new Vector3();
32761 // generate vertices, normals and uvs
32763 for ( let i = 0; i <= tubularSegments; ++ i ) {
32765 // the radian "u" is used to calculate the position on the torus curve of the current tubular segement
32767 const u = i / tubularSegments * p * Math.PI * 2;
32769 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
32770 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
32772 calculatePositionOnCurve( u, p, q, radius, P1 );
32773 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
32775 // calculate orthonormal basis
32777 T.subVectors( P2, P1 );
32778 N.addVectors( P2, P1 );
32779 B.crossVectors( T, N );
32780 N.crossVectors( B, T );
32782 // normalize B, N. T can be ignored, we don't use it
32787 for ( let j = 0; j <= radialSegments; ++ j ) {
32789 // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
32790 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
32792 const v = j / radialSegments * Math.PI * 2;
32793 const cx = - tube * Math.cos( v );
32794 const cy = tube * Math.sin( v );
32796 // now calculate the final vertex position.
32797 // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
32799 vertex.x = P1.x + ( cx * N.x + cy * B.x );
32800 vertex.y = P1.y + ( cx * N.y + cy * B.y );
32801 vertex.z = P1.z + ( cx * N.z + cy * B.z );
32803 vertices.push( vertex.x, vertex.y, vertex.z );
32805 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
32807 normal.subVectors( vertex, P1 ).normalize();
32809 normals.push( normal.x, normal.y, normal.z );
32813 uvs.push( i / tubularSegments );
32814 uvs.push( j / radialSegments );
32820 // generate indices
32822 for ( let j = 1; j <= tubularSegments; j ++ ) {
32824 for ( let i = 1; i <= radialSegments; i ++ ) {
32828 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
32829 const b = ( radialSegments + 1 ) * j + ( i - 1 );
32830 const c = ( radialSegments + 1 ) * j + i;
32831 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
32835 indices.push( a, b, d );
32836 indices.push( b, c, d );
32844 this.setIndex( indices );
32845 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32846 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32847 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32849 // this function calculates the current position on the torus curve
32851 function calculatePositionOnCurve( u, p, q, radius, position ) {
32853 const cu = Math.cos( u );
32854 const su = Math.sin( u );
32855 const quOverP = q / p * u;
32856 const cs = Math.cos( quOverP );
32858 position.x = radius * ( 2 + cs ) * 0.5 * cu;
32859 position.y = radius * ( 2 + cs ) * su * 0.5;
32860 position.z = radius * Math.sin( quOverP ) * 0.5;
32868 class TorusKnotGeometry extends Geometry {
32870 constructor( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
32873 this.type = 'TorusKnotGeometry';
32875 this.parameters = {
32878 tubularSegments: tubularSegments,
32879 radialSegments: radialSegments,
32884 if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
32886 this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
32887 this.mergeVertices();
32893 class TubeBufferGeometry extends BufferGeometry {
32895 constructor( path, tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
32898 this.type = 'TubeBufferGeometry';
32900 this.parameters = {
32902 tubularSegments: tubularSegments,
32904 radialSegments: radialSegments,
32908 const frames = path.computeFrenetFrames( tubularSegments, closed );
32910 // expose internals
32912 this.tangents = frames.tangents;
32913 this.normals = frames.normals;
32914 this.binormals = frames.binormals;
32916 // helper variables
32918 const vertex = new Vector3();
32919 const normal = new Vector3();
32920 const uv = new Vector2();
32921 let P = new Vector3();
32925 const vertices = [];
32926 const normals = [];
32928 const indices = [];
32930 // create buffer data
32932 generateBufferData();
32936 this.setIndex( indices );
32937 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32938 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32939 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32943 function generateBufferData() {
32945 for ( let i = 0; i < tubularSegments; i ++ ) {
32947 generateSegment( i );
32951 // if the geometry is not closed, generate the last row of vertices and normals
32952 // at the regular position on the given path
32954 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
32956 generateSegment( ( closed === false ) ? tubularSegments : 0 );
32958 // uvs are generated in a separate function.
32959 // this makes it easy compute correct values for closed geometries
32963 // finally create faces
32969 function generateSegment( i ) {
32971 // we use getPointAt to sample evenly distributed points from the given path
32973 P = path.getPointAt( i / tubularSegments, P );
32975 // retrieve corresponding normal and binormal
32977 const N = frames.normals[ i ];
32978 const B = frames.binormals[ i ];
32980 // generate normals and vertices for the current segment
32982 for ( let j = 0; j <= radialSegments; j ++ ) {
32984 const v = j / radialSegments * Math.PI * 2;
32986 const sin = Math.sin( v );
32987 const cos = - Math.cos( v );
32991 normal.x = ( cos * N.x + sin * B.x );
32992 normal.y = ( cos * N.y + sin * B.y );
32993 normal.z = ( cos * N.z + sin * B.z );
32994 normal.normalize();
32996 normals.push( normal.x, normal.y, normal.z );
33000 vertex.x = P.x + radius * normal.x;
33001 vertex.y = P.y + radius * normal.y;
33002 vertex.z = P.z + radius * normal.z;
33004 vertices.push( vertex.x, vertex.y, vertex.z );
33010 function generateIndices() {
33012 for ( let j = 1; j <= tubularSegments; j ++ ) {
33014 for ( let i = 1; i <= radialSegments; i ++ ) {
33016 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
33017 const b = ( radialSegments + 1 ) * j + ( i - 1 );
33018 const c = ( radialSegments + 1 ) * j + i;
33019 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
33023 indices.push( a, b, d );
33024 indices.push( b, c, d );
33032 function generateUVs() {
33034 for ( let i = 0; i <= tubularSegments; i ++ ) {
33036 for ( let j = 0; j <= radialSegments; j ++ ) {
33038 uv.x = i / tubularSegments;
33039 uv.y = j / radialSegments;
33041 uvs.push( uv.x, uv.y );
33052 const data = BufferGeometry.prototype.toJSON.call( this );
33054 data.path = this.parameters.path.toJSON();
33062 class TubeGeometry extends Geometry {
33064 constructor( path, tubularSegments, radius, radialSegments, closed, taper ) {
33067 this.type = 'TubeGeometry';
33069 this.parameters = {
33071 tubularSegments: tubularSegments,
33073 radialSegments: radialSegments,
33077 if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
33079 const bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
33081 // expose internals
33083 this.tangents = bufferGeometry.tangents;
33084 this.normals = bufferGeometry.normals;
33085 this.binormals = bufferGeometry.binormals;
33089 this.fromBufferGeometry( bufferGeometry );
33090 this.mergeVertices();
33096 class WireframeGeometry extends BufferGeometry {
33098 constructor( geometry ) {
33101 this.type = 'WireframeGeometry';
33105 const vertices = [];
33107 // helper variables
33109 const edge = [ 0, 0 ], edges = {};
33110 const keys = [ 'a', 'b', 'c' ];
33112 // different logic for Geometry and BufferGeometry
33114 if ( geometry && geometry.isGeometry ) {
33116 // create a data structure that contains all edges without duplicates
33118 const faces = geometry.faces;
33120 for ( let i = 0, l = faces.length; i < l; i ++ ) {
33122 const face = faces[ i ];
33124 for ( let j = 0; j < 3; j ++ ) {
33126 const edge1 = face[ keys[ j ] ];
33127 const edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
33128 edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
33129 edge[ 1 ] = Math.max( edge1, edge2 );
33131 const key = edge[ 0 ] + ',' + edge[ 1 ];
33133 if ( edges[ key ] === undefined ) {
33135 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
33143 // generate vertices
33145 for ( const key in edges ) {
33147 const e = edges[ key ];
33149 let vertex = geometry.vertices[ e.index1 ];
33150 vertices.push( vertex.x, vertex.y, vertex.z );
33152 vertex = geometry.vertices[ e.index2 ];
33153 vertices.push( vertex.x, vertex.y, vertex.z );
33157 } else if ( geometry && geometry.isBufferGeometry ) {
33159 const vertex = new Vector3();
33161 if ( geometry.index !== null ) {
33163 // indexed BufferGeometry
33165 const position = geometry.attributes.position;
33166 const indices = geometry.index;
33167 let groups = geometry.groups;
33169 if ( groups.length === 0 ) {
33171 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
33175 // create a data structure that contains all eges without duplicates
33177 for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
33179 const group = groups[ o ];
33181 const start = group.start;
33182 const count = group.count;
33184 for ( let i = start, l = ( start + count ); i < l; i += 3 ) {
33186 for ( let j = 0; j < 3; j ++ ) {
33188 const edge1 = indices.getX( i + j );
33189 const edge2 = indices.getX( i + ( j + 1 ) % 3 );
33190 edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
33191 edge[ 1 ] = Math.max( edge1, edge2 );
33193 const key = edge[ 0 ] + ',' + edge[ 1 ];
33195 if ( edges[ key ] === undefined ) {
33197 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
33207 // generate vertices
33209 for ( const key in edges ) {
33211 const e = edges[ key ];
33213 vertex.fromBufferAttribute( position, e.index1 );
33214 vertices.push( vertex.x, vertex.y, vertex.z );
33216 vertex.fromBufferAttribute( position, e.index2 );
33217 vertices.push( vertex.x, vertex.y, vertex.z );
33223 // non-indexed BufferGeometry
33225 const position = geometry.attributes.position;
33227 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
33229 for ( let j = 0; j < 3; j ++ ) {
33231 // three edges per triangle, an edge is represented as (index1, index2)
33232 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
33234 const index1 = 3 * i + j;
33235 vertex.fromBufferAttribute( position, index1 );
33236 vertices.push( vertex.x, vertex.y, vertex.z );
33238 const index2 = 3 * i + ( ( j + 1 ) % 3 );
33239 vertex.fromBufferAttribute( position, index2 );
33240 vertices.push( vertex.x, vertex.y, vertex.z );
33252 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33258 var Geometries = /*#__PURE__*/Object.freeze({
33260 BoxGeometry: BoxGeometry,
33261 BoxBufferGeometry: BoxBufferGeometry,
33262 CircleGeometry: CircleGeometry,
33263 CircleBufferGeometry: CircleBufferGeometry,
33264 ConeGeometry: ConeGeometry,
33265 ConeBufferGeometry: ConeBufferGeometry,
33266 CylinderGeometry: CylinderGeometry,
33267 CylinderBufferGeometry: CylinderBufferGeometry,
33268 DodecahedronGeometry: DodecahedronGeometry,
33269 DodecahedronBufferGeometry: DodecahedronBufferGeometry,
33270 EdgesGeometry: EdgesGeometry,
33271 ExtrudeGeometry: ExtrudeGeometry,
33272 ExtrudeBufferGeometry: ExtrudeBufferGeometry,
33273 IcosahedronGeometry: IcosahedronGeometry,
33274 IcosahedronBufferGeometry: IcosahedronBufferGeometry,
33275 LatheGeometry: LatheGeometry,
33276 LatheBufferGeometry: LatheBufferGeometry,
33277 OctahedronGeometry: OctahedronGeometry,
33278 OctahedronBufferGeometry: OctahedronBufferGeometry,
33279 ParametricGeometry: ParametricGeometry,
33280 ParametricBufferGeometry: ParametricBufferGeometry,
33281 PlaneGeometry: PlaneGeometry,
33282 PlaneBufferGeometry: PlaneBufferGeometry,
33283 PolyhedronGeometry: PolyhedronGeometry,
33284 PolyhedronBufferGeometry: PolyhedronBufferGeometry,
33285 RingGeometry: RingGeometry,
33286 RingBufferGeometry: RingBufferGeometry,
33287 ShapeGeometry: ShapeGeometry,
33288 ShapeBufferGeometry: ShapeBufferGeometry,
33289 SphereGeometry: SphereGeometry,
33290 SphereBufferGeometry: SphereBufferGeometry,
33291 TetrahedronGeometry: TetrahedronGeometry,
33292 TetrahedronBufferGeometry: TetrahedronBufferGeometry,
33293 TextGeometry: TextGeometry,
33294 TextBufferGeometry: TextBufferGeometry,
33295 TorusGeometry: TorusGeometry,
33296 TorusBufferGeometry: TorusBufferGeometry,
33297 TorusKnotGeometry: TorusKnotGeometry,
33298 TorusKnotBufferGeometry: TorusKnotBufferGeometry,
33299 TubeGeometry: TubeGeometry,
33300 TubeBufferGeometry: TubeBufferGeometry,
33301 WireframeGeometry: WireframeGeometry
33306 * color: <THREE.Color>
33310 function ShadowMaterial( parameters ) {
33312 Material.call( this );
33314 this.type = 'ShadowMaterial';
33316 this.color = new Color( 0x000000 );
33317 this.transparent = true;
33319 this.setValues( parameters );
33323 ShadowMaterial.prototype = Object.create( Material.prototype );
33324 ShadowMaterial.prototype.constructor = ShadowMaterial;
33326 ShadowMaterial.prototype.isShadowMaterial = true;
33328 ShadowMaterial.prototype.copy = function ( source ) {
33330 Material.prototype.copy.call( this, source );
33332 this.color.copy( source.color );
33338 function RawShaderMaterial( parameters ) {
33340 ShaderMaterial.call( this, parameters );
33342 this.type = 'RawShaderMaterial';
33346 RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
33347 RawShaderMaterial.prototype.constructor = RawShaderMaterial;
33349 RawShaderMaterial.prototype.isRawShaderMaterial = true;
33354 * roughness: <float>,
33355 * metalness: <float>,
33356 * opacity: <float>,
33358 * map: new THREE.Texture( <Image> ),
33360 * lightMap: new THREE.Texture( <Image> ),
33361 * lightMapIntensity: <float>
33363 * aoMap: new THREE.Texture( <Image> ),
33364 * aoMapIntensity: <float>
33367 * emissiveIntensity: <float>
33368 * emissiveMap: new THREE.Texture( <Image> ),
33370 * bumpMap: new THREE.Texture( <Image> ),
33371 * bumpScale: <float>,
33373 * normalMap: new THREE.Texture( <Image> ),
33374 * normalMapType: THREE.TangentSpaceNormalMap,
33375 * normalScale: <Vector2>,
33377 * displacementMap: new THREE.Texture( <Image> ),
33378 * displacementScale: <float>,
33379 * displacementBias: <float>,
33381 * roughnessMap: new THREE.Texture( <Image> ),
33383 * metalnessMap: new THREE.Texture( <Image> ),
33385 * alphaMap: new THREE.Texture( <Image> ),
33387 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33388 * envMapIntensity: <float>
33390 * refractionRatio: <float>,
33392 * wireframe: <boolean>,
33393 * wireframeLinewidth: <float>,
33395 * skinning: <bool>,
33396 * morphTargets: <bool>,
33397 * morphNormals: <bool>
33401 function MeshStandardMaterial( parameters ) {
33403 Material.call( this );
33405 this.defines = { 'STANDARD': '' };
33407 this.type = 'MeshStandardMaterial';
33409 this.color = new Color( 0xffffff ); // diffuse
33410 this.roughness = 1.0;
33411 this.metalness = 0.0;
33415 this.lightMap = null;
33416 this.lightMapIntensity = 1.0;
33419 this.aoMapIntensity = 1.0;
33421 this.emissive = new Color( 0x000000 );
33422 this.emissiveIntensity = 1.0;
33423 this.emissiveMap = null;
33425 this.bumpMap = null;
33426 this.bumpScale = 1;
33428 this.normalMap = null;
33429 this.normalMapType = TangentSpaceNormalMap;
33430 this.normalScale = new Vector2( 1, 1 );
33432 this.displacementMap = null;
33433 this.displacementScale = 1;
33434 this.displacementBias = 0;
33436 this.roughnessMap = null;
33438 this.metalnessMap = null;
33440 this.alphaMap = null;
33442 this.envMap = null;
33443 this.envMapIntensity = 1.0;
33445 this.refractionRatio = 0.98;
33447 this.wireframe = false;
33448 this.wireframeLinewidth = 1;
33449 this.wireframeLinecap = 'round';
33450 this.wireframeLinejoin = 'round';
33452 this.skinning = false;
33453 this.morphTargets = false;
33454 this.morphNormals = false;
33456 this.vertexTangents = false;
33458 this.setValues( parameters );
33462 MeshStandardMaterial.prototype = Object.create( Material.prototype );
33463 MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
33465 MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
33467 MeshStandardMaterial.prototype.copy = function ( source ) {
33469 Material.prototype.copy.call( this, source );
33471 this.defines = { 'STANDARD': '' };
33473 this.color.copy( source.color );
33474 this.roughness = source.roughness;
33475 this.metalness = source.metalness;
33477 this.map = source.map;
33479 this.lightMap = source.lightMap;
33480 this.lightMapIntensity = source.lightMapIntensity;
33482 this.aoMap = source.aoMap;
33483 this.aoMapIntensity = source.aoMapIntensity;
33485 this.emissive.copy( source.emissive );
33486 this.emissiveMap = source.emissiveMap;
33487 this.emissiveIntensity = source.emissiveIntensity;
33489 this.bumpMap = source.bumpMap;
33490 this.bumpScale = source.bumpScale;
33492 this.normalMap = source.normalMap;
33493 this.normalMapType = source.normalMapType;
33494 this.normalScale.copy( source.normalScale );
33496 this.displacementMap = source.displacementMap;
33497 this.displacementScale = source.displacementScale;
33498 this.displacementBias = source.displacementBias;
33500 this.roughnessMap = source.roughnessMap;
33502 this.metalnessMap = source.metalnessMap;
33504 this.alphaMap = source.alphaMap;
33506 this.envMap = source.envMap;
33507 this.envMapIntensity = source.envMapIntensity;
33509 this.refractionRatio = source.refractionRatio;
33511 this.wireframe = source.wireframe;
33512 this.wireframeLinewidth = source.wireframeLinewidth;
33513 this.wireframeLinecap = source.wireframeLinecap;
33514 this.wireframeLinejoin = source.wireframeLinejoin;
33516 this.skinning = source.skinning;
33517 this.morphTargets = source.morphTargets;
33518 this.morphNormals = source.morphNormals;
33520 this.vertexTangents = source.vertexTangents;
33528 * clearcoat: <float>,
33529 * clearcoatMap: new THREE.Texture( <Image> ),
33530 * clearcoatRoughness: <float>,
33531 * clearcoatRoughnessMap: new THREE.Texture( <Image> ),
33532 * clearcoatNormalScale: <Vector2>,
33533 * clearcoatNormalMap: new THREE.Texture( <Image> ),
33535 * reflectivity: <float>,
33540 * transmission: <float>,
33541 * transmissionMap: new THREE.Texture( <Image> )
33545 function MeshPhysicalMaterial( parameters ) {
33547 MeshStandardMaterial.call( this );
33556 this.type = 'MeshPhysicalMaterial';
33558 this.clearcoat = 0.0;
33559 this.clearcoatMap = null;
33560 this.clearcoatRoughness = 0.0;
33561 this.clearcoatRoughnessMap = null;
33562 this.clearcoatNormalScale = new Vector2( 1, 1 );
33563 this.clearcoatNormalMap = null;
33565 this.reflectivity = 0.5; // maps to F0 = 0.04
33567 Object.defineProperty( this, 'ior', {
33570 return ( 1 + 0.4 * this.reflectivity ) / ( 1 - 0.4 * this.reflectivity );
33573 set: function ( ior ) {
33575 this.reflectivity = MathUtils.clamp( 2.5 * ( ior - 1 ) / ( ior + 1 ), 0, 1 );
33580 this.sheen = null; // null will disable sheen bsdf
33582 this.transmission = 0.0;
33583 this.transmissionMap = null;
33585 this.setValues( parameters );
33589 MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
33590 MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
33592 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
33594 MeshPhysicalMaterial.prototype.copy = function ( source ) {
33596 MeshStandardMaterial.prototype.copy.call( this, source );
33605 this.clearcoat = source.clearcoat;
33606 this.clearcoatMap = source.clearcoatMap;
33607 this.clearcoatRoughness = source.clearcoatRoughness;
33608 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
33609 this.clearcoatNormalMap = source.clearcoatNormalMap;
33610 this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
33612 this.reflectivity = source.reflectivity;
33614 if ( source.sheen ) {
33616 this.sheen = ( this.sheen || new Color() ).copy( source.sheen );
33624 this.transmission = source.transmission;
33625 this.transmissionMap = source.transmissionMap;
33635 * shininess: <float>,
33636 * opacity: <float>,
33638 * map: new THREE.Texture( <Image> ),
33640 * lightMap: new THREE.Texture( <Image> ),
33641 * lightMapIntensity: <float>
33643 * aoMap: new THREE.Texture( <Image> ),
33644 * aoMapIntensity: <float>
33647 * emissiveIntensity: <float>
33648 * emissiveMap: new THREE.Texture( <Image> ),
33650 * bumpMap: new THREE.Texture( <Image> ),
33651 * bumpScale: <float>,
33653 * normalMap: new THREE.Texture( <Image> ),
33654 * normalMapType: THREE.TangentSpaceNormalMap,
33655 * normalScale: <Vector2>,
33657 * displacementMap: new THREE.Texture( <Image> ),
33658 * displacementScale: <float>,
33659 * displacementBias: <float>,
33661 * specularMap: new THREE.Texture( <Image> ),
33663 * alphaMap: new THREE.Texture( <Image> ),
33665 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33666 * combine: THREE.MultiplyOperation,
33667 * reflectivity: <float>,
33668 * refractionRatio: <float>,
33670 * wireframe: <boolean>,
33671 * wireframeLinewidth: <float>,
33673 * skinning: <bool>,
33674 * morphTargets: <bool>,
33675 * morphNormals: <bool>
33679 function MeshPhongMaterial( parameters ) {
33681 Material.call( this );
33683 this.type = 'MeshPhongMaterial';
33685 this.color = new Color( 0xffffff ); // diffuse
33686 this.specular = new Color( 0x111111 );
33687 this.shininess = 30;
33691 this.lightMap = null;
33692 this.lightMapIntensity = 1.0;
33695 this.aoMapIntensity = 1.0;
33697 this.emissive = new Color( 0x000000 );
33698 this.emissiveIntensity = 1.0;
33699 this.emissiveMap = null;
33701 this.bumpMap = null;
33702 this.bumpScale = 1;
33704 this.normalMap = null;
33705 this.normalMapType = TangentSpaceNormalMap;
33706 this.normalScale = new Vector2( 1, 1 );
33708 this.displacementMap = null;
33709 this.displacementScale = 1;
33710 this.displacementBias = 0;
33712 this.specularMap = null;
33714 this.alphaMap = null;
33716 this.envMap = null;
33717 this.combine = MultiplyOperation;
33718 this.reflectivity = 1;
33719 this.refractionRatio = 0.98;
33721 this.wireframe = false;
33722 this.wireframeLinewidth = 1;
33723 this.wireframeLinecap = 'round';
33724 this.wireframeLinejoin = 'round';
33726 this.skinning = false;
33727 this.morphTargets = false;
33728 this.morphNormals = false;
33730 this.setValues( parameters );
33734 MeshPhongMaterial.prototype = Object.create( Material.prototype );
33735 MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
33737 MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
33739 MeshPhongMaterial.prototype.copy = function ( source ) {
33741 Material.prototype.copy.call( this, source );
33743 this.color.copy( source.color );
33744 this.specular.copy( source.specular );
33745 this.shininess = source.shininess;
33747 this.map = source.map;
33749 this.lightMap = source.lightMap;
33750 this.lightMapIntensity = source.lightMapIntensity;
33752 this.aoMap = source.aoMap;
33753 this.aoMapIntensity = source.aoMapIntensity;
33755 this.emissive.copy( source.emissive );
33756 this.emissiveMap = source.emissiveMap;
33757 this.emissiveIntensity = source.emissiveIntensity;
33759 this.bumpMap = source.bumpMap;
33760 this.bumpScale = source.bumpScale;
33762 this.normalMap = source.normalMap;
33763 this.normalMapType = source.normalMapType;
33764 this.normalScale.copy( source.normalScale );
33766 this.displacementMap = source.displacementMap;
33767 this.displacementScale = source.displacementScale;
33768 this.displacementBias = source.displacementBias;
33770 this.specularMap = source.specularMap;
33772 this.alphaMap = source.alphaMap;
33774 this.envMap = source.envMap;
33775 this.combine = source.combine;
33776 this.reflectivity = source.reflectivity;
33777 this.refractionRatio = source.refractionRatio;
33779 this.wireframe = source.wireframe;
33780 this.wireframeLinewidth = source.wireframeLinewidth;
33781 this.wireframeLinecap = source.wireframeLinecap;
33782 this.wireframeLinejoin = source.wireframeLinejoin;
33784 this.skinning = source.skinning;
33785 this.morphTargets = source.morphTargets;
33786 this.morphNormals = source.morphNormals;
33796 * map: new THREE.Texture( <Image> ),
33797 * gradientMap: new THREE.Texture( <Image> ),
33799 * lightMap: new THREE.Texture( <Image> ),
33800 * lightMapIntensity: <float>
33802 * aoMap: new THREE.Texture( <Image> ),
33803 * aoMapIntensity: <float>
33806 * emissiveIntensity: <float>
33807 * emissiveMap: new THREE.Texture( <Image> ),
33809 * bumpMap: new THREE.Texture( <Image> ),
33810 * bumpScale: <float>,
33812 * normalMap: new THREE.Texture( <Image> ),
33813 * normalMapType: THREE.TangentSpaceNormalMap,
33814 * normalScale: <Vector2>,
33816 * displacementMap: new THREE.Texture( <Image> ),
33817 * displacementScale: <float>,
33818 * displacementBias: <float>,
33820 * alphaMap: new THREE.Texture( <Image> ),
33822 * wireframe: <boolean>,
33823 * wireframeLinewidth: <float>,
33825 * skinning: <bool>,
33826 * morphTargets: <bool>,
33827 * morphNormals: <bool>
33831 function MeshToonMaterial( parameters ) {
33833 Material.call( this );
33835 this.defines = { 'TOON': '' };
33837 this.type = 'MeshToonMaterial';
33839 this.color = new Color( 0xffffff );
33842 this.gradientMap = null;
33844 this.lightMap = null;
33845 this.lightMapIntensity = 1.0;
33848 this.aoMapIntensity = 1.0;
33850 this.emissive = new Color( 0x000000 );
33851 this.emissiveIntensity = 1.0;
33852 this.emissiveMap = null;
33854 this.bumpMap = null;
33855 this.bumpScale = 1;
33857 this.normalMap = null;
33858 this.normalMapType = TangentSpaceNormalMap;
33859 this.normalScale = new Vector2( 1, 1 );
33861 this.displacementMap = null;
33862 this.displacementScale = 1;
33863 this.displacementBias = 0;
33865 this.alphaMap = null;
33867 this.wireframe = false;
33868 this.wireframeLinewidth = 1;
33869 this.wireframeLinecap = 'round';
33870 this.wireframeLinejoin = 'round';
33872 this.skinning = false;
33873 this.morphTargets = false;
33874 this.morphNormals = false;
33876 this.setValues( parameters );
33880 MeshToonMaterial.prototype = Object.create( Material.prototype );
33881 MeshToonMaterial.prototype.constructor = MeshToonMaterial;
33883 MeshToonMaterial.prototype.isMeshToonMaterial = true;
33885 MeshToonMaterial.prototype.copy = function ( source ) {
33887 Material.prototype.copy.call( this, source );
33889 this.color.copy( source.color );
33891 this.map = source.map;
33892 this.gradientMap = source.gradientMap;
33894 this.lightMap = source.lightMap;
33895 this.lightMapIntensity = source.lightMapIntensity;
33897 this.aoMap = source.aoMap;
33898 this.aoMapIntensity = source.aoMapIntensity;
33900 this.emissive.copy( source.emissive );
33901 this.emissiveMap = source.emissiveMap;
33902 this.emissiveIntensity = source.emissiveIntensity;
33904 this.bumpMap = source.bumpMap;
33905 this.bumpScale = source.bumpScale;
33907 this.normalMap = source.normalMap;
33908 this.normalMapType = source.normalMapType;
33909 this.normalScale.copy( source.normalScale );
33911 this.displacementMap = source.displacementMap;
33912 this.displacementScale = source.displacementScale;
33913 this.displacementBias = source.displacementBias;
33915 this.alphaMap = source.alphaMap;
33917 this.wireframe = source.wireframe;
33918 this.wireframeLinewidth = source.wireframeLinewidth;
33919 this.wireframeLinecap = source.wireframeLinecap;
33920 this.wireframeLinejoin = source.wireframeLinejoin;
33922 this.skinning = source.skinning;
33923 this.morphTargets = source.morphTargets;
33924 this.morphNormals = source.morphNormals;
33932 * opacity: <float>,
33934 * bumpMap: new THREE.Texture( <Image> ),
33935 * bumpScale: <float>,
33937 * normalMap: new THREE.Texture( <Image> ),
33938 * normalMapType: THREE.TangentSpaceNormalMap,
33939 * normalScale: <Vector2>,
33941 * displacementMap: new THREE.Texture( <Image> ),
33942 * displacementScale: <float>,
33943 * displacementBias: <float>,
33945 * wireframe: <boolean>,
33946 * wireframeLinewidth: <float>
33948 * skinning: <bool>,
33949 * morphTargets: <bool>,
33950 * morphNormals: <bool>
33954 function MeshNormalMaterial( parameters ) {
33956 Material.call( this );
33958 this.type = 'MeshNormalMaterial';
33960 this.bumpMap = null;
33961 this.bumpScale = 1;
33963 this.normalMap = null;
33964 this.normalMapType = TangentSpaceNormalMap;
33965 this.normalScale = new Vector2( 1, 1 );
33967 this.displacementMap = null;
33968 this.displacementScale = 1;
33969 this.displacementBias = 0;
33971 this.wireframe = false;
33972 this.wireframeLinewidth = 1;
33976 this.skinning = false;
33977 this.morphTargets = false;
33978 this.morphNormals = false;
33980 this.setValues( parameters );
33984 MeshNormalMaterial.prototype = Object.create( Material.prototype );
33985 MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
33987 MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
33989 MeshNormalMaterial.prototype.copy = function ( source ) {
33991 Material.prototype.copy.call( this, source );
33993 this.bumpMap = source.bumpMap;
33994 this.bumpScale = source.bumpScale;
33996 this.normalMap = source.normalMap;
33997 this.normalMapType = source.normalMapType;
33998 this.normalScale.copy( source.normalScale );
34000 this.displacementMap = source.displacementMap;
34001 this.displacementScale = source.displacementScale;
34002 this.displacementBias = source.displacementBias;
34004 this.wireframe = source.wireframe;
34005 this.wireframeLinewidth = source.wireframeLinewidth;
34007 this.skinning = source.skinning;
34008 this.morphTargets = source.morphTargets;
34009 this.morphNormals = source.morphNormals;
34018 * opacity: <float>,
34020 * map: new THREE.Texture( <Image> ),
34022 * lightMap: new THREE.Texture( <Image> ),
34023 * lightMapIntensity: <float>
34025 * aoMap: new THREE.Texture( <Image> ),
34026 * aoMapIntensity: <float>
34029 * emissiveIntensity: <float>
34030 * emissiveMap: new THREE.Texture( <Image> ),
34032 * specularMap: new THREE.Texture( <Image> ),
34034 * alphaMap: new THREE.Texture( <Image> ),
34036 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
34037 * combine: THREE.Multiply,
34038 * reflectivity: <float>,
34039 * refractionRatio: <float>,
34041 * wireframe: <boolean>,
34042 * wireframeLinewidth: <float>,
34044 * skinning: <bool>,
34045 * morphTargets: <bool>,
34046 * morphNormals: <bool>
34050 function MeshLambertMaterial( parameters ) {
34052 Material.call( this );
34054 this.type = 'MeshLambertMaterial';
34056 this.color = new Color( 0xffffff ); // diffuse
34060 this.lightMap = null;
34061 this.lightMapIntensity = 1.0;
34064 this.aoMapIntensity = 1.0;
34066 this.emissive = new Color( 0x000000 );
34067 this.emissiveIntensity = 1.0;
34068 this.emissiveMap = null;
34070 this.specularMap = null;
34072 this.alphaMap = null;
34074 this.envMap = null;
34075 this.combine = MultiplyOperation;
34076 this.reflectivity = 1;
34077 this.refractionRatio = 0.98;
34079 this.wireframe = false;
34080 this.wireframeLinewidth = 1;
34081 this.wireframeLinecap = 'round';
34082 this.wireframeLinejoin = 'round';
34084 this.skinning = false;
34085 this.morphTargets = false;
34086 this.morphNormals = false;
34088 this.setValues( parameters );
34092 MeshLambertMaterial.prototype = Object.create( Material.prototype );
34093 MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
34095 MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
34097 MeshLambertMaterial.prototype.copy = function ( source ) {
34099 Material.prototype.copy.call( this, source );
34101 this.color.copy( source.color );
34103 this.map = source.map;
34105 this.lightMap = source.lightMap;
34106 this.lightMapIntensity = source.lightMapIntensity;
34108 this.aoMap = source.aoMap;
34109 this.aoMapIntensity = source.aoMapIntensity;
34111 this.emissive.copy( source.emissive );
34112 this.emissiveMap = source.emissiveMap;
34113 this.emissiveIntensity = source.emissiveIntensity;
34115 this.specularMap = source.specularMap;
34117 this.alphaMap = source.alphaMap;
34119 this.envMap = source.envMap;
34120 this.combine = source.combine;
34121 this.reflectivity = source.reflectivity;
34122 this.refractionRatio = source.refractionRatio;
34124 this.wireframe = source.wireframe;
34125 this.wireframeLinewidth = source.wireframeLinewidth;
34126 this.wireframeLinecap = source.wireframeLinecap;
34127 this.wireframeLinejoin = source.wireframeLinejoin;
34129 this.skinning = source.skinning;
34130 this.morphTargets = source.morphTargets;
34131 this.morphNormals = source.morphNormals;
34140 * opacity: <float>,
34142 * matcap: new THREE.Texture( <Image> ),
34144 * map: new THREE.Texture( <Image> ),
34146 * bumpMap: new THREE.Texture( <Image> ),
34147 * bumpScale: <float>,
34149 * normalMap: new THREE.Texture( <Image> ),
34150 * normalMapType: THREE.TangentSpaceNormalMap,
34151 * normalScale: <Vector2>,
34153 * displacementMap: new THREE.Texture( <Image> ),
34154 * displacementScale: <float>,
34155 * displacementBias: <float>,
34157 * alphaMap: new THREE.Texture( <Image> ),
34159 * skinning: <bool>,
34160 * morphTargets: <bool>,
34161 * morphNormals: <bool>
34165 function MeshMatcapMaterial( parameters ) {
34167 Material.call( this );
34169 this.defines = { 'MATCAP': '' };
34171 this.type = 'MeshMatcapMaterial';
34173 this.color = new Color( 0xffffff ); // diffuse
34175 this.matcap = null;
34179 this.bumpMap = null;
34180 this.bumpScale = 1;
34182 this.normalMap = null;
34183 this.normalMapType = TangentSpaceNormalMap;
34184 this.normalScale = new Vector2( 1, 1 );
34186 this.displacementMap = null;
34187 this.displacementScale = 1;
34188 this.displacementBias = 0;
34190 this.alphaMap = null;
34192 this.skinning = false;
34193 this.morphTargets = false;
34194 this.morphNormals = false;
34196 this.setValues( parameters );
34200 MeshMatcapMaterial.prototype = Object.create( Material.prototype );
34201 MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial;
34203 MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true;
34205 MeshMatcapMaterial.prototype.copy = function ( source ) {
34207 Material.prototype.copy.call( this, source );
34209 this.defines = { 'MATCAP': '' };
34211 this.color.copy( source.color );
34213 this.matcap = source.matcap;
34215 this.map = source.map;
34217 this.bumpMap = source.bumpMap;
34218 this.bumpScale = source.bumpScale;
34220 this.normalMap = source.normalMap;
34221 this.normalMapType = source.normalMapType;
34222 this.normalScale.copy( source.normalScale );
34224 this.displacementMap = source.displacementMap;
34225 this.displacementScale = source.displacementScale;
34226 this.displacementBias = source.displacementBias;
34228 this.alphaMap = source.alphaMap;
34230 this.skinning = source.skinning;
34231 this.morphTargets = source.morphTargets;
34232 this.morphNormals = source.morphNormals;
34241 * opacity: <float>,
34243 * linewidth: <float>,
34246 * dashSize: <float>,
34251 function LineDashedMaterial( parameters ) {
34253 LineBasicMaterial.call( this );
34255 this.type = 'LineDashedMaterial';
34261 this.setValues( parameters );
34265 LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
34266 LineDashedMaterial.prototype.constructor = LineDashedMaterial;
34268 LineDashedMaterial.prototype.isLineDashedMaterial = true;
34270 LineDashedMaterial.prototype.copy = function ( source ) {
34272 LineBasicMaterial.prototype.copy.call( this, source );
34274 this.scale = source.scale;
34275 this.dashSize = source.dashSize;
34276 this.gapSize = source.gapSize;
34282 var Materials = /*#__PURE__*/Object.freeze({
34284 ShadowMaterial: ShadowMaterial,
34285 SpriteMaterial: SpriteMaterial,
34286 RawShaderMaterial: RawShaderMaterial,
34287 ShaderMaterial: ShaderMaterial,
34288 PointsMaterial: PointsMaterial,
34289 MeshPhysicalMaterial: MeshPhysicalMaterial,
34290 MeshStandardMaterial: MeshStandardMaterial,
34291 MeshPhongMaterial: MeshPhongMaterial,
34292 MeshToonMaterial: MeshToonMaterial,
34293 MeshNormalMaterial: MeshNormalMaterial,
34294 MeshLambertMaterial: MeshLambertMaterial,
34295 MeshDepthMaterial: MeshDepthMaterial,
34296 MeshDistanceMaterial: MeshDistanceMaterial,
34297 MeshBasicMaterial: MeshBasicMaterial,
34298 MeshMatcapMaterial: MeshMatcapMaterial,
34299 LineDashedMaterial: LineDashedMaterial,
34300 LineBasicMaterial: LineBasicMaterial,
34304 const AnimationUtils = {
34306 // same as Array.prototype.slice, but also works on typed arrays
34307 arraySlice: function ( array, from, to ) {
34309 if ( AnimationUtils.isTypedArray( array ) ) {
34311 // in ios9 array.subarray(from, undefined) will return empty array
34312 // but array.subarray(from) or array.subarray(from, len) is correct
34313 return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
34317 return array.slice( from, to );
34321 // converts an array to a specific type
34322 convertArray: function ( array, type, forceClone ) {
34324 if ( ! array || // let 'undefined' and 'null' pass
34325 ! forceClone && array.constructor === type ) return array;
34327 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
34329 return new type( array ); // create typed array
34333 return Array.prototype.slice.call( array ); // create Array
34337 isTypedArray: function ( object ) {
34339 return ArrayBuffer.isView( object ) &&
34340 ! ( object instanceof DataView );
34344 // returns an array by which times and values can be sorted
34345 getKeyframeOrder: function ( times ) {
34347 function compareTime( i, j ) {
34349 return times[ i ] - times[ j ];
34353 const n = times.length;
34354 const result = new Array( n );
34355 for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
34357 result.sort( compareTime );
34363 // uses the array previously returned by 'getKeyframeOrder' to sort data
34364 sortedArray: function ( values, stride, order ) {
34366 const nValues = values.length;
34367 const result = new values.constructor( nValues );
34369 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
34371 const srcOffset = order[ i ] * stride;
34373 for ( let j = 0; j !== stride; ++ j ) {
34375 result[ dstOffset ++ ] = values[ srcOffset + j ];
34385 // function for parsing AOS keyframe formats
34386 flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
34388 let i = 1, key = jsonKeys[ 0 ];
34390 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
34392 key = jsonKeys[ i ++ ];
34396 if ( key === undefined ) return; // no data
34398 let value = key[ valuePropertyName ];
34399 if ( value === undefined ) return; // no data
34401 if ( Array.isArray( value ) ) {
34405 value = key[ valuePropertyName ];
34407 if ( value !== undefined ) {
34409 times.push( key.time );
34410 values.push.apply( values, value ); // push all elements
34414 key = jsonKeys[ i ++ ];
34416 } while ( key !== undefined );
34418 } else if ( value.toArray !== undefined ) {
34420 // ...assume THREE.Math-ish
34424 value = key[ valuePropertyName ];
34426 if ( value !== undefined ) {
34428 times.push( key.time );
34429 value.toArray( values, values.length );
34433 key = jsonKeys[ i ++ ];
34435 } while ( key !== undefined );
34439 // otherwise push as-is
34443 value = key[ valuePropertyName ];
34445 if ( value !== undefined ) {
34447 times.push( key.time );
34448 values.push( value );
34452 key = jsonKeys[ i ++ ];
34454 } while ( key !== undefined );
34460 subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) {
34462 const clip = sourceClip.clone();
34468 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34470 const track = clip.tracks[ i ];
34471 const valueSize = track.getValueSize();
34476 for ( let j = 0; j < track.times.length; ++ j ) {
34478 const frame = track.times[ j ] * fps;
34480 if ( frame < startFrame || frame >= endFrame ) continue;
34482 times.push( track.times[ j ] );
34484 for ( let k = 0; k < valueSize; ++ k ) {
34486 values.push( track.values[ j * valueSize + k ] );
34492 if ( times.length === 0 ) continue;
34494 track.times = AnimationUtils.convertArray( times, track.times.constructor );
34495 track.values = AnimationUtils.convertArray( values, track.values.constructor );
34497 tracks.push( track );
34501 clip.tracks = tracks;
34503 // find minimum .times value across all tracks in the trimmed clip
34505 let minStartTime = Infinity;
34507 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34509 if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
34511 minStartTime = clip.tracks[ i ].times[ 0 ];
34517 // shift all tracks such that clip begins at t=0
34519 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34521 clip.tracks[ i ].shift( - 1 * minStartTime );
34525 clip.resetDuration();
34531 makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
34533 if ( fps <= 0 ) fps = 30;
34535 const numTracks = referenceClip.tracks.length;
34536 const referenceTime = referenceFrame / fps;
34538 // Make each track's values relative to the values at the reference frame
34539 for ( let i = 0; i < numTracks; ++ i ) {
34541 const referenceTrack = referenceClip.tracks[ i ];
34542 const referenceTrackType = referenceTrack.ValueTypeName;
34544 // Skip this track if it's non-numeric
34545 if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
34547 // Find the track in the target clip whose name and type matches the reference track
34548 const targetTrack = targetClip.tracks.find( function ( track ) {
34550 return track.name === referenceTrack.name
34551 && track.ValueTypeName === referenceTrackType;
34555 if ( targetTrack === undefined ) continue;
34557 let referenceOffset = 0;
34558 const referenceValueSize = referenceTrack.getValueSize();
34560 if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
34562 referenceOffset = referenceValueSize / 3;
34566 let targetOffset = 0;
34567 const targetValueSize = targetTrack.getValueSize();
34569 if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
34571 targetOffset = targetValueSize / 3;
34575 const lastIndex = referenceTrack.times.length - 1;
34576 let referenceValue;
34578 // Find the value to subtract out of the track
34579 if ( referenceTime <= referenceTrack.times[ 0 ] ) {
34581 // Reference frame is earlier than the first keyframe, so just use the first keyframe
34582 const startIndex = referenceOffset;
34583 const endIndex = referenceValueSize - referenceOffset;
34584 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
34586 } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
34588 // Reference frame is after the last keyframe, so just use the last keyframe
34589 const startIndex = lastIndex * referenceValueSize + referenceOffset;
34590 const endIndex = startIndex + referenceValueSize - referenceOffset;
34591 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
34595 // Interpolate to the reference value
34596 const interpolant = referenceTrack.createInterpolant();
34597 const startIndex = referenceOffset;
34598 const endIndex = referenceValueSize - referenceOffset;
34599 interpolant.evaluate( referenceTime );
34600 referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex );
34604 // Conjugate the quaternion
34605 if ( referenceTrackType === 'quaternion' ) {
34607 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
34608 referenceQuat.toArray( referenceValue );
34612 // Subtract the reference value from all of the track values
34614 const numTimes = targetTrack.times.length;
34615 for ( let j = 0; j < numTimes; ++ j ) {
34617 const valueStart = j * targetValueSize + targetOffset;
34619 if ( referenceTrackType === 'quaternion' ) {
34621 // Multiply the conjugate for quaternion track types
34622 Quaternion.multiplyQuaternionsFlat(
34623 targetTrack.values,
34627 targetTrack.values,
34633 const valueEnd = targetValueSize - targetOffset * 2;
34635 // Subtract each value for all other numeric track types
34636 for ( let k = 0; k < valueEnd; ++ k ) {
34638 targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
34648 targetClip.blendMode = AdditiveAnimationBlendMode;
34657 * Abstract base class of interpolants over parametric samples.
34659 * The parameter domain is one dimensional, typically the time or a path
34660 * along a curve defined by the data.
34662 * The sample values can have any dimensionality and derived classes may
34663 * apply special interpretations to the data.
34665 * This class provides the interval seek in a Template Method, deferring
34666 * the actual interpolation to derived classes.
34668 * Time complexity is O(1) for linear access crossing at most two points
34669 * and O(log N) for random access, where N is the number of positions.
34673 * http://www.oodesign.com/template-method-pattern.html
34677 function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
34679 this.parameterPositions = parameterPositions;
34680 this._cachedIndex = 0;
34682 this.resultBuffer = resultBuffer !== undefined ?
34683 resultBuffer : new sampleValues.constructor( sampleSize );
34684 this.sampleValues = sampleValues;
34685 this.valueSize = sampleSize;
34689 Object.assign( Interpolant.prototype, {
34691 evaluate: function ( t ) {
34693 const pp = this.parameterPositions;
34694 let i1 = this._cachedIndex,
34698 validate_interval: {
34706 //- See http://jsperf.com/comparison-to-undefined/3
34709 //- if ( t >= t1 || t1 === undefined ) {
34710 forward_scan: if ( ! ( t < t1 ) ) {
34712 for ( let giveUpAt = i1 + 2; ; ) {
34714 if ( t1 === undefined ) {
34716 if ( t < t0 ) break forward_scan;
34721 this._cachedIndex = i1;
34722 return this.afterEnd_( i1 - 1, t, t0 );
34726 if ( i1 === giveUpAt ) break; // this loop
34733 // we have arrived at the sought interval
34740 // prepare binary search on the right side of the index
34747 //- if ( t < t0 || t0 === undefined ) {
34748 if ( ! ( t >= t0 ) ) {
34752 const t1global = pp[ 1 ];
34754 if ( t < t1global ) {
34756 i1 = 2; // + 1, using the scan for the details
34761 // linear reverse scan
34763 for ( let giveUpAt = i1 - 2; ; ) {
34765 if ( t0 === undefined ) {
34769 this._cachedIndex = 0;
34770 return this.beforeStart_( 0, t, t1 );
34774 if ( i1 === giveUpAt ) break; // this loop
34777 t0 = pp[ -- i1 - 1 ];
34781 // we have arrived at the sought interval
34788 // prepare binary search on the left side of the index
34795 // the interval is valid
34797 break validate_interval;
34803 while ( i1 < right ) {
34805 const mid = ( i1 + right ) >>> 1;
34807 if ( t < pp[ mid ] ) {
34822 // check boundary cases, again
34824 if ( t0 === undefined ) {
34826 this._cachedIndex = 0;
34827 return this.beforeStart_( 0, t, t1 );
34831 if ( t1 === undefined ) {
34834 this._cachedIndex = i1;
34835 return this.afterEnd_( i1 - 1, t0, t );
34841 this._cachedIndex = i1;
34843 this.intervalChanged_( i1, t0, t1 );
34845 } // validate_interval
34847 return this.interpolate_( i1, t0, t, t1 );
34851 settings: null, // optional, subclass-specific settings structure
34852 // Note: The indirection allows central control of many interpolants.
34854 // --- Protected interface
34856 DefaultSettings_: {},
34858 getSettings_: function () {
34860 return this.settings || this.DefaultSettings_;
34864 copySampleValue_: function ( index ) {
34866 // copies a sample value to the result buffer
34868 const result = this.resultBuffer,
34869 values = this.sampleValues,
34870 stride = this.valueSize,
34871 offset = index * stride;
34873 for ( let i = 0; i !== stride; ++ i ) {
34875 result[ i ] = values[ offset + i ];
34883 // Template methods for derived classes:
34885 interpolate_: function ( /* i1, t0, t, t1 */ ) {
34887 throw new Error( 'call to abstract method' );
34888 // implementations shall return this.resultBuffer
34892 intervalChanged_: function ( /* i1, t0, t1 */ ) {
34900 // DECLARE ALIAS AFTER assign prototype
34901 Object.assign( Interpolant.prototype, {
34903 //( 0, t, t0 ), returns this.resultBuffer
34904 beforeStart_: Interpolant.prototype.copySampleValue_,
34906 //( N-1, tN-1, t ), returns this.resultBuffer
34907 afterEnd_: Interpolant.prototype.copySampleValue_,
34912 * Fast and simple cubic spline interpolant.
34914 * It was derived from a Hermitian construction setting the first derivative
34915 * at each sample position to the linear slope between neighboring positions
34916 * over their parameter interval.
34919 function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
34921 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
34923 this._weightPrev = - 0;
34924 this._offsetPrev = - 0;
34925 this._weightNext = - 0;
34926 this._offsetNext = - 0;
34930 CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
34932 constructor: CubicInterpolant,
34934 DefaultSettings_: {
34936 endingStart: ZeroCurvatureEnding,
34937 endingEnd: ZeroCurvatureEnding
34941 intervalChanged_: function ( i1, t0, t1 ) {
34943 const pp = this.parameterPositions;
34944 let iPrev = i1 - 2,
34947 tPrev = pp[ iPrev ],
34948 tNext = pp[ iNext ];
34950 if ( tPrev === undefined ) {
34952 switch ( this.getSettings_().endingStart ) {
34954 case ZeroSlopeEnding:
34958 tPrev = 2 * t0 - t1;
34962 case WrapAroundEnding:
34964 // use the other end of the curve
34965 iPrev = pp.length - 2;
34966 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
34970 default: // ZeroCurvatureEnding
34972 // f''(t0) = 0 a.k.a. Natural Spline
34980 if ( tNext === undefined ) {
34982 switch ( this.getSettings_().endingEnd ) {
34984 case ZeroSlopeEnding:
34988 tNext = 2 * t1 - t0;
34992 case WrapAroundEnding:
34994 // use the other end of the curve
34996 tNext = t1 + pp[ 1 ] - pp[ 0 ];
35000 default: // ZeroCurvatureEnding
35002 // f''(tN) = 0, a.k.a. Natural Spline
35010 const halfDt = ( t1 - t0 ) * 0.5,
35011 stride = this.valueSize;
35013 this._weightPrev = halfDt / ( t0 - tPrev );
35014 this._weightNext = halfDt / ( tNext - t1 );
35015 this._offsetPrev = iPrev * stride;
35016 this._offsetNext = iNext * stride;
35020 interpolate_: function ( i1, t0, t, t1 ) {
35022 const result = this.resultBuffer,
35023 values = this.sampleValues,
35024 stride = this.valueSize,
35026 o1 = i1 * stride, o0 = o1 - stride,
35027 oP = this._offsetPrev, oN = this._offsetNext,
35028 wP = this._weightPrev, wN = this._weightNext,
35030 p = ( t - t0 ) / ( t1 - t0 ),
35034 // evaluate polynomials
35036 const sP = - wP * ppp + 2 * wP * pp - wP * p;
35037 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
35038 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
35039 const sN = wN * ppp - wN * pp;
35041 // combine data linearly
35043 for ( let i = 0; i !== stride; ++ i ) {
35046 sP * values[ oP + i ] +
35047 s0 * values[ o0 + i ] +
35048 s1 * values[ o1 + i ] +
35049 sN * values[ oN + i ];
35059 function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
35061 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
35065 LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
35067 constructor: LinearInterpolant,
35069 interpolate_: function ( i1, t0, t, t1 ) {
35071 const result = this.resultBuffer,
35072 values = this.sampleValues,
35073 stride = this.valueSize,
35075 offset1 = i1 * stride,
35076 offset0 = offset1 - stride,
35078 weight1 = ( t - t0 ) / ( t1 - t0 ),
35079 weight0 = 1 - weight1;
35081 for ( let i = 0; i !== stride; ++ i ) {
35084 values[ offset0 + i ] * weight0 +
35085 values[ offset1 + i ] * weight1;
35097 * Interpolant that evaluates to the sample value at the position preceeding
35101 function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
35103 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
35107 DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
35109 constructor: DiscreteInterpolant,
35111 interpolate_: function ( i1 /*, t0, t, t1 */ ) {
35113 return this.copySampleValue_( i1 - 1 );
35119 function KeyframeTrack( name, times, values, interpolation ) {
35121 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
35122 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
35126 this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
35127 this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
35129 this.setInterpolation( interpolation || this.DefaultInterpolation );
35135 Object.assign( KeyframeTrack, {
35137 // Serialization (in static context, because of constructor invocation
35138 // and automatic invocation of .toJSON):
35140 toJSON: function ( track ) {
35142 const trackType = track.constructor;
35146 // derived classes can define a static toJSON method
35147 if ( trackType.toJSON !== undefined ) {
35149 json = trackType.toJSON( track );
35153 // by default, we assume the data can be serialized as-is
35156 'name': track.name,
35157 'times': AnimationUtils.convertArray( track.times, Array ),
35158 'values': AnimationUtils.convertArray( track.values, Array )
35162 const interpolation = track.getInterpolation();
35164 if ( interpolation !== track.DefaultInterpolation ) {
35166 json.interpolation = interpolation;
35172 json.type = track.ValueTypeName; // mandatory
35180 Object.assign( KeyframeTrack.prototype, {
35182 constructor: KeyframeTrack,
35184 TimeBufferType: Float32Array,
35186 ValueBufferType: Float32Array,
35188 DefaultInterpolation: InterpolateLinear,
35190 InterpolantFactoryMethodDiscrete: function ( result ) {
35192 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
35196 InterpolantFactoryMethodLinear: function ( result ) {
35198 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
35202 InterpolantFactoryMethodSmooth: function ( result ) {
35204 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
35208 setInterpolation: function ( interpolation ) {
35212 switch ( interpolation ) {
35214 case InterpolateDiscrete:
35216 factoryMethod = this.InterpolantFactoryMethodDiscrete;
35220 case InterpolateLinear:
35222 factoryMethod = this.InterpolantFactoryMethodLinear;
35226 case InterpolateSmooth:
35228 factoryMethod = this.InterpolantFactoryMethodSmooth;
35234 if ( factoryMethod === undefined ) {
35236 const message = "unsupported interpolation for " +
35237 this.ValueTypeName + " keyframe track named " + this.name;
35239 if ( this.createInterpolant === undefined ) {
35241 // fall back to default, unless the default itself is messed up
35242 if ( interpolation !== this.DefaultInterpolation ) {
35244 this.setInterpolation( this.DefaultInterpolation );
35248 throw new Error( message ); // fatal, in this case
35254 console.warn( 'THREE.KeyframeTrack:', message );
35259 this.createInterpolant = factoryMethod;
35265 getInterpolation: function () {
35267 switch ( this.createInterpolant ) {
35269 case this.InterpolantFactoryMethodDiscrete:
35271 return InterpolateDiscrete;
35273 case this.InterpolantFactoryMethodLinear:
35275 return InterpolateLinear;
35277 case this.InterpolantFactoryMethodSmooth:
35279 return InterpolateSmooth;
35285 getValueSize: function () {
35287 return this.values.length / this.times.length;
35291 // move all keyframes either forwards or backwards in time
35292 shift: function ( timeOffset ) {
35294 if ( timeOffset !== 0.0 ) {
35296 const times = this.times;
35298 for ( let i = 0, n = times.length; i !== n; ++ i ) {
35300 times[ i ] += timeOffset;
35310 // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
35311 scale: function ( timeScale ) {
35313 if ( timeScale !== 1.0 ) {
35315 const times = this.times;
35317 for ( let i = 0, n = times.length; i !== n; ++ i ) {
35319 times[ i ] *= timeScale;
35329 // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
35330 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
35331 trim: function ( startTime, endTime ) {
35333 const times = this.times,
35334 nKeys = times.length;
35339 while ( from !== nKeys && times[ from ] < startTime ) {
35345 while ( to !== - 1 && times[ to ] > endTime ) {
35351 ++ to; // inclusive -> exclusive bound
35353 if ( from !== 0 || to !== nKeys ) {
35355 // empty tracks are forbidden, so keep at least one keyframe
35356 if ( from >= to ) {
35358 to = Math.max( to, 1 );
35363 const stride = this.getValueSize();
35364 this.times = AnimationUtils.arraySlice( times, from, to );
35365 this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
35373 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
35374 validate: function () {
35378 const valueSize = this.getValueSize();
35379 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
35381 console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
35386 const times = this.times,
35387 values = this.values,
35389 nKeys = times.length;
35391 if ( nKeys === 0 ) {
35393 console.error( 'THREE.KeyframeTrack: Track is empty.', this );
35398 let prevTime = null;
35400 for ( let i = 0; i !== nKeys; i ++ ) {
35402 const currTime = times[ i ];
35404 if ( typeof currTime === 'number' && isNaN( currTime ) ) {
35406 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
35412 if ( prevTime !== null && prevTime > currTime ) {
35414 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
35420 prevTime = currTime;
35424 if ( values !== undefined ) {
35426 if ( AnimationUtils.isTypedArray( values ) ) {
35428 for ( let i = 0, n = values.length; i !== n; ++ i ) {
35430 const value = values[ i ];
35432 if ( isNaN( value ) ) {
35434 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
35450 // removes equivalent sequential keys as common in morph target sequences
35451 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
35452 optimize: function () {
35454 // times or values may be shared with other tracks, so overwriting is unsafe
35455 const times = AnimationUtils.arraySlice( this.times ),
35456 values = AnimationUtils.arraySlice( this.values ),
35457 stride = this.getValueSize(),
35459 smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
35461 lastIndex = times.length - 1;
35463 let writeIndex = 1;
35465 for ( let i = 1; i < lastIndex; ++ i ) {
35469 const time = times[ i ];
35470 const timeNext = times[ i + 1 ];
35472 // remove adjacent keyframes scheduled at the same time
35474 if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
35476 if ( ! smoothInterpolation ) {
35478 // remove unnecessary keyframes same as their neighbors
35480 const offset = i * stride,
35481 offsetP = offset - stride,
35482 offsetN = offset + stride;
35484 for ( let j = 0; j !== stride; ++ j ) {
35486 const value = values[ offset + j ];
35488 if ( value !== values[ offsetP + j ] ||
35489 value !== values[ offsetN + j ] ) {
35506 // in-place compaction
35510 if ( i !== writeIndex ) {
35512 times[ writeIndex ] = times[ i ];
35514 const readOffset = i * stride,
35515 writeOffset = writeIndex * stride;
35517 for ( let j = 0; j !== stride; ++ j ) {
35519 values[ writeOffset + j ] = values[ readOffset + j ];
35531 // flush last keyframe (compaction looks ahead)
35533 if ( lastIndex > 0 ) {
35535 times[ writeIndex ] = times[ lastIndex ];
35537 for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
35539 values[ writeOffset + j ] = values[ readOffset + j ];
35547 if ( writeIndex !== times.length ) {
35549 this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
35550 this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
35554 this.times = times;
35555 this.values = values;
35563 clone: function () {
35565 const times = AnimationUtils.arraySlice( this.times, 0 );
35566 const values = AnimationUtils.arraySlice( this.values, 0 );
35568 const TypedKeyframeTrack = this.constructor;
35569 const track = new TypedKeyframeTrack( this.name, times, values );
35571 // Interpolant argument to constructor is not saved, so copy the factory method directly.
35572 track.createInterpolant = this.createInterpolant;
35581 * A Track of Boolean keyframe values.
35584 function BooleanKeyframeTrack( name, times, values ) {
35586 KeyframeTrack.call( this, name, times, values );
35590 BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35592 constructor: BooleanKeyframeTrack,
35594 ValueTypeName: 'bool',
35595 ValueBufferType: Array,
35597 DefaultInterpolation: InterpolateDiscrete,
35599 InterpolantFactoryMethodLinear: undefined,
35600 InterpolantFactoryMethodSmooth: undefined
35602 // Note: Actually this track could have a optimized / compressed
35603 // representation of a single value and a custom interpolant that
35604 // computes "firstValue ^ isOdd( index )".
35609 * A Track of keyframe values that represent color.
35612 function ColorKeyframeTrack( name, times, values, interpolation ) {
35614 KeyframeTrack.call( this, name, times, values, interpolation );
35618 ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35620 constructor: ColorKeyframeTrack,
35622 ValueTypeName: 'color'
35624 // ValueBufferType is inherited
35626 // DefaultInterpolation is inherited
35628 // Note: Very basic implementation and nothing special yet.
35629 // However, this is the place for color space parameterization.
35634 * A Track of numeric keyframe values.
35637 function NumberKeyframeTrack( name, times, values, interpolation ) {
35639 KeyframeTrack.call( this, name, times, values, interpolation );
35643 NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35645 constructor: NumberKeyframeTrack,
35647 ValueTypeName: 'number'
35649 // ValueBufferType is inherited
35651 // DefaultInterpolation is inherited
35656 * Spherical linear unit quaternion interpolant.
35659 function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
35661 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
35665 QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
35667 constructor: QuaternionLinearInterpolant,
35669 interpolate_: function ( i1, t0, t, t1 ) {
35671 const result = this.resultBuffer,
35672 values = this.sampleValues,
35673 stride = this.valueSize,
35675 alpha = ( t - t0 ) / ( t1 - t0 );
35677 let offset = i1 * stride;
35679 for ( let end = offset + stride; offset !== end; offset += 4 ) {
35681 Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
35692 * A Track of quaternion keyframe values.
35695 function QuaternionKeyframeTrack( name, times, values, interpolation ) {
35697 KeyframeTrack.call( this, name, times, values, interpolation );
35701 QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35703 constructor: QuaternionKeyframeTrack,
35705 ValueTypeName: 'quaternion',
35707 // ValueBufferType is inherited
35709 DefaultInterpolation: InterpolateLinear,
35711 InterpolantFactoryMethodLinear: function ( result ) {
35713 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
35717 InterpolantFactoryMethodSmooth: undefined // not yet implemented
35722 * A Track that interpolates Strings
35725 function StringKeyframeTrack( name, times, values, interpolation ) {
35727 KeyframeTrack.call( this, name, times, values, interpolation );
35731 StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35733 constructor: StringKeyframeTrack,
35735 ValueTypeName: 'string',
35736 ValueBufferType: Array,
35738 DefaultInterpolation: InterpolateDiscrete,
35740 InterpolantFactoryMethodLinear: undefined,
35742 InterpolantFactoryMethodSmooth: undefined
35747 * A Track of vectored keyframe values.
35750 function VectorKeyframeTrack( name, times, values, interpolation ) {
35752 KeyframeTrack.call( this, name, times, values, interpolation );
35756 VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35758 constructor: VectorKeyframeTrack,
35760 ValueTypeName: 'vector'
35762 // ValueBufferType is inherited
35764 // DefaultInterpolation is inherited
35768 function AnimationClip( name, duration, tracks, blendMode ) {
35771 this.tracks = tracks;
35772 this.duration = ( duration !== undefined ) ? duration : - 1;
35773 this.blendMode = ( blendMode !== undefined ) ? blendMode : NormalAnimationBlendMode;
35775 this.uuid = MathUtils.generateUUID();
35777 // this means it should figure out its duration by scanning the tracks
35778 if ( this.duration < 0 ) {
35780 this.resetDuration();
35786 function getTrackTypeForValueTypeName( typeName ) {
35788 switch ( typeName.toLowerCase() ) {
35796 return NumberKeyframeTrack;
35803 return VectorKeyframeTrack;
35807 return ColorKeyframeTrack;
35811 return QuaternionKeyframeTrack;
35816 return BooleanKeyframeTrack;
35820 return StringKeyframeTrack;
35824 throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
35828 function parseKeyframeTrack( json ) {
35830 if ( json.type === undefined ) {
35832 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
35836 const trackType = getTrackTypeForValueTypeName( json.type );
35838 if ( json.times === undefined ) {
35840 const times = [], values = [];
35842 AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
35844 json.times = times;
35845 json.values = values;
35849 // derived classes can define a static parse method
35850 if ( trackType.parse !== undefined ) {
35852 return trackType.parse( json );
35856 // by default, we assume a constructor compatible with the base
35857 return new trackType( json.name, json.times, json.values, json.interpolation );
35863 Object.assign( AnimationClip, {
35865 parse: function ( json ) {
35868 jsonTracks = json.tracks,
35869 frameTime = 1.0 / ( json.fps || 1.0 );
35871 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
35873 tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
35877 const clip = new AnimationClip( json.name, json.duration, tracks, json.blendMode );
35878 clip.uuid = json.uuid;
35884 toJSON: function ( clip ) {
35887 clipTracks = clip.tracks;
35892 'duration': clip.duration,
35895 'blendMode': clip.blendMode
35899 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
35901 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
35909 CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
35911 const numMorphTargets = morphTargetSequence.length;
35914 for ( let i = 0; i < numMorphTargets; i ++ ) {
35920 ( i + numMorphTargets - 1 ) % numMorphTargets,
35922 ( i + 1 ) % numMorphTargets );
35924 values.push( 0, 1, 0 );
35926 const order = AnimationUtils.getKeyframeOrder( times );
35927 times = AnimationUtils.sortedArray( times, 1, order );
35928 values = AnimationUtils.sortedArray( values, 1, order );
35930 // if there is a key at the first frame, duplicate it as the
35931 // last frame as well for perfect loop.
35932 if ( ! noLoop && times[ 0 ] === 0 ) {
35934 times.push( numMorphTargets );
35935 values.push( values[ 0 ] );
35940 new NumberKeyframeTrack(
35941 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
35943 ).scale( 1.0 / fps ) );
35947 return new AnimationClip( name, - 1, tracks );
35951 findByName: function ( objectOrClipArray, name ) {
35953 let clipArray = objectOrClipArray;
35955 if ( ! Array.isArray( objectOrClipArray ) ) {
35957 const o = objectOrClipArray;
35958 clipArray = o.geometry && o.geometry.animations || o.animations;
35962 for ( let i = 0; i < clipArray.length; i ++ ) {
35964 if ( clipArray[ i ].name === name ) {
35966 return clipArray[ i ];
35976 CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
35978 const animationToMorphTargets = {};
35980 // tested with https://regex101.com/ on trick sequences
35981 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
35982 const pattern = /^([\w-]*?)([\d]+)$/;
35984 // sort morph target names into animation groups based
35985 // patterns like Walk_001, Walk_002, Run_001, Run_002
35986 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
35988 const morphTarget = morphTargets[ i ];
35989 const parts = morphTarget.name.match( pattern );
35991 if ( parts && parts.length > 1 ) {
35993 const name = parts[ 1 ];
35995 let animationMorphTargets = animationToMorphTargets[ name ];
35997 if ( ! animationMorphTargets ) {
35999 animationToMorphTargets[ name ] = animationMorphTargets = [];
36003 animationMorphTargets.push( morphTarget );
36011 for ( const name in animationToMorphTargets ) {
36013 clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
36021 // parse the animation.hierarchy format
36022 parseAnimation: function ( animation, bones ) {
36024 if ( ! animation ) {
36026 console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
36031 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
36033 // only return track if there are actually keys.
36034 if ( animationKeys.length !== 0 ) {
36039 AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
36041 // empty keys are filtered out, so check again
36042 if ( times.length !== 0 ) {
36044 destTracks.push( new trackType( trackName, times, values ) );
36054 const clipName = animation.name || 'default';
36055 const fps = animation.fps || 30;
36056 const blendMode = animation.blendMode;
36058 // automatic length determination in AnimationClip.
36059 let duration = animation.length || - 1;
36061 const hierarchyTracks = animation.hierarchy || [];
36063 for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
36065 const animationKeys = hierarchyTracks[ h ].keys;
36067 // skip empty tracks
36068 if ( ! animationKeys || animationKeys.length === 0 ) continue;
36070 // process morph targets
36071 if ( animationKeys[ 0 ].morphTargets ) {
36073 // figure out all morph targets used in this track
36074 const morphTargetNames = {};
36078 for ( k = 0; k < animationKeys.length; k ++ ) {
36080 if ( animationKeys[ k ].morphTargets ) {
36082 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
36084 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
36092 // create a track for each morph target with all zero
36093 // morphTargetInfluences except for the keys in which
36094 // the morphTarget is named.
36095 for ( const morphTargetName in morphTargetNames ) {
36100 for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
36102 const animationKey = animationKeys[ k ];
36104 times.push( animationKey.time );
36105 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
36109 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
36113 duration = morphTargetNames.length * ( fps || 1.0 );
36117 // ...assume skeletal animation
36119 const boneName = '.bones[' + bones[ h ].name + ']';
36122 VectorKeyframeTrack, boneName + '.position',
36123 animationKeys, 'pos', tracks );
36126 QuaternionKeyframeTrack, boneName + '.quaternion',
36127 animationKeys, 'rot', tracks );
36130 VectorKeyframeTrack, boneName + '.scale',
36131 animationKeys, 'scl', tracks );
36137 if ( tracks.length === 0 ) {
36143 const clip = new AnimationClip( clipName, duration, tracks, blendMode );
36151 Object.assign( AnimationClip.prototype, {
36153 resetDuration: function () {
36155 const tracks = this.tracks;
36158 for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
36160 const track = this.tracks[ i ];
36162 duration = Math.max( duration, track.times[ track.times.length - 1 ] );
36166 this.duration = duration;
36172 trim: function () {
36174 for ( let i = 0; i < this.tracks.length; i ++ ) {
36176 this.tracks[ i ].trim( 0, this.duration );
36184 validate: function () {
36188 for ( let i = 0; i < this.tracks.length; i ++ ) {
36190 valid = valid && this.tracks[ i ].validate();
36198 optimize: function () {
36200 for ( let i = 0; i < this.tracks.length; i ++ ) {
36202 this.tracks[ i ].optimize();
36210 clone: function () {
36214 for ( let i = 0; i < this.tracks.length; i ++ ) {
36216 tracks.push( this.tracks[ i ].clone() );
36220 return new AnimationClip( this.name, this.duration, tracks, this.blendMode );
36224 toJSON: function () {
36226 return AnimationClip.toJSON( this );
36238 add: function ( key, file ) {
36240 if ( this.enabled === false ) return;
36242 // console.log( 'THREE.Cache', 'Adding key:', key );
36244 this.files[ key ] = file;
36248 get: function ( key ) {
36250 if ( this.enabled === false ) return;
36252 // console.log( 'THREE.Cache', 'Checking key:', key );
36254 return this.files[ key ];
36258 remove: function ( key ) {
36260 delete this.files[ key ];
36264 clear: function () {
36272 function LoadingManager( onLoad, onProgress, onError ) {
36274 const scope = this;
36276 let isLoading = false;
36277 let itemsLoaded = 0;
36278 let itemsTotal = 0;
36279 let urlModifier = undefined;
36280 const handlers = [];
36282 // Refer to #5689 for the reason why we don't set .onStart
36283 // in the constructor
36285 this.onStart = undefined;
36286 this.onLoad = onLoad;
36287 this.onProgress = onProgress;
36288 this.onError = onError;
36290 this.itemStart = function ( url ) {
36294 if ( isLoading === false ) {
36296 if ( scope.onStart !== undefined ) {
36298 scope.onStart( url, itemsLoaded, itemsTotal );
36308 this.itemEnd = function ( url ) {
36312 if ( scope.onProgress !== undefined ) {
36314 scope.onProgress( url, itemsLoaded, itemsTotal );
36318 if ( itemsLoaded === itemsTotal ) {
36322 if ( scope.onLoad !== undefined ) {
36332 this.itemError = function ( url ) {
36334 if ( scope.onError !== undefined ) {
36336 scope.onError( url );
36342 this.resolveURL = function ( url ) {
36344 if ( urlModifier ) {
36346 return urlModifier( url );
36354 this.setURLModifier = function ( transform ) {
36356 urlModifier = transform;
36362 this.addHandler = function ( regex, loader ) {
36364 handlers.push( regex, loader );
36370 this.removeHandler = function ( regex ) {
36372 const index = handlers.indexOf( regex );
36374 if ( index !== - 1 ) {
36376 handlers.splice( index, 2 );
36384 this.getHandler = function ( file ) {
36386 for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
36388 const regex = handlers[ i ];
36389 const loader = handlers[ i + 1 ];
36391 if ( regex.global ) regex.lastIndex = 0; // see #17920
36393 if ( regex.test( file ) ) {
36407 const DefaultLoadingManager = new LoadingManager();
36409 function Loader( manager ) {
36411 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
36413 this.crossOrigin = 'anonymous';
36414 this.withCredentials = false;
36416 this.resourcePath = '';
36417 this.requestHeader = {};
36421 Object.assign( Loader.prototype, {
36423 load: function ( /* url, onLoad, onProgress, onError */ ) {},
36425 loadAsync: function ( url, onProgress ) {
36427 const scope = this;
36429 return new Promise( function ( resolve, reject ) {
36431 scope.load( url, resolve, onProgress, reject );
36437 parse: function ( /* data */ ) {},
36439 setCrossOrigin: function ( crossOrigin ) {
36441 this.crossOrigin = crossOrigin;
36446 setWithCredentials: function ( value ) {
36448 this.withCredentials = value;
36453 setPath: function ( path ) {
36460 setResourcePath: function ( resourcePath ) {
36462 this.resourcePath = resourcePath;
36467 setRequestHeader: function ( requestHeader ) {
36469 this.requestHeader = requestHeader;
36476 const loading = {};
36478 function FileLoader( manager ) {
36480 Loader.call( this, manager );
36484 FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36486 constructor: FileLoader,
36488 load: function ( url, onLoad, onProgress, onError ) {
36490 if ( url === undefined ) url = '';
36492 if ( this.path !== undefined ) url = this.path + url;
36494 url = this.manager.resolveURL( url );
36496 const scope = this;
36498 const cached = Cache.get( url );
36500 if ( cached !== undefined ) {
36502 scope.manager.itemStart( url );
36504 setTimeout( function () {
36506 if ( onLoad ) onLoad( cached );
36508 scope.manager.itemEnd( url );
36516 // Check if request is duplicate
36518 if ( loading[ url ] !== undefined ) {
36520 loading[ url ].push( {
36523 onProgress: onProgress,
36532 // Check for data: URI
36533 const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
36534 const dataUriRegexResult = url.match( dataUriRegex );
36537 // Safari can not handle Data URIs through XMLHttpRequest so process manually
36538 if ( dataUriRegexResult ) {
36540 const mimeType = dataUriRegexResult[ 1 ];
36541 const isBase64 = !! dataUriRegexResult[ 2 ];
36543 let data = dataUriRegexResult[ 3 ];
36544 data = decodeURIComponent( data );
36546 if ( isBase64 ) data = atob( data );
36551 const responseType = ( this.responseType || '' ).toLowerCase();
36553 switch ( responseType ) {
36555 case 'arraybuffer':
36558 const view = new Uint8Array( data.length );
36560 for ( let i = 0; i < data.length; i ++ ) {
36562 view[ i ] = data.charCodeAt( i );
36566 if ( responseType === 'blob' ) {
36568 response = new Blob( [ view.buffer ], { type: mimeType } );
36572 response = view.buffer;
36580 const parser = new DOMParser();
36581 response = parser.parseFromString( data, mimeType );
36587 response = JSON.parse( data );
36591 default: // 'text' or other
36599 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
36600 setTimeout( function () {
36602 if ( onLoad ) onLoad( response );
36604 scope.manager.itemEnd( url );
36608 } catch ( error ) {
36610 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
36611 setTimeout( function () {
36613 if ( onError ) onError( error );
36615 scope.manager.itemError( url );
36616 scope.manager.itemEnd( url );
36624 // Initialise array for duplicate requests
36626 loading[ url ] = [];
36628 loading[ url ].push( {
36631 onProgress: onProgress,
36636 request = new XMLHttpRequest();
36638 request.open( 'GET', url, true );
36640 request.addEventListener( 'load', function ( event ) {
36642 const response = this.response;
36644 const callbacks = loading[ url ];
36646 delete loading[ url ];
36648 if ( this.status === 200 || this.status === 0 ) {
36650 // Some browsers return HTTP Status 0 when using non-http protocol
36651 // e.g. 'file://' or 'data://'. Handle as success.
36653 if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
36655 // Add to cache only on HTTP success, so that we do not cache
36656 // error response bodies as proper responses to requests.
36657 Cache.add( url, response );
36659 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36661 const callback = callbacks[ i ];
36662 if ( callback.onLoad ) callback.onLoad( response );
36666 scope.manager.itemEnd( url );
36670 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36672 const callback = callbacks[ i ];
36673 if ( callback.onError ) callback.onError( event );
36677 scope.manager.itemError( url );
36678 scope.manager.itemEnd( url );
36684 request.addEventListener( 'progress', function ( event ) {
36686 const callbacks = loading[ url ];
36688 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36690 const callback = callbacks[ i ];
36691 if ( callback.onProgress ) callback.onProgress( event );
36697 request.addEventListener( 'error', function ( event ) {
36699 const callbacks = loading[ url ];
36701 delete loading[ url ];
36703 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36705 const callback = callbacks[ i ];
36706 if ( callback.onError ) callback.onError( event );
36710 scope.manager.itemError( url );
36711 scope.manager.itemEnd( url );
36715 request.addEventListener( 'abort', function ( event ) {
36717 const callbacks = loading[ url ];
36719 delete loading[ url ];
36721 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36723 const callback = callbacks[ i ];
36724 if ( callback.onError ) callback.onError( event );
36728 scope.manager.itemError( url );
36729 scope.manager.itemEnd( url );
36733 if ( this.responseType !== undefined ) request.responseType = this.responseType;
36734 if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
36736 if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
36738 for ( const header in this.requestHeader ) {
36740 request.setRequestHeader( header, this.requestHeader[ header ] );
36744 request.send( null );
36748 scope.manager.itemStart( url );
36754 setResponseType: function ( value ) {
36756 this.responseType = value;
36761 setMimeType: function ( value ) {
36763 this.mimeType = value;
36770 function AnimationLoader( manager ) {
36772 Loader.call( this, manager );
36776 AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36778 constructor: AnimationLoader,
36780 load: function ( url, onLoad, onProgress, onError ) {
36782 const scope = this;
36784 const loader = new FileLoader( scope.manager );
36785 loader.setPath( scope.path );
36786 loader.setRequestHeader( scope.requestHeader );
36787 loader.setWithCredentials( scope.withCredentials );
36788 loader.load( url, function ( text ) {
36792 onLoad( scope.parse( JSON.parse( text ) ) );
36802 console.error( e );
36806 scope.manager.itemError( url );
36810 }, onProgress, onError );
36814 parse: function ( json ) {
36816 const animations = [];
36818 for ( let i = 0; i < json.length; i ++ ) {
36820 const clip = AnimationClip.parse( json[ i ] );
36822 animations.push( clip );
36833 * Abstract Base class to block based textures loader (dds, pvr, ...)
36835 * Sub classes have to implement the parse() method which will be used in load().
36838 function CompressedTextureLoader( manager ) {
36840 Loader.call( this, manager );
36844 CompressedTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36846 constructor: CompressedTextureLoader,
36848 load: function ( url, onLoad, onProgress, onError ) {
36850 const scope = this;
36854 const texture = new CompressedTexture();
36855 texture.image = images;
36857 const loader = new FileLoader( this.manager );
36858 loader.setPath( this.path );
36859 loader.setResponseType( 'arraybuffer' );
36860 loader.setRequestHeader( this.requestHeader );
36861 loader.setWithCredentials( scope.withCredentials );
36865 function loadTexture( i ) {
36867 loader.load( url[ i ], function ( buffer ) {
36869 const texDatas = scope.parse( buffer, true );
36872 width: texDatas.width,
36873 height: texDatas.height,
36874 format: texDatas.format,
36875 mipmaps: texDatas.mipmaps
36880 if ( loaded === 6 ) {
36882 if ( texDatas.mipmapCount === 1 )
36883 texture.minFilter = LinearFilter;
36885 texture.format = texDatas.format;
36886 texture.needsUpdate = true;
36888 if ( onLoad ) onLoad( texture );
36892 }, onProgress, onError );
36896 if ( Array.isArray( url ) ) {
36898 for ( let i = 0, il = url.length; i < il; ++ i ) {
36906 // compressed cubemap texture stored in a single DDS file
36908 loader.load( url, function ( buffer ) {
36910 const texDatas = scope.parse( buffer, true );
36912 if ( texDatas.isCubemap ) {
36914 const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
36916 for ( let f = 0; f < faces; f ++ ) {
36918 images[ f ] = { mipmaps: [] };
36920 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
36922 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
36923 images[ f ].format = texDatas.format;
36924 images[ f ].width = texDatas.width;
36925 images[ f ].height = texDatas.height;
36933 texture.image.width = texDatas.width;
36934 texture.image.height = texDatas.height;
36935 texture.mipmaps = texDatas.mipmaps;
36939 if ( texDatas.mipmapCount === 1 ) {
36941 texture.minFilter = LinearFilter;
36945 texture.format = texDatas.format;
36946 texture.needsUpdate = true;
36948 if ( onLoad ) onLoad( texture );
36950 }, onProgress, onError );
36960 function ImageLoader( manager ) {
36962 Loader.call( this, manager );
36966 ImageLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36968 constructor: ImageLoader,
36970 load: function ( url, onLoad, onProgress, onError ) {
36972 if ( this.path !== undefined ) url = this.path + url;
36974 url = this.manager.resolveURL( url );
36976 const scope = this;
36978 const cached = Cache.get( url );
36980 if ( cached !== undefined ) {
36982 scope.manager.itemStart( url );
36984 setTimeout( function () {
36986 if ( onLoad ) onLoad( cached );
36988 scope.manager.itemEnd( url );
36996 const image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
36998 function onImageLoad() {
37000 image.removeEventListener( 'load', onImageLoad, false );
37001 image.removeEventListener( 'error', onImageError, false );
37003 Cache.add( url, this );
37005 if ( onLoad ) onLoad( this );
37007 scope.manager.itemEnd( url );
37011 function onImageError( event ) {
37013 image.removeEventListener( 'load', onImageLoad, false );
37014 image.removeEventListener( 'error', onImageError, false );
37016 if ( onError ) onError( event );
37018 scope.manager.itemError( url );
37019 scope.manager.itemEnd( url );
37023 image.addEventListener( 'load', onImageLoad, false );
37024 image.addEventListener( 'error', onImageError, false );
37026 if ( url.substr( 0, 5 ) !== 'data:' ) {
37028 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
37032 scope.manager.itemStart( url );
37042 function CubeTextureLoader( manager ) {
37044 Loader.call( this, manager );
37048 CubeTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37050 constructor: CubeTextureLoader,
37052 load: function ( urls, onLoad, onProgress, onError ) {
37054 const texture = new CubeTexture();
37056 const loader = new ImageLoader( this.manager );
37057 loader.setCrossOrigin( this.crossOrigin );
37058 loader.setPath( this.path );
37062 function loadTexture( i ) {
37064 loader.load( urls[ i ], function ( image ) {
37066 texture.images[ i ] = image;
37070 if ( loaded === 6 ) {
37072 texture.needsUpdate = true;
37074 if ( onLoad ) onLoad( texture );
37078 }, undefined, onError );
37082 for ( let i = 0; i < urls.length; ++ i ) {
37095 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
37097 * Sub classes have to implement the parse() method which will be used in load().
37100 function DataTextureLoader( manager ) {
37102 Loader.call( this, manager );
37106 DataTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37108 constructor: DataTextureLoader,
37110 load: function ( url, onLoad, onProgress, onError ) {
37112 const scope = this;
37114 const texture = new DataTexture();
37116 const loader = new FileLoader( this.manager );
37117 loader.setResponseType( 'arraybuffer' );
37118 loader.setRequestHeader( this.requestHeader );
37119 loader.setPath( this.path );
37120 loader.setWithCredentials( scope.withCredentials );
37121 loader.load( url, function ( buffer ) {
37123 const texData = scope.parse( buffer );
37125 if ( ! texData ) return;
37127 if ( texData.image !== undefined ) {
37129 texture.image = texData.image;
37131 } else if ( texData.data !== undefined ) {
37133 texture.image.width = texData.width;
37134 texture.image.height = texData.height;
37135 texture.image.data = texData.data;
37139 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
37140 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
37142 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
37143 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
37145 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
37147 if ( texData.format !== undefined ) {
37149 texture.format = texData.format;
37153 if ( texData.type !== undefined ) {
37155 texture.type = texData.type;
37159 if ( texData.mipmaps !== undefined ) {
37161 texture.mipmaps = texData.mipmaps;
37162 texture.minFilter = LinearMipmapLinearFilter; // presumably...
37166 if ( texData.mipmapCount === 1 ) {
37168 texture.minFilter = LinearFilter;
37172 texture.needsUpdate = true;
37174 if ( onLoad ) onLoad( texture, texData );
37176 }, onProgress, onError );
37185 function TextureLoader( manager ) {
37187 Loader.call( this, manager );
37191 TextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37193 constructor: TextureLoader,
37195 load: function ( url, onLoad, onProgress, onError ) {
37197 const texture = new Texture();
37199 const loader = new ImageLoader( this.manager );
37200 loader.setCrossOrigin( this.crossOrigin );
37201 loader.setPath( this.path );
37203 loader.load( url, function ( image ) {
37205 texture.image = image;
37207 // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
37208 const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
37210 texture.format = isJPEG ? RGBFormat : RGBAFormat;
37211 texture.needsUpdate = true;
37213 if ( onLoad !== undefined ) {
37219 }, onProgress, onError );
37228 * Extensible curve object.
37230 * Some common of curve methods:
37231 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
37232 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
37233 * .getPoints(), .getSpacedPoints()
37235 * .updateArcLengths()
37237 * This following curves inherit from THREE.Curve:
37241 * THREE.CubicBezierCurve
37242 * THREE.EllipseCurve
37244 * THREE.QuadraticBezierCurve
37245 * THREE.SplineCurve
37248 * THREE.CatmullRomCurve3
37249 * THREE.CubicBezierCurve3
37251 * THREE.QuadraticBezierCurve3
37253 * A series of curves can be represented as a THREE.CurvePath.
37259 this.type = 'Curve';
37261 this.arcLengthDivisions = 200;
37265 Object.assign( Curve.prototype, {
37267 // Virtual base class method to overwrite and implement in subclasses
37270 getPoint: function ( /* t, optionalTarget */ ) {
37272 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
37277 // Get point at relative position in curve according to arc length
37280 getPointAt: function ( u, optionalTarget ) {
37282 const t = this.getUtoTmapping( u );
37283 return this.getPoint( t, optionalTarget );
37287 // Get sequence of points using getPoint( t )
37289 getPoints: function ( divisions = 5 ) {
37293 for ( let d = 0; d <= divisions; d ++ ) {
37295 points.push( this.getPoint( d / divisions ) );
37303 // Get sequence of points using getPointAt( u )
37305 getSpacedPoints: function ( divisions = 5 ) {
37309 for ( let d = 0; d <= divisions; d ++ ) {
37311 points.push( this.getPointAt( d / divisions ) );
37319 // Get total curve arc length
37321 getLength: function () {
37323 const lengths = this.getLengths();
37324 return lengths[ lengths.length - 1 ];
37328 // Get list of cumulative segment lengths
37330 getLengths: function ( divisions ) {
37332 if ( divisions === undefined ) divisions = this.arcLengthDivisions;
37334 if ( this.cacheArcLengths &&
37335 ( this.cacheArcLengths.length === divisions + 1 ) &&
37336 ! this.needsUpdate ) {
37338 return this.cacheArcLengths;
37342 this.needsUpdate = false;
37345 let current, last = this.getPoint( 0 );
37350 for ( let p = 1; p <= divisions; p ++ ) {
37352 current = this.getPoint( p / divisions );
37353 sum += current.distanceTo( last );
37359 this.cacheArcLengths = cache;
37361 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
37365 updateArcLengths: function () {
37367 this.needsUpdate = true;
37372 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
37374 getUtoTmapping: function ( u, distance ) {
37376 const arcLengths = this.getLengths();
37379 const il = arcLengths.length;
37381 let targetArcLength; // The targeted u distance value to get
37385 targetArcLength = distance;
37389 targetArcLength = u * arcLengths[ il - 1 ];
37393 // binary search for the index with largest value smaller than target u distance
37395 let low = 0, high = il - 1, comparison;
37397 while ( low <= high ) {
37399 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
37401 comparison = arcLengths[ i ] - targetArcLength;
37403 if ( comparison < 0 ) {
37407 } else if ( comparison > 0 ) {
37424 if ( arcLengths[ i ] === targetArcLength ) {
37426 return i / ( il - 1 );
37430 // we could get finer grain at lengths, or use simple interpolation between two points
37432 const lengthBefore = arcLengths[ i ];
37433 const lengthAfter = arcLengths[ i + 1 ];
37435 const segmentLength = lengthAfter - lengthBefore;
37437 // determine where we are between the 'before' and 'after' points
37439 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
37441 // add that fractional amount to t
37443 const t = ( i + segmentFraction ) / ( il - 1 );
37449 // Returns a unit vector tangent at t
37450 // In case any sub curve does not implement its tangent derivation,
37451 // 2 points a small delta apart will be used to find its gradient
37452 // which seems to give a reasonable approximation
37454 getTangent: function ( t, optionalTarget ) {
37456 const delta = 0.0001;
37457 let t1 = t - delta;
37458 let t2 = t + delta;
37460 // Capping in case of danger
37462 if ( t1 < 0 ) t1 = 0;
37463 if ( t2 > 1 ) t2 = 1;
37465 const pt1 = this.getPoint( t1 );
37466 const pt2 = this.getPoint( t2 );
37468 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
37470 tangent.copy( pt2 ).sub( pt1 ).normalize();
37476 getTangentAt: function ( u, optionalTarget ) {
37478 const t = this.getUtoTmapping( u );
37479 return this.getTangent( t, optionalTarget );
37483 computeFrenetFrames: function ( segments, closed ) {
37485 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
37487 const normal = new Vector3();
37489 const tangents = [];
37490 const normals = [];
37491 const binormals = [];
37493 const vec = new Vector3();
37494 const mat = new Matrix4();
37496 // compute the tangent vectors for each segment on the curve
37498 for ( let i = 0; i <= segments; i ++ ) {
37500 const u = i / segments;
37502 tangents[ i ] = this.getTangentAt( u, new Vector3() );
37503 tangents[ i ].normalize();
37507 // select an initial normal vector perpendicular to the first tangent vector,
37508 // and in the direction of the minimum tangent xyz component
37510 normals[ 0 ] = new Vector3();
37511 binormals[ 0 ] = new Vector3();
37512 let min = Number.MAX_VALUE;
37513 const tx = Math.abs( tangents[ 0 ].x );
37514 const ty = Math.abs( tangents[ 0 ].y );
37515 const tz = Math.abs( tangents[ 0 ].z );
37520 normal.set( 1, 0, 0 );
37527 normal.set( 0, 1, 0 );
37533 normal.set( 0, 0, 1 );
37537 vec.crossVectors( tangents[ 0 ], normal ).normalize();
37539 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
37540 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
37543 // compute the slowly-varying normal and binormal vectors for each segment on the curve
37545 for ( let i = 1; i <= segments; i ++ ) {
37547 normals[ i ] = normals[ i - 1 ].clone();
37549 binormals[ i ] = binormals[ i - 1 ].clone();
37551 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
37553 if ( vec.length() > Number.EPSILON ) {
37557 const theta = Math.acos( MathUtils.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
37559 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
37563 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
37567 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
37569 if ( closed === true ) {
37571 let theta = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
37574 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
37580 for ( let i = 1; i <= segments; i ++ ) {
37582 // twist a little...
37583 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
37584 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
37591 tangents: tangents,
37593 binormals: binormals
37598 clone: function () {
37600 return new this.constructor().copy( this );
37604 copy: function ( source ) {
37606 this.arcLengthDivisions = source.arcLengthDivisions;
37612 toJSON: function () {
37618 generator: 'Curve.toJSON'
37622 data.arcLengthDivisions = this.arcLengthDivisions;
37623 data.type = this.type;
37629 fromJSON: function ( json ) {
37631 this.arcLengthDivisions = json.arcLengthDivisions;
37639 function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
37641 Curve.call( this );
37643 this.type = 'EllipseCurve';
37648 this.xRadius = xRadius || 1;
37649 this.yRadius = yRadius || 1;
37651 this.aStartAngle = aStartAngle || 0;
37652 this.aEndAngle = aEndAngle || 2 * Math.PI;
37654 this.aClockwise = aClockwise || false;
37656 this.aRotation = aRotation || 0;
37660 EllipseCurve.prototype = Object.create( Curve.prototype );
37661 EllipseCurve.prototype.constructor = EllipseCurve;
37663 EllipseCurve.prototype.isEllipseCurve = true;
37665 EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) {
37667 const point = optionalTarget || new Vector2();
37669 const twoPi = Math.PI * 2;
37670 let deltaAngle = this.aEndAngle - this.aStartAngle;
37671 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
37673 // ensures that deltaAngle is 0 .. 2 PI
37674 while ( deltaAngle < 0 ) deltaAngle += twoPi;
37675 while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
37677 if ( deltaAngle < Number.EPSILON ) {
37679 if ( samePoints ) {
37685 deltaAngle = twoPi;
37691 if ( this.aClockwise === true && ! samePoints ) {
37693 if ( deltaAngle === twoPi ) {
37695 deltaAngle = - twoPi;
37699 deltaAngle = deltaAngle - twoPi;
37705 const angle = this.aStartAngle + t * deltaAngle;
37706 let x = this.aX + this.xRadius * Math.cos( angle );
37707 let y = this.aY + this.yRadius * Math.sin( angle );
37709 if ( this.aRotation !== 0 ) {
37711 const cos = Math.cos( this.aRotation );
37712 const sin = Math.sin( this.aRotation );
37714 const tx = x - this.aX;
37715 const ty = y - this.aY;
37717 // Rotate the point about the center of the ellipse.
37718 x = tx * cos - ty * sin + this.aX;
37719 y = tx * sin + ty * cos + this.aY;
37723 return point.set( x, y );
37727 EllipseCurve.prototype.copy = function ( source ) {
37729 Curve.prototype.copy.call( this, source );
37731 this.aX = source.aX;
37732 this.aY = source.aY;
37734 this.xRadius = source.xRadius;
37735 this.yRadius = source.yRadius;
37737 this.aStartAngle = source.aStartAngle;
37738 this.aEndAngle = source.aEndAngle;
37740 this.aClockwise = source.aClockwise;
37742 this.aRotation = source.aRotation;
37749 EllipseCurve.prototype.toJSON = function () {
37751 const data = Curve.prototype.toJSON.call( this );
37756 data.xRadius = this.xRadius;
37757 data.yRadius = this.yRadius;
37759 data.aStartAngle = this.aStartAngle;
37760 data.aEndAngle = this.aEndAngle;
37762 data.aClockwise = this.aClockwise;
37764 data.aRotation = this.aRotation;
37770 EllipseCurve.prototype.fromJSON = function ( json ) {
37772 Curve.prototype.fromJSON.call( this, json );
37777 this.xRadius = json.xRadius;
37778 this.yRadius = json.yRadius;
37780 this.aStartAngle = json.aStartAngle;
37781 this.aEndAngle = json.aEndAngle;
37783 this.aClockwise = json.aClockwise;
37785 this.aRotation = json.aRotation;
37791 function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
37793 EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
37795 this.type = 'ArcCurve';
37799 ArcCurve.prototype = Object.create( EllipseCurve.prototype );
37800 ArcCurve.prototype.constructor = ArcCurve;
37802 ArcCurve.prototype.isArcCurve = true;
37805 * Centripetal CatmullRom Curve - which is useful for avoiding
37806 * cusps and self-intersections in non-uniform catmull rom curves.
37807 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
37809 * curve.type accepts centripetal(default), chordal and catmullrom
37810 * curve.tension is used for catmullrom which defaults to 0.5
37815 Based on an optimized c++ solution in
37816 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
37817 - http://ideone.com/NoEbVM
37819 This CubicPoly class could be used for reusing some variables and calculations,
37820 but for three.js curve use, it could be possible inlined and flatten into a single function call
37821 which can be placed in CurveUtils.
37824 function CubicPoly() {
37826 let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
37829 * Compute coefficients for a cubic polynomial
37830 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
37832 * p(0) = x0, p(1) = x1
37834 * p'(0) = t0, p'(1) = t1.
37836 function init( x0, x1, t0, t1 ) {
37840 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
37841 c3 = 2 * x0 - 2 * x1 + t0 + t1;
37847 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
37849 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
37853 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
37855 // compute tangents when parameterized in [t1,t2]
37856 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
37857 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
37859 // rescale tangents for parametrization in [0,1]
37863 init( x1, x2, t1, t2 );
37867 calc: function ( t ) {
37871 return c0 + c1 * t + c2 * t2 + c3 * t3;
37881 const tmp = new Vector3();
37882 const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
37884 function CatmullRomCurve3( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
37886 Curve.call( this );
37888 this.type = 'CatmullRomCurve3';
37890 this.points = points;
37891 this.closed = closed;
37892 this.curveType = curveType;
37893 this.tension = tension;
37897 CatmullRomCurve3.prototype = Object.create( Curve.prototype );
37898 CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
37900 CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
37902 CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
37904 const point = optionalTarget;
37906 const points = this.points;
37907 const l = points.length;
37909 const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
37910 let intPoint = Math.floor( p );
37911 let weight = p - intPoint;
37913 if ( this.closed ) {
37915 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
37917 } else if ( weight === 0 && intPoint === l - 1 ) {
37924 let p0, p3; // 4 points (p1 & p2 defined below)
37926 if ( this.closed || intPoint > 0 ) {
37928 p0 = points[ ( intPoint - 1 ) % l ];
37932 // extrapolate first point
37933 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
37938 const p1 = points[ intPoint % l ];
37939 const p2 = points[ ( intPoint + 1 ) % l ];
37941 if ( this.closed || intPoint + 2 < l ) {
37943 p3 = points[ ( intPoint + 2 ) % l ];
37947 // extrapolate last point
37948 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
37953 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
37955 // init Centripetal / Chordal Catmull-Rom
37956 const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
37957 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
37958 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
37959 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
37961 // safety check for repeated points
37962 if ( dt1 < 1e-4 ) dt1 = 1.0;
37963 if ( dt0 < 1e-4 ) dt0 = dt1;
37964 if ( dt2 < 1e-4 ) dt2 = dt1;
37966 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
37967 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
37968 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
37970 } else if ( this.curveType === 'catmullrom' ) {
37972 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
37973 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
37974 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
37988 CatmullRomCurve3.prototype.copy = function ( source ) {
37990 Curve.prototype.copy.call( this, source );
37994 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
37996 const point = source.points[ i ];
37998 this.points.push( point.clone() );
38002 this.closed = source.closed;
38003 this.curveType = source.curveType;
38004 this.tension = source.tension;
38010 CatmullRomCurve3.prototype.toJSON = function () {
38012 const data = Curve.prototype.toJSON.call( this );
38016 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
38018 const point = this.points[ i ];
38019 data.points.push( point.toArray() );
38023 data.closed = this.closed;
38024 data.curveType = this.curveType;
38025 data.tension = this.tension;
38031 CatmullRomCurve3.prototype.fromJSON = function ( json ) {
38033 Curve.prototype.fromJSON.call( this, json );
38037 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
38039 const point = json.points[ i ];
38040 this.points.push( new Vector3().fromArray( point ) );
38044 this.closed = json.closed;
38045 this.curveType = json.curveType;
38046 this.tension = json.tension;
38053 * Bezier Curves formulas obtained from
38054 * http://en.wikipedia.org/wiki/Bézier_curve
38057 function CatmullRom( t, p0, p1, p2, p3 ) {
38059 const v0 = ( p2 - p0 ) * 0.5;
38060 const v1 = ( p3 - p1 ) * 0.5;
38063 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
38069 function QuadraticBezierP0( t, p ) {
38076 function QuadraticBezierP1( t, p ) {
38078 return 2 * ( 1 - t ) * t * p;
38082 function QuadraticBezierP2( t, p ) {
38088 function QuadraticBezier( t, p0, p1, p2 ) {
38090 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
38091 QuadraticBezierP2( t, p2 );
38097 function CubicBezierP0( t, p ) {
38100 return k * k * k * p;
38104 function CubicBezierP1( t, p ) {
38107 return 3 * k * k * t * p;
38111 function CubicBezierP2( t, p ) {
38113 return 3 * ( 1 - t ) * t * t * p;
38117 function CubicBezierP3( t, p ) {
38119 return t * t * t * p;
38123 function CubicBezier( t, p0, p1, p2, p3 ) {
38125 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
38126 CubicBezierP3( t, p3 );
38130 function CubicBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
38132 Curve.call( this );
38134 this.type = 'CubicBezierCurve';
38143 CubicBezierCurve.prototype = Object.create( Curve.prototype );
38144 CubicBezierCurve.prototype.constructor = CubicBezierCurve;
38146 CubicBezierCurve.prototype.isCubicBezierCurve = true;
38148 CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38150 const point = optionalTarget;
38152 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
38155 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
38156 CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
38163 CubicBezierCurve.prototype.copy = function ( source ) {
38165 Curve.prototype.copy.call( this, source );
38167 this.v0.copy( source.v0 );
38168 this.v1.copy( source.v1 );
38169 this.v2.copy( source.v2 );
38170 this.v3.copy( source.v3 );
38176 CubicBezierCurve.prototype.toJSON = function () {
38178 const data = Curve.prototype.toJSON.call( this );
38180 data.v0 = this.v0.toArray();
38181 data.v1 = this.v1.toArray();
38182 data.v2 = this.v2.toArray();
38183 data.v3 = this.v3.toArray();
38189 CubicBezierCurve.prototype.fromJSON = function ( json ) {
38191 Curve.prototype.fromJSON.call( this, json );
38193 this.v0.fromArray( json.v0 );
38194 this.v1.fromArray( json.v1 );
38195 this.v2.fromArray( json.v2 );
38196 this.v3.fromArray( json.v3 );
38202 function CubicBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
38204 Curve.call( this );
38206 this.type = 'CubicBezierCurve3';
38215 CubicBezierCurve3.prototype = Object.create( Curve.prototype );
38216 CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
38218 CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
38220 CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38222 const point = optionalTarget;
38224 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
38227 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
38228 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
38229 CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
38236 CubicBezierCurve3.prototype.copy = function ( source ) {
38238 Curve.prototype.copy.call( this, source );
38240 this.v0.copy( source.v0 );
38241 this.v1.copy( source.v1 );
38242 this.v2.copy( source.v2 );
38243 this.v3.copy( source.v3 );
38249 CubicBezierCurve3.prototype.toJSON = function () {
38251 const data = Curve.prototype.toJSON.call( this );
38253 data.v0 = this.v0.toArray();
38254 data.v1 = this.v1.toArray();
38255 data.v2 = this.v2.toArray();
38256 data.v3 = this.v3.toArray();
38262 CubicBezierCurve3.prototype.fromJSON = function ( json ) {
38264 Curve.prototype.fromJSON.call( this, json );
38266 this.v0.fromArray( json.v0 );
38267 this.v1.fromArray( json.v1 );
38268 this.v2.fromArray( json.v2 );
38269 this.v3.fromArray( json.v3 );
38275 function LineCurve( v1 = new Vector2(), v2 = new Vector2() ) {
38277 Curve.call( this );
38279 this.type = 'LineCurve';
38286 LineCurve.prototype = Object.create( Curve.prototype );
38287 LineCurve.prototype.constructor = LineCurve;
38289 LineCurve.prototype.isLineCurve = true;
38291 LineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38293 const point = optionalTarget;
38297 point.copy( this.v2 );
38301 point.copy( this.v2 ).sub( this.v1 );
38302 point.multiplyScalar( t ).add( this.v1 );
38310 // Line curve is linear, so we can overwrite default getPointAt
38312 LineCurve.prototype.getPointAt = function ( u, optionalTarget ) {
38314 return this.getPoint( u, optionalTarget );
38318 LineCurve.prototype.getTangent = function ( t, optionalTarget ) {
38320 const tangent = optionalTarget || new Vector2();
38322 tangent.copy( this.v2 ).sub( this.v1 ).normalize();
38328 LineCurve.prototype.copy = function ( source ) {
38330 Curve.prototype.copy.call( this, source );
38332 this.v1.copy( source.v1 );
38333 this.v2.copy( source.v2 );
38339 LineCurve.prototype.toJSON = function () {
38341 const data = Curve.prototype.toJSON.call( this );
38343 data.v1 = this.v1.toArray();
38344 data.v2 = this.v2.toArray();
38350 LineCurve.prototype.fromJSON = function ( json ) {
38352 Curve.prototype.fromJSON.call( this, json );
38354 this.v1.fromArray( json.v1 );
38355 this.v2.fromArray( json.v2 );
38361 function LineCurve3( v1 = new Vector3(), v2 = new Vector3() ) {
38363 Curve.call( this );
38365 this.type = 'LineCurve3';
38372 LineCurve3.prototype = Object.create( Curve.prototype );
38373 LineCurve3.prototype.constructor = LineCurve3;
38375 LineCurve3.prototype.isLineCurve3 = true;
38377 LineCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38379 const point = optionalTarget;
38383 point.copy( this.v2 );
38387 point.copy( this.v2 ).sub( this.v1 );
38388 point.multiplyScalar( t ).add( this.v1 );
38396 // Line curve is linear, so we can overwrite default getPointAt
38398 LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) {
38400 return this.getPoint( u, optionalTarget );
38404 LineCurve3.prototype.copy = function ( source ) {
38406 Curve.prototype.copy.call( this, source );
38408 this.v1.copy( source.v1 );
38409 this.v2.copy( source.v2 );
38415 LineCurve3.prototype.toJSON = function () {
38417 const data = Curve.prototype.toJSON.call( this );
38419 data.v1 = this.v1.toArray();
38420 data.v2 = this.v2.toArray();
38426 LineCurve3.prototype.fromJSON = function ( json ) {
38428 Curve.prototype.fromJSON.call( this, json );
38430 this.v1.fromArray( json.v1 );
38431 this.v2.fromArray( json.v2 );
38437 function QuadraticBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
38439 Curve.call( this );
38441 this.type = 'QuadraticBezierCurve';
38449 QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
38450 QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
38452 QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
38454 QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38456 const point = optionalTarget;
38458 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
38461 QuadraticBezier( t, v0.x, v1.x, v2.x ),
38462 QuadraticBezier( t, v0.y, v1.y, v2.y )
38469 QuadraticBezierCurve.prototype.copy = function ( source ) {
38471 Curve.prototype.copy.call( this, source );
38473 this.v0.copy( source.v0 );
38474 this.v1.copy( source.v1 );
38475 this.v2.copy( source.v2 );
38481 QuadraticBezierCurve.prototype.toJSON = function () {
38483 const data = Curve.prototype.toJSON.call( this );
38485 data.v0 = this.v0.toArray();
38486 data.v1 = this.v1.toArray();
38487 data.v2 = this.v2.toArray();
38493 QuadraticBezierCurve.prototype.fromJSON = function ( json ) {
38495 Curve.prototype.fromJSON.call( this, json );
38497 this.v0.fromArray( json.v0 );
38498 this.v1.fromArray( json.v1 );
38499 this.v2.fromArray( json.v2 );
38505 function QuadraticBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
38507 Curve.call( this );
38509 this.type = 'QuadraticBezierCurve3';
38517 QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
38518 QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
38520 QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
38522 QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38524 const point = optionalTarget;
38526 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
38529 QuadraticBezier( t, v0.x, v1.x, v2.x ),
38530 QuadraticBezier( t, v0.y, v1.y, v2.y ),
38531 QuadraticBezier( t, v0.z, v1.z, v2.z )
38538 QuadraticBezierCurve3.prototype.copy = function ( source ) {
38540 Curve.prototype.copy.call( this, source );
38542 this.v0.copy( source.v0 );
38543 this.v1.copy( source.v1 );
38544 this.v2.copy( source.v2 );
38550 QuadraticBezierCurve3.prototype.toJSON = function () {
38552 const data = Curve.prototype.toJSON.call( this );
38554 data.v0 = this.v0.toArray();
38555 data.v1 = this.v1.toArray();
38556 data.v2 = this.v2.toArray();
38562 QuadraticBezierCurve3.prototype.fromJSON = function ( json ) {
38564 Curve.prototype.fromJSON.call( this, json );
38566 this.v0.fromArray( json.v0 );
38567 this.v1.fromArray( json.v1 );
38568 this.v2.fromArray( json.v2 );
38574 function SplineCurve( points = [] ) {
38576 Curve.call( this );
38578 this.type = 'SplineCurve';
38580 this.points = points;
38584 SplineCurve.prototype = Object.create( Curve.prototype );
38585 SplineCurve.prototype.constructor = SplineCurve;
38587 SplineCurve.prototype.isSplineCurve = true;
38589 SplineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38591 const point = optionalTarget;
38593 const points = this.points;
38594 const p = ( points.length - 1 ) * t;
38596 const intPoint = Math.floor( p );
38597 const weight = p - intPoint;
38599 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
38600 const p1 = points[ intPoint ];
38601 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
38602 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
38605 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
38606 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
38613 SplineCurve.prototype.copy = function ( source ) {
38615 Curve.prototype.copy.call( this, source );
38619 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
38621 const point = source.points[ i ];
38623 this.points.push( point.clone() );
38631 SplineCurve.prototype.toJSON = function () {
38633 const data = Curve.prototype.toJSON.call( this );
38637 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
38639 const point = this.points[ i ];
38640 data.points.push( point.toArray() );
38648 SplineCurve.prototype.fromJSON = function ( json ) {
38650 Curve.prototype.fromJSON.call( this, json );
38654 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
38656 const point = json.points[ i ];
38657 this.points.push( new Vector2().fromArray( point ) );
38665 var Curves = /*#__PURE__*/Object.freeze({
38667 ArcCurve: ArcCurve,
38668 CatmullRomCurve3: CatmullRomCurve3,
38669 CubicBezierCurve: CubicBezierCurve,
38670 CubicBezierCurve3: CubicBezierCurve3,
38671 EllipseCurve: EllipseCurve,
38672 LineCurve: LineCurve,
38673 LineCurve3: LineCurve3,
38674 QuadraticBezierCurve: QuadraticBezierCurve,
38675 QuadraticBezierCurve3: QuadraticBezierCurve3,
38676 SplineCurve: SplineCurve
38679 /**************************************************************
38680 * Curved Path - a curve path is simply a array of connected
38681 * curves, but retains the api of a curve
38682 **************************************************************/
38684 function CurvePath() {
38686 Curve.call( this );
38688 this.type = 'CurvePath';
38691 this.autoClose = false; // Automatically closes the path
38695 CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
38697 constructor: CurvePath,
38699 add: function ( curve ) {
38701 this.curves.push( curve );
38705 closePath: function () {
38707 // Add a line curve if start and end of lines are not connected
38708 const startPoint = this.curves[ 0 ].getPoint( 0 );
38709 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
38711 if ( ! startPoint.equals( endPoint ) ) {
38713 this.curves.push( new LineCurve( endPoint, startPoint ) );
38719 // To get accurate point with reference to
38720 // entire path distance at time t,
38721 // following has to be done:
38723 // 1. Length of each sub path have to be known
38724 // 2. Locate and identify type of curve
38725 // 3. Get t for the curve
38726 // 4. Return curve.getPointAt(t')
38728 getPoint: function ( t ) {
38730 const d = t * this.getLength();
38731 const curveLengths = this.getCurveLengths();
38734 // To think about boundaries points.
38736 while ( i < curveLengths.length ) {
38738 if ( curveLengths[ i ] >= d ) {
38740 const diff = curveLengths[ i ] - d;
38741 const curve = this.curves[ i ];
38743 const segmentLength = curve.getLength();
38744 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
38746 return curve.getPointAt( u );
38756 // loop where sum != 0, sum > d , sum+1 <d
38760 // We cannot use the default THREE.Curve getPoint() with getLength() because in
38761 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
38762 // getPoint() depends on getLength
38764 getLength: function () {
38766 const lens = this.getCurveLengths();
38767 return lens[ lens.length - 1 ];
38771 // cacheLengths must be recalculated.
38772 updateArcLengths: function () {
38774 this.needsUpdate = true;
38775 this.cacheLengths = null;
38776 this.getCurveLengths();
38780 // Compute lengths and cache them
38781 // We cannot overwrite getLengths() because UtoT mapping uses it.
38783 getCurveLengths: function () {
38785 // We use cache values if curves and cache array are same length
38787 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
38789 return this.cacheLengths;
38793 // Get length of sub-curve
38794 // Push sums into cached array
38796 const lengths = [];
38799 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
38801 sums += this.curves[ i ].getLength();
38802 lengths.push( sums );
38806 this.cacheLengths = lengths;
38812 getSpacedPoints: function ( divisions = 40 ) {
38816 for ( let i = 0; i <= divisions; i ++ ) {
38818 points.push( this.getPoint( i / divisions ) );
38822 if ( this.autoClose ) {
38824 points.push( points[ 0 ] );
38832 getPoints: function ( divisions = 12 ) {
38837 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
38839 const curve = curves[ i ];
38840 const resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
38841 : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1
38842 : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
38845 const pts = curve.getPoints( resolution );
38847 for ( let j = 0; j < pts.length; j ++ ) {
38849 const point = pts[ j ];
38851 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
38853 points.push( point );
38860 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
38862 points.push( points[ 0 ] );
38870 copy: function ( source ) {
38872 Curve.prototype.copy.call( this, source );
38876 for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
38878 const curve = source.curves[ i ];
38880 this.curves.push( curve.clone() );
38884 this.autoClose = source.autoClose;
38890 toJSON: function () {
38892 const data = Curve.prototype.toJSON.call( this );
38894 data.autoClose = this.autoClose;
38897 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
38899 const curve = this.curves[ i ];
38900 data.curves.push( curve.toJSON() );
38908 fromJSON: function ( json ) {
38910 Curve.prototype.fromJSON.call( this, json );
38912 this.autoClose = json.autoClose;
38915 for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
38917 const curve = json.curves[ i ];
38918 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
38928 function Path( points ) {
38930 CurvePath.call( this );
38932 this.type = 'Path';
38934 this.currentPoint = new Vector2();
38938 this.setFromPoints( points );
38944 Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
38948 setFromPoints: function ( points ) {
38950 this.moveTo( points[ 0 ].x, points[ 0 ].y );
38952 for ( let i = 1, l = points.length; i < l; i ++ ) {
38954 this.lineTo( points[ i ].x, points[ i ].y );
38962 moveTo: function ( x, y ) {
38964 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
38970 lineTo: function ( x, y ) {
38972 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
38973 this.curves.push( curve );
38975 this.currentPoint.set( x, y );
38981 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
38983 const curve = new QuadraticBezierCurve(
38984 this.currentPoint.clone(),
38985 new Vector2( aCPx, aCPy ),
38986 new Vector2( aX, aY )
38989 this.curves.push( curve );
38991 this.currentPoint.set( aX, aY );
38997 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
38999 const curve = new CubicBezierCurve(
39000 this.currentPoint.clone(),
39001 new Vector2( aCP1x, aCP1y ),
39002 new Vector2( aCP2x, aCP2y ),
39003 new Vector2( aX, aY )
39006 this.curves.push( curve );
39008 this.currentPoint.set( aX, aY );
39014 splineThru: function ( pts /*Array of Vector*/ ) {
39016 const npts = [ this.currentPoint.clone() ].concat( pts );
39018 const curve = new SplineCurve( npts );
39019 this.curves.push( curve );
39021 this.currentPoint.copy( pts[ pts.length - 1 ] );
39027 arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
39029 const x0 = this.currentPoint.x;
39030 const y0 = this.currentPoint.y;
39032 this.absarc( aX + x0, aY + y0, aRadius,
39033 aStartAngle, aEndAngle, aClockwise );
39039 absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
39041 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
39047 ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
39049 const x0 = this.currentPoint.x;
39050 const y0 = this.currentPoint.y;
39052 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
39058 absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
39060 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
39062 if ( this.curves.length > 0 ) {
39064 // if a previous curve is present, attempt to join
39065 const firstPoint = curve.getPoint( 0 );
39067 if ( ! firstPoint.equals( this.currentPoint ) ) {
39069 this.lineTo( firstPoint.x, firstPoint.y );
39075 this.curves.push( curve );
39077 const lastPoint = curve.getPoint( 1 );
39078 this.currentPoint.copy( lastPoint );
39084 copy: function ( source ) {
39086 CurvePath.prototype.copy.call( this, source );
39088 this.currentPoint.copy( source.currentPoint );
39094 toJSON: function () {
39096 const data = CurvePath.prototype.toJSON.call( this );
39098 data.currentPoint = this.currentPoint.toArray();
39104 fromJSON: function ( json ) {
39106 CurvePath.prototype.fromJSON.call( this, json );
39108 this.currentPoint.fromArray( json.currentPoint );
39116 function Shape( points ) {
39118 Path.call( this, points );
39120 this.uuid = MathUtils.generateUUID();
39122 this.type = 'Shape';
39128 Shape.prototype = Object.assign( Object.create( Path.prototype ), {
39130 constructor: Shape,
39132 getPointsHoles: function ( divisions ) {
39134 const holesPts = [];
39136 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
39138 holesPts[ i ] = this.holes[ i ].getPoints( divisions );
39146 // get points of shape and holes (keypoints based on segments parameter)
39148 extractPoints: function ( divisions ) {
39152 shape: this.getPoints( divisions ),
39153 holes: this.getPointsHoles( divisions )
39159 copy: function ( source ) {
39161 Path.prototype.copy.call( this, source );
39165 for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
39167 const hole = source.holes[ i ];
39169 this.holes.push( hole.clone() );
39177 toJSON: function () {
39179 const data = Path.prototype.toJSON.call( this );
39181 data.uuid = this.uuid;
39184 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
39186 const hole = this.holes[ i ];
39187 data.holes.push( hole.toJSON() );
39195 fromJSON: function ( json ) {
39197 Path.prototype.fromJSON.call( this, json );
39199 this.uuid = json.uuid;
39202 for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
39204 const hole = json.holes[ i ];
39205 this.holes.push( new Path().fromJSON( hole ) );
39215 function Light( color, intensity = 1 ) {
39217 Object3D.call( this );
39219 this.type = 'Light';
39221 this.color = new Color( color );
39222 this.intensity = intensity;
39226 Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
39228 constructor: Light,
39232 copy: function ( source ) {
39234 Object3D.prototype.copy.call( this, source );
39236 this.color.copy( source.color );
39237 this.intensity = source.intensity;
39243 toJSON: function ( meta ) {
39245 const data = Object3D.prototype.toJSON.call( this, meta );
39247 data.object.color = this.color.getHex();
39248 data.object.intensity = this.intensity;
39250 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
39252 if ( this.distance !== undefined ) data.object.distance = this.distance;
39253 if ( this.angle !== undefined ) data.object.angle = this.angle;
39254 if ( this.decay !== undefined ) data.object.decay = this.decay;
39255 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
39257 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
39265 function HemisphereLight( skyColor, groundColor, intensity ) {
39267 Light.call( this, skyColor, intensity );
39269 this.type = 'HemisphereLight';
39271 this.position.copy( Object3D.DefaultUp );
39272 this.updateMatrix();
39274 this.groundColor = new Color( groundColor );
39278 HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
39280 constructor: HemisphereLight,
39282 isHemisphereLight: true,
39284 copy: function ( source ) {
39286 Light.prototype.copy.call( this, source );
39288 this.groundColor.copy( source.groundColor );
39296 function LightShadow( camera ) {
39298 this.camera = camera;
39301 this.normalBias = 0;
39304 this.mapSize = new Vector2( 512, 512 );
39307 this.mapPass = null;
39308 this.matrix = new Matrix4();
39310 this.autoUpdate = true;
39311 this.needsUpdate = false;
39313 this._frustum = new Frustum();
39314 this._frameExtents = new Vector2( 1, 1 );
39316 this._viewportCount = 1;
39318 this._viewports = [
39320 new Vector4( 0, 0, 1, 1 )
39326 Object.assign( LightShadow.prototype, {
39328 _projScreenMatrix: new Matrix4(),
39330 _lightPositionWorld: new Vector3(),
39332 _lookTarget: new Vector3(),
39334 getViewportCount: function () {
39336 return this._viewportCount;
39340 getFrustum: function () {
39342 return this._frustum;
39346 updateMatrices: function ( light ) {
39348 const shadowCamera = this.camera,
39349 shadowMatrix = this.matrix,
39350 projScreenMatrix = this._projScreenMatrix,
39351 lookTarget = this._lookTarget,
39352 lightPositionWorld = this._lightPositionWorld;
39354 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
39355 shadowCamera.position.copy( lightPositionWorld );
39357 lookTarget.setFromMatrixPosition( light.target.matrixWorld );
39358 shadowCamera.lookAt( lookTarget );
39359 shadowCamera.updateMatrixWorld();
39361 projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
39362 this._frustum.setFromProjectionMatrix( projScreenMatrix );
39365 0.5, 0.0, 0.0, 0.5,
39366 0.0, 0.5, 0.0, 0.5,
39367 0.0, 0.0, 0.5, 0.5,
39371 shadowMatrix.multiply( shadowCamera.projectionMatrix );
39372 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
39376 getViewport: function ( viewportIndex ) {
39378 return this._viewports[ viewportIndex ];
39382 getFrameExtents: function () {
39384 return this._frameExtents;
39388 copy: function ( source ) {
39390 this.camera = source.camera.clone();
39392 this.bias = source.bias;
39393 this.radius = source.radius;
39395 this.mapSize.copy( source.mapSize );
39401 clone: function () {
39403 return new this.constructor().copy( this );
39407 toJSON: function () {
39411 if ( this.bias !== 0 ) object.bias = this.bias;
39412 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
39413 if ( this.radius !== 1 ) object.radius = this.radius;
39414 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
39416 object.camera = this.camera.toJSON( false ).object;
39417 delete object.camera.matrix;
39425 function SpotLightShadow() {
39427 LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
39433 SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39435 constructor: SpotLightShadow,
39437 isSpotLightShadow: true,
39439 updateMatrices: function ( light ) {
39441 const camera = this.camera;
39443 const fov = MathUtils.RAD2DEG * 2 * light.angle * this.focus;
39444 const aspect = this.mapSize.width / this.mapSize.height;
39445 const far = light.distance || camera.far;
39447 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
39450 camera.aspect = aspect;
39452 camera.updateProjectionMatrix();
39456 LightShadow.prototype.updateMatrices.call( this, light );
39462 function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
39464 Light.call( this, color, intensity );
39466 this.type = 'SpotLight';
39468 this.position.copy( Object3D.DefaultUp );
39469 this.updateMatrix();
39471 this.target = new Object3D();
39473 Object.defineProperty( this, 'power', {
39476 // intensity = power per solid angle.
39477 // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39478 return this.intensity * Math.PI;
39481 set: function ( power ) {
39483 // intensity = power per solid angle.
39484 // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39485 this.intensity = power / Math.PI;
39490 this.distance = ( distance !== undefined ) ? distance : 0;
39491 this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
39492 this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
39493 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
39495 this.shadow = new SpotLightShadow();
39499 SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
39501 constructor: SpotLight,
39505 copy: function ( source ) {
39507 Light.prototype.copy.call( this, source );
39509 this.distance = source.distance;
39510 this.angle = source.angle;
39511 this.penumbra = source.penumbra;
39512 this.decay = source.decay;
39514 this.target = source.target.clone();
39516 this.shadow = source.shadow.clone();
39524 function PointLightShadow() {
39526 LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) );
39528 this._frameExtents = new Vector2( 4, 2 );
39530 this._viewportCount = 6;
39532 this._viewports = [
39533 // These viewports map a cube-map onto a 2D texture with the
39534 // following orientation:
39539 // X - Positive x direction
39540 // x - Negative x direction
39541 // Y - Positive y direction
39542 // y - Negative y direction
39543 // Z - Positive z direction
39544 // z - Negative z direction
39547 new Vector4( 2, 1, 1, 1 ),
39549 new Vector4( 0, 1, 1, 1 ),
39551 new Vector4( 3, 1, 1, 1 ),
39553 new Vector4( 1, 1, 1, 1 ),
39555 new Vector4( 3, 0, 1, 1 ),
39557 new Vector4( 1, 0, 1, 1 )
39560 this._cubeDirections = [
39561 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
39562 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
39566 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
39567 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
39572 PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39574 constructor: PointLightShadow,
39576 isPointLightShadow: true,
39578 updateMatrices: function ( light, viewportIndex = 0 ) {
39580 const camera = this.camera,
39581 shadowMatrix = this.matrix,
39582 lightPositionWorld = this._lightPositionWorld,
39583 lookTarget = this._lookTarget,
39584 projScreenMatrix = this._projScreenMatrix;
39586 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
39587 camera.position.copy( lightPositionWorld );
39589 lookTarget.copy( camera.position );
39590 lookTarget.add( this._cubeDirections[ viewportIndex ] );
39591 camera.up.copy( this._cubeUps[ viewportIndex ] );
39592 camera.lookAt( lookTarget );
39593 camera.updateMatrixWorld();
39595 shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z );
39597 projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
39598 this._frustum.setFromProjectionMatrix( projScreenMatrix );
39604 function PointLight( color, intensity, distance, decay ) {
39606 Light.call( this, color, intensity );
39608 this.type = 'PointLight';
39610 Object.defineProperty( this, 'power', {
39613 // intensity = power per solid angle.
39614 // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39615 return this.intensity * 4 * Math.PI;
39618 set: function ( power ) {
39620 // intensity = power per solid angle.
39621 // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39622 this.intensity = power / ( 4 * Math.PI );
39627 this.distance = ( distance !== undefined ) ? distance : 0;
39628 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
39630 this.shadow = new PointLightShadow();
39634 PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
39636 constructor: PointLight,
39638 isPointLight: true,
39640 copy: function ( source ) {
39642 Light.prototype.copy.call( this, source );
39644 this.distance = source.distance;
39645 this.decay = source.decay;
39647 this.shadow = source.shadow.clone();
39655 function OrthographicCamera( left, right, top, bottom, near, far ) {
39657 Camera.call( this );
39659 this.type = 'OrthographicCamera';
39664 this.left = ( left !== undefined ) ? left : - 1;
39665 this.right = ( right !== undefined ) ? right : 1;
39666 this.top = ( top !== undefined ) ? top : 1;
39667 this.bottom = ( bottom !== undefined ) ? bottom : - 1;
39669 this.near = ( near !== undefined ) ? near : 0.1;
39670 this.far = ( far !== undefined ) ? far : 2000;
39672 this.updateProjectionMatrix();
39676 OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
39678 constructor: OrthographicCamera,
39680 isOrthographicCamera: true,
39682 copy: function ( source, recursive ) {
39684 Camera.prototype.copy.call( this, source, recursive );
39686 this.left = source.left;
39687 this.right = source.right;
39688 this.top = source.top;
39689 this.bottom = source.bottom;
39690 this.near = source.near;
39691 this.far = source.far;
39693 this.zoom = source.zoom;
39694 this.view = source.view === null ? null : Object.assign( {}, source.view );
39700 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
39702 if ( this.view === null ) {
39716 this.view.enabled = true;
39717 this.view.fullWidth = fullWidth;
39718 this.view.fullHeight = fullHeight;
39719 this.view.offsetX = x;
39720 this.view.offsetY = y;
39721 this.view.width = width;
39722 this.view.height = height;
39724 this.updateProjectionMatrix();
39728 clearViewOffset: function () {
39730 if ( this.view !== null ) {
39732 this.view.enabled = false;
39736 this.updateProjectionMatrix();
39740 updateProjectionMatrix: function () {
39742 const dx = ( this.right - this.left ) / ( 2 * this.zoom );
39743 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
39744 const cx = ( this.right + this.left ) / 2;
39745 const cy = ( this.top + this.bottom ) / 2;
39747 let left = cx - dx;
39748 let right = cx + dx;
39750 let bottom = cy - dy;
39752 if ( this.view !== null && this.view.enabled ) {
39754 const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
39755 const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
39757 left += scaleW * this.view.offsetX;
39758 right = left + scaleW * this.view.width;
39759 top -= scaleH * this.view.offsetY;
39760 bottom = top - scaleH * this.view.height;
39764 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
39766 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
39770 toJSON: function ( meta ) {
39772 const data = Object3D.prototype.toJSON.call( this, meta );
39774 data.object.zoom = this.zoom;
39775 data.object.left = this.left;
39776 data.object.right = this.right;
39777 data.object.top = this.top;
39778 data.object.bottom = this.bottom;
39779 data.object.near = this.near;
39780 data.object.far = this.far;
39782 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
39790 function DirectionalLightShadow() {
39792 LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
39796 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39798 constructor: DirectionalLightShadow,
39800 isDirectionalLightShadow: true,
39802 updateMatrices: function ( light ) {
39804 LightShadow.prototype.updateMatrices.call( this, light );
39810 function DirectionalLight( color, intensity ) {
39812 Light.call( this, color, intensity );
39814 this.type = 'DirectionalLight';
39816 this.position.copy( Object3D.DefaultUp );
39817 this.updateMatrix();
39819 this.target = new Object3D();
39821 this.shadow = new DirectionalLightShadow();
39825 DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
39827 constructor: DirectionalLight,
39829 isDirectionalLight: true,
39831 copy: function ( source ) {
39833 Light.prototype.copy.call( this, source );
39835 this.target = source.target.clone();
39837 this.shadow = source.shadow.clone();
39845 function AmbientLight( color, intensity ) {
39847 Light.call( this, color, intensity );
39849 this.type = 'AmbientLight';
39853 AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
39855 constructor: AmbientLight,
39857 isAmbientLight: true
39861 function RectAreaLight( color, intensity, width, height ) {
39863 Light.call( this, color, intensity );
39865 this.type = 'RectAreaLight';
39867 this.width = ( width !== undefined ) ? width : 10;
39868 this.height = ( height !== undefined ) ? height : 10;
39872 RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
39874 constructor: RectAreaLight,
39876 isRectAreaLight: true,
39878 copy: function ( source ) {
39880 Light.prototype.copy.call( this, source );
39882 this.width = source.width;
39883 this.height = source.height;
39889 toJSON: function ( meta ) {
39891 const data = Light.prototype.toJSON.call( this, meta );
39893 data.object.width = this.width;
39894 data.object.height = this.height;
39903 * Primary reference:
39904 * https://graphics.stanford.edu/papers/envmap/envmap.pdf
39906 * Secondary reference:
39907 * https://www.ppsloan.org/publications/StupidSH36.pdf
39910 // 3-band SH defined by 9 coefficients
39912 class SphericalHarmonics3 {
39916 Object.defineProperty( this, 'isSphericalHarmonics3', { value: true } );
39918 this.coefficients = [];
39920 for ( let i = 0; i < 9; i ++ ) {
39922 this.coefficients.push( new Vector3() );
39928 set( coefficients ) {
39930 for ( let i = 0; i < 9; i ++ ) {
39932 this.coefficients[ i ].copy( coefficients[ i ] );
39942 for ( let i = 0; i < 9; i ++ ) {
39944 this.coefficients[ i ].set( 0, 0, 0 );
39952 // get the radiance in the direction of the normal
39953 // target is a Vector3
39954 getAt( normal, target ) {
39956 // normal is assumed to be unit length
39958 const x = normal.x, y = normal.y, z = normal.z;
39960 const coeff = this.coefficients;
39963 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
39966 target.addScaledVector( coeff[ 1 ], 0.488603 * y );
39967 target.addScaledVector( coeff[ 2 ], 0.488603 * z );
39968 target.addScaledVector( coeff[ 3 ], 0.488603 * x );
39971 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
39972 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
39973 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
39974 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
39975 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
39981 // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
39982 // target is a Vector3
39983 // https://graphics.stanford.edu/papers/envmap/envmap.pdf
39984 getIrradianceAt( normal, target ) {
39986 // normal is assumed to be unit length
39988 const x = normal.x, y = normal.y, z = normal.z;
39990 const coeff = this.coefficients;
39993 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
39996 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
39997 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
39998 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
40001 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
40002 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
40003 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
40004 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
40005 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
40013 for ( let i = 0; i < 9; i ++ ) {
40015 this.coefficients[ i ].add( sh.coefficients[ i ] );
40023 addScaledSH( sh, s ) {
40025 for ( let i = 0; i < 9; i ++ ) {
40027 this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
40037 for ( let i = 0; i < 9; i ++ ) {
40039 this.coefficients[ i ].multiplyScalar( s );
40047 lerp( sh, alpha ) {
40049 for ( let i = 0; i < 9; i ++ ) {
40051 this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
40061 for ( let i = 0; i < 9; i ++ ) {
40063 if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
40077 return this.set( sh.coefficients );
40083 return new this.constructor().copy( this );
40087 fromArray( array, offset = 0 ) {
40089 const coefficients = this.coefficients;
40091 for ( let i = 0; i < 9; i ++ ) {
40093 coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
40101 toArray( array = [], offset = 0 ) {
40103 const coefficients = this.coefficients;
40105 for ( let i = 0; i < 9; i ++ ) {
40107 coefficients[ i ].toArray( array, offset + ( i * 3 ) );
40115 // evaluate the basis functions
40116 // shBasis is an Array[ 9 ]
40117 static getBasisAt( normal, shBasis ) {
40119 // normal is assumed to be unit length
40121 const x = normal.x, y = normal.y, z = normal.z;
40124 shBasis[ 0 ] = 0.282095;
40127 shBasis[ 1 ] = 0.488603 * y;
40128 shBasis[ 2 ] = 0.488603 * z;
40129 shBasis[ 3 ] = 0.488603 * x;
40132 shBasis[ 4 ] = 1.092548 * x * y;
40133 shBasis[ 5 ] = 1.092548 * y * z;
40134 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
40135 shBasis[ 7 ] = 1.092548 * x * z;
40136 shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
40142 function LightProbe( sh, intensity ) {
40144 Light.call( this, undefined, intensity );
40146 this.type = 'LightProbe';
40148 this.sh = ( sh !== undefined ) ? sh : new SphericalHarmonics3();
40152 LightProbe.prototype = Object.assign( Object.create( Light.prototype ), {
40154 constructor: LightProbe,
40156 isLightProbe: true,
40158 copy: function ( source ) {
40160 Light.prototype.copy.call( this, source );
40162 this.sh.copy( source.sh );
40168 fromJSON: function ( json ) {
40170 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
40171 this.sh.fromArray( json.sh );
40177 toJSON: function ( meta ) {
40179 const data = Light.prototype.toJSON.call( this, meta );
40181 data.object.sh = this.sh.toArray();
40189 function MaterialLoader( manager ) {
40191 Loader.call( this, manager );
40193 this.textures = {};
40197 MaterialLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40199 constructor: MaterialLoader,
40201 load: function ( url, onLoad, onProgress, onError ) {
40203 const scope = this;
40205 const loader = new FileLoader( scope.manager );
40206 loader.setPath( scope.path );
40207 loader.setRequestHeader( scope.requestHeader );
40208 loader.setWithCredentials( scope.withCredentials );
40209 loader.load( url, function ( text ) {
40213 onLoad( scope.parse( JSON.parse( text ) ) );
40223 console.error( e );
40227 scope.manager.itemError( url );
40231 }, onProgress, onError );
40235 parse: function ( json ) {
40237 const textures = this.textures;
40239 function getTexture( name ) {
40241 if ( textures[ name ] === undefined ) {
40243 console.warn( 'THREE.MaterialLoader: Undefined texture', name );
40247 return textures[ name ];
40251 const material = new Materials[ json.type ]();
40253 if ( json.uuid !== undefined ) material.uuid = json.uuid;
40254 if ( json.name !== undefined ) material.name = json.name;
40255 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
40256 if ( json.roughness !== undefined ) material.roughness = json.roughness;
40257 if ( json.metalness !== undefined ) material.metalness = json.metalness;
40258 if ( json.sheen !== undefined ) material.sheen = new Color().setHex( json.sheen );
40259 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
40260 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
40261 if ( json.shininess !== undefined ) material.shininess = json.shininess;
40262 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
40263 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
40264 if ( json.fog !== undefined ) material.fog = json.fog;
40265 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
40266 if ( json.blending !== undefined ) material.blending = json.blending;
40267 if ( json.combine !== undefined ) material.combine = json.combine;
40268 if ( json.side !== undefined ) material.side = json.side;
40269 if ( json.opacity !== undefined ) material.opacity = json.opacity;
40270 if ( json.transparent !== undefined ) material.transparent = json.transparent;
40271 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
40272 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
40273 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
40274 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
40276 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
40277 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
40278 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
40279 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
40280 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
40281 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
40282 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
40283 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
40285 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
40286 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
40287 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
40288 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
40290 if ( json.rotation !== undefined ) material.rotation = json.rotation;
40292 if ( json.linewidth !== 1 ) material.linewidth = json.linewidth;
40293 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
40294 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
40295 if ( json.scale !== undefined ) material.scale = json.scale;
40297 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
40298 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
40299 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
40301 if ( json.skinning !== undefined ) material.skinning = json.skinning;
40302 if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
40303 if ( json.morphNormals !== undefined ) material.morphNormals = json.morphNormals;
40304 if ( json.dithering !== undefined ) material.dithering = json.dithering;
40306 if ( json.vertexTangents !== undefined ) material.vertexTangents = json.vertexTangents;
40308 if ( json.visible !== undefined ) material.visible = json.visible;
40310 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
40312 if ( json.userData !== undefined ) material.userData = json.userData;
40314 if ( json.vertexColors !== undefined ) {
40316 if ( typeof json.vertexColors === 'number' ) {
40318 material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
40322 material.vertexColors = json.vertexColors;
40330 if ( json.uniforms !== undefined ) {
40332 for ( const name in json.uniforms ) {
40334 const uniform = json.uniforms[ name ];
40336 material.uniforms[ name ] = {};
40338 switch ( uniform.type ) {
40341 material.uniforms[ name ].value = getTexture( uniform.value );
40345 material.uniforms[ name ].value = new Color().setHex( uniform.value );
40349 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
40353 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
40357 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
40361 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
40365 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
40369 material.uniforms[ name ].value = uniform.value;
40377 if ( json.defines !== undefined ) material.defines = json.defines;
40378 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
40379 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
40381 if ( json.extensions !== undefined ) {
40383 for ( const key in json.extensions ) {
40385 material.extensions[ key ] = json.extensions[ key ];
40393 if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
40395 // for PointsMaterial
40397 if ( json.size !== undefined ) material.size = json.size;
40398 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
40402 if ( json.map !== undefined ) material.map = getTexture( json.map );
40403 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
40405 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
40407 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
40408 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
40410 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
40411 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
40412 if ( json.normalScale !== undefined ) {
40414 let normalScale = json.normalScale;
40416 if ( Array.isArray( normalScale ) === false ) {
40418 // Blender exporter used to export a scalar. See #7459
40420 normalScale = [ normalScale, normalScale ];
40424 material.normalScale = new Vector2().fromArray( normalScale );
40428 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
40429 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
40430 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
40432 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
40433 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
40435 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
40436 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
40438 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
40440 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
40441 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
40443 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
40444 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
40446 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
40447 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
40449 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
40450 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
40452 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
40454 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
40455 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
40456 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
40457 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
40459 if ( json.transmission !== undefined ) material.transmission = json.transmission;
40460 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
40466 setTextures: function ( value ) {
40468 this.textures = value;
40475 const LoaderUtils = {
40477 decodeText: function ( array ) {
40479 if ( typeof TextDecoder !== 'undefined' ) {
40481 return new TextDecoder().decode( array );
40485 // Avoid the String.fromCharCode.apply(null, array) shortcut, which
40486 // throws a "maximum call stack size exceeded" error for large arrays.
40490 for ( let i = 0, il = array.length; i < il; i ++ ) {
40492 // Implicitly assumes little-endian.
40493 s += String.fromCharCode( array[ i ] );
40499 // merges multi-byte utf-8 characters.
40501 return decodeURIComponent( escape( s ) );
40503 } catch ( e ) { // see #16358
40511 extractUrlBase: function ( url ) {
40513 const index = url.lastIndexOf( '/' );
40515 if ( index === - 1 ) return './';
40517 return url.substr( 0, index + 1 );
40523 function InstancedBufferGeometry() {
40525 BufferGeometry.call( this );
40527 this.type = 'InstancedBufferGeometry';
40528 this.instanceCount = Infinity;
40532 InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
40534 constructor: InstancedBufferGeometry,
40536 isInstancedBufferGeometry: true,
40538 copy: function ( source ) {
40540 BufferGeometry.prototype.copy.call( this, source );
40542 this.instanceCount = source.instanceCount;
40548 clone: function () {
40550 return new this.constructor().copy( this );
40554 toJSON: function () {
40556 const data = BufferGeometry.prototype.toJSON.call( this );
40558 data.instanceCount = this.instanceCount;
40560 data.isInstancedBufferGeometry = true;
40568 function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) {
40570 if ( typeof ( normalized ) === 'number' ) {
40572 meshPerAttribute = normalized;
40574 normalized = false;
40576 console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' );
40580 BufferAttribute.call( this, array, itemSize, normalized );
40582 this.meshPerAttribute = meshPerAttribute || 1;
40586 InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
40588 constructor: InstancedBufferAttribute,
40590 isInstancedBufferAttribute: true,
40592 copy: function ( source ) {
40594 BufferAttribute.prototype.copy.call( this, source );
40596 this.meshPerAttribute = source.meshPerAttribute;
40602 toJSON: function () {
40604 const data = BufferAttribute.prototype.toJSON.call( this );
40606 data.meshPerAttribute = this.meshPerAttribute;
40608 data.isInstancedBufferAttribute = true;
40616 function BufferGeometryLoader( manager ) {
40618 Loader.call( this, manager );
40622 BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40624 constructor: BufferGeometryLoader,
40626 load: function ( url, onLoad, onProgress, onError ) {
40628 const scope = this;
40630 const loader = new FileLoader( scope.manager );
40631 loader.setPath( scope.path );
40632 loader.setRequestHeader( scope.requestHeader );
40633 loader.setWithCredentials( scope.withCredentials );
40634 loader.load( url, function ( text ) {
40638 onLoad( scope.parse( JSON.parse( text ) ) );
40648 console.error( e );
40652 scope.manager.itemError( url );
40656 }, onProgress, onError );
40660 parse: function ( json ) {
40662 const interleavedBufferMap = {};
40663 const arrayBufferMap = {};
40665 function getInterleavedBuffer( json, uuid ) {
40667 if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
40669 const interleavedBuffers = json.interleavedBuffers;
40670 const interleavedBuffer = interleavedBuffers[ uuid ];
40672 const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
40674 const array = getTypedArray( interleavedBuffer.type, buffer );
40675 const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
40676 ib.uuid = interleavedBuffer.uuid;
40678 interleavedBufferMap[ uuid ] = ib;
40684 function getArrayBuffer( json, uuid ) {
40686 if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
40688 const arrayBuffers = json.arrayBuffers;
40689 const arrayBuffer = arrayBuffers[ uuid ];
40691 const ab = new Uint32Array( arrayBuffer ).buffer;
40693 arrayBufferMap[ uuid ] = ab;
40699 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
40701 const index = json.data.index;
40703 if ( index !== undefined ) {
40705 const typedArray = getTypedArray( index.type, index.array );
40706 geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
40710 const attributes = json.data.attributes;
40712 for ( const key in attributes ) {
40714 const attribute = attributes[ key ];
40715 let bufferAttribute;
40717 if ( attribute.isInterleavedBufferAttribute ) {
40719 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
40720 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
40724 const typedArray = getTypedArray( attribute.type, attribute.array );
40725 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
40726 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
40730 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
40731 geometry.setAttribute( key, bufferAttribute );
40735 const morphAttributes = json.data.morphAttributes;
40737 if ( morphAttributes ) {
40739 for ( const key in morphAttributes ) {
40741 const attributeArray = morphAttributes[ key ];
40745 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
40747 const attribute = attributeArray[ i ];
40748 let bufferAttribute;
40750 if ( attribute.isInterleavedBufferAttribute ) {
40752 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
40753 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
40757 const typedArray = getTypedArray( attribute.type, attribute.array );
40758 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
40762 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
40763 array.push( bufferAttribute );
40767 geometry.morphAttributes[ key ] = array;
40773 const morphTargetsRelative = json.data.morphTargetsRelative;
40775 if ( morphTargetsRelative ) {
40777 geometry.morphTargetsRelative = true;
40781 const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
40783 if ( groups !== undefined ) {
40785 for ( let i = 0, n = groups.length; i !== n; ++ i ) {
40787 const group = groups[ i ];
40789 geometry.addGroup( group.start, group.count, group.materialIndex );
40795 const boundingSphere = json.data.boundingSphere;
40797 if ( boundingSphere !== undefined ) {
40799 const center = new Vector3();
40801 if ( boundingSphere.center !== undefined ) {
40803 center.fromArray( boundingSphere.center );
40807 geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
40811 if ( json.name ) geometry.name = json.name;
40812 if ( json.userData ) geometry.userData = json.userData;
40820 class ObjectLoader extends Loader {
40822 constructor( manager ) {
40828 load( url, onLoad, onProgress, onError ) {
40830 const scope = this;
40832 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
40833 this.resourcePath = this.resourcePath || path;
40835 const loader = new FileLoader( this.manager );
40836 loader.setPath( this.path );
40837 loader.setRequestHeader( this.requestHeader );
40838 loader.setWithCredentials( this.withCredentials );
40839 loader.load( url, function ( text ) {
40845 json = JSON.parse( text );
40847 } catch ( error ) {
40849 if ( onError !== undefined ) onError( error );
40851 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
40857 const metadata = json.metadata;
40859 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
40861 console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
40866 scope.parse( json, onLoad );
40868 }, onProgress, onError );
40872 parse( json, onLoad ) {
40874 const animations = this.parseAnimations( json.animations );
40875 const shapes = this.parseShapes( json.shapes );
40876 const geometries = this.parseGeometries( json.geometries, shapes );
40878 const images = this.parseImages( json.images, function () {
40880 if ( onLoad !== undefined ) onLoad( object );
40884 const textures = this.parseTextures( json.textures, images );
40885 const materials = this.parseMaterials( json.materials, textures );
40887 const object = this.parseObject( json.object, geometries, materials, animations );
40888 const skeletons = this.parseSkeletons( json.skeletons, object );
40890 this.bindSkeletons( object, skeletons );
40894 if ( onLoad !== undefined ) {
40896 let hasImages = false;
40898 for ( const uuid in images ) {
40900 if ( images[ uuid ] instanceof HTMLImageElement ) {
40909 if ( hasImages === false ) onLoad( object );
40917 parseShapes( json ) {
40921 if ( json !== undefined ) {
40923 for ( let i = 0, l = json.length; i < l; i ++ ) {
40925 const shape = new Shape().fromJSON( json[ i ] );
40927 shapes[ shape.uuid ] = shape;
40937 parseSkeletons( json, object ) {
40939 const skeletons = {};
40942 // generate bone lookup table
40944 object.traverse( function ( child ) {
40946 if ( child.isBone ) bones[ child.uuid ] = child;
40950 // create skeletons
40952 if ( json !== undefined ) {
40954 for ( let i = 0, l = json.length; i < l; i ++ ) {
40956 const skeleton = new Skeleton().fromJSON( json[ i ], bones );
40958 skeletons[ skeleton.uuid ] = skeleton;
40968 parseGeometries( json, shapes ) {
40970 const geometries = {};
40971 let geometryShapes;
40973 if ( json !== undefined ) {
40975 const bufferGeometryLoader = new BufferGeometryLoader();
40977 for ( let i = 0, l = json.length; i < l; i ++ ) {
40980 const data = json[ i ];
40982 switch ( data.type ) {
40984 case 'PlaneGeometry':
40985 case 'PlaneBufferGeometry':
40987 geometry = new Geometries[ data.type ](
40990 data.widthSegments,
40991 data.heightSegments
40996 case 'BoxGeometry':
40997 case 'BoxBufferGeometry':
40998 case 'CubeGeometry': // backwards compatible
41000 geometry = new Geometries[ data.type ](
41004 data.widthSegments,
41005 data.heightSegments,
41011 case 'CircleGeometry':
41012 case 'CircleBufferGeometry':
41014 geometry = new Geometries[ data.type ](
41023 case 'CylinderGeometry':
41024 case 'CylinderBufferGeometry':
41026 geometry = new Geometries[ data.type ](
41030 data.radialSegments,
41031 data.heightSegments,
41039 case 'ConeGeometry':
41040 case 'ConeBufferGeometry':
41042 geometry = new Geometries[ data.type ](
41045 data.radialSegments,
41046 data.heightSegments,
41054 case 'SphereGeometry':
41055 case 'SphereBufferGeometry':
41057 geometry = new Geometries[ data.type ](
41059 data.widthSegments,
41060 data.heightSegments,
41069 case 'DodecahedronGeometry':
41070 case 'DodecahedronBufferGeometry':
41071 case 'IcosahedronGeometry':
41072 case 'IcosahedronBufferGeometry':
41073 case 'OctahedronGeometry':
41074 case 'OctahedronBufferGeometry':
41075 case 'TetrahedronGeometry':
41076 case 'TetrahedronBufferGeometry':
41078 geometry = new Geometries[ data.type ](
41085 case 'RingGeometry':
41086 case 'RingBufferGeometry':
41088 geometry = new Geometries[ data.type ](
41091 data.thetaSegments,
41099 case 'TorusGeometry':
41100 case 'TorusBufferGeometry':
41102 geometry = new Geometries[ data.type ](
41105 data.radialSegments,
41106 data.tubularSegments,
41112 case 'TorusKnotGeometry':
41113 case 'TorusKnotBufferGeometry':
41115 geometry = new Geometries[ data.type ](
41118 data.tubularSegments,
41119 data.radialSegments,
41126 case 'TubeGeometry':
41127 case 'TubeBufferGeometry':
41129 // This only works for built-in curves (e.g. CatmullRomCurve3).
41130 // User defined curves or instances of CurvePath will not be deserialized.
41131 geometry = new Geometries[ data.type ](
41132 new Curves[ data.path.type ]().fromJSON( data.path ),
41133 data.tubularSegments,
41135 data.radialSegments,
41141 case 'LatheGeometry':
41142 case 'LatheBufferGeometry':
41144 geometry = new Geometries[ data.type ](
41153 case 'PolyhedronGeometry':
41154 case 'PolyhedronBufferGeometry':
41156 geometry = new Geometries[ data.type ](
41165 case 'ShapeGeometry':
41166 case 'ShapeBufferGeometry':
41168 geometryShapes = [];
41170 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
41172 const shape = shapes[ data.shapes[ j ] ];
41174 geometryShapes.push( shape );
41178 geometry = new Geometries[ data.type ](
41186 case 'ExtrudeGeometry':
41187 case 'ExtrudeBufferGeometry':
41189 geometryShapes = [];
41191 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
41193 const shape = shapes[ data.shapes[ j ] ];
41195 geometryShapes.push( shape );
41199 const extrudePath = data.options.extrudePath;
41201 if ( extrudePath !== undefined ) {
41203 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
41207 geometry = new Geometries[ data.type ](
41214 case 'BufferGeometry':
41215 case 'InstancedBufferGeometry':
41217 geometry = bufferGeometryLoader.parse( data );
41223 console.error( 'THREE.ObjectLoader: Loading "Geometry" is not supported anymore.' );
41229 console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
41235 geometry.uuid = data.uuid;
41237 if ( data.name !== undefined ) geometry.name = data.name;
41238 if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData;
41240 geometries[ data.uuid ] = geometry;
41250 parseMaterials( json, textures ) {
41252 const cache = {}; // MultiMaterial
41253 const materials = {};
41255 if ( json !== undefined ) {
41257 const loader = new MaterialLoader();
41258 loader.setTextures( textures );
41260 for ( let i = 0, l = json.length; i < l; i ++ ) {
41262 const data = json[ i ];
41264 if ( data.type === 'MultiMaterial' ) {
41270 for ( let j = 0; j < data.materials.length; j ++ ) {
41272 const material = data.materials[ j ];
41274 if ( cache[ material.uuid ] === undefined ) {
41276 cache[ material.uuid ] = loader.parse( material );
41280 array.push( cache[ material.uuid ] );
41284 materials[ data.uuid ] = array;
41288 if ( cache[ data.uuid ] === undefined ) {
41290 cache[ data.uuid ] = loader.parse( data );
41294 materials[ data.uuid ] = cache[ data.uuid ];
41306 parseAnimations( json ) {
41308 const animations = {};
41310 if ( json !== undefined ) {
41312 for ( let i = 0; i < json.length; i ++ ) {
41314 const data = json[ i ];
41316 const clip = AnimationClip.parse( data );
41318 animations[ clip.uuid ] = clip;
41328 parseImages( json, onLoad ) {
41330 const scope = this;
41335 function loadImage( url ) {
41337 scope.manager.itemStart( url );
41339 return loader.load( url, function () {
41341 scope.manager.itemEnd( url );
41343 }, undefined, function () {
41345 scope.manager.itemError( url );
41346 scope.manager.itemEnd( url );
41352 function deserializeImage( image ) {
41354 if ( typeof image === 'string' ) {
41358 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
41360 return loadImage( path );
41364 if ( image.data ) {
41367 data: getTypedArray( image.type, image.data ),
41368 width: image.width,
41369 height: image.height
41382 if ( json !== undefined && json.length > 0 ) {
41384 const manager = new LoadingManager( onLoad );
41386 loader = new ImageLoader( manager );
41387 loader.setCrossOrigin( this.crossOrigin );
41389 for ( let i = 0, il = json.length; i < il; i ++ ) {
41391 const image = json[ i ];
41392 const url = image.url;
41394 if ( Array.isArray( url ) ) {
41396 // load array of images e.g CubeTexture
41398 images[ image.uuid ] = [];
41400 for ( let j = 0, jl = url.length; j < jl; j ++ ) {
41402 const currentUrl = url[ j ];
41404 const deserializedImage = deserializeImage( currentUrl );
41406 if ( deserializedImage !== null ) {
41408 if ( deserializedImage instanceof HTMLImageElement ) {
41410 images[ image.uuid ].push( deserializedImage );
41414 // special case: handle array of data textures for cube textures
41416 images[ image.uuid ].push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
41426 // load single image
41428 const deserializedImage = deserializeImage( image.url );
41430 if ( deserializedImage !== null ) {
41432 images[ image.uuid ] = deserializedImage;
41446 parseTextures( json, images ) {
41448 function parseConstant( value, type ) {
41450 if ( typeof value === 'number' ) return value;
41452 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
41454 return type[ value ];
41458 const textures = {};
41460 if ( json !== undefined ) {
41462 for ( let i = 0, l = json.length; i < l; i ++ ) {
41464 const data = json[ i ];
41466 if ( data.image === undefined ) {
41468 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
41472 if ( images[ data.image ] === undefined ) {
41474 console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
41479 const image = images[ data.image ];
41481 if ( Array.isArray( image ) ) {
41483 texture = new CubeTexture( image );
41485 if ( image.length === 6 ) texture.needsUpdate = true;
41489 if ( image && image.data ) {
41491 texture = new DataTexture( image.data, image.width, image.height );
41495 texture = new Texture( image );
41499 if ( image ) texture.needsUpdate = true; // textures can have undefined image data
41503 texture.uuid = data.uuid;
41505 if ( data.name !== undefined ) texture.name = data.name;
41507 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
41509 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
41510 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
41511 if ( data.center !== undefined ) texture.center.fromArray( data.center );
41512 if ( data.rotation !== undefined ) texture.rotation = data.rotation;
41514 if ( data.wrap !== undefined ) {
41516 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
41517 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
41521 if ( data.format !== undefined ) texture.format = data.format;
41522 if ( data.type !== undefined ) texture.type = data.type;
41523 if ( data.encoding !== undefined ) texture.encoding = data.encoding;
41525 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
41526 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
41527 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
41529 if ( data.flipY !== undefined ) texture.flipY = data.flipY;
41531 if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
41532 if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
41534 textures[ data.uuid ] = texture;
41544 parseObject( data, geometries, materials, animations ) {
41548 function getGeometry( name ) {
41550 if ( geometries[ name ] === undefined ) {
41552 console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
41556 return geometries[ name ];
41560 function getMaterial( name ) {
41562 if ( name === undefined ) return undefined;
41564 if ( Array.isArray( name ) ) {
41568 for ( let i = 0, l = name.length; i < l; i ++ ) {
41570 const uuid = name[ i ];
41572 if ( materials[ uuid ] === undefined ) {
41574 console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
41578 array.push( materials[ uuid ] );
41586 if ( materials[ name ] === undefined ) {
41588 console.warn( 'THREE.ObjectLoader: Undefined material', name );
41592 return materials[ name ];
41596 let geometry, material;
41598 switch ( data.type ) {
41602 object = new Scene();
41604 if ( data.background !== undefined ) {
41606 if ( Number.isInteger( data.background ) ) {
41608 object.background = new Color( data.background );
41614 if ( data.fog !== undefined ) {
41616 if ( data.fog.type === 'Fog' ) {
41618 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
41620 } else if ( data.fog.type === 'FogExp2' ) {
41622 object.fog = new FogExp2( data.fog.color, data.fog.density );
41630 case 'PerspectiveCamera':
41632 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
41634 if ( data.focus !== undefined ) object.focus = data.focus;
41635 if ( data.zoom !== undefined ) object.zoom = data.zoom;
41636 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
41637 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
41638 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
41642 case 'OrthographicCamera':
41644 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
41646 if ( data.zoom !== undefined ) object.zoom = data.zoom;
41647 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
41651 case 'AmbientLight':
41653 object = new AmbientLight( data.color, data.intensity );
41657 case 'DirectionalLight':
41659 object = new DirectionalLight( data.color, data.intensity );
41665 object = new PointLight( data.color, data.intensity, data.distance, data.decay );
41669 case 'RectAreaLight':
41671 object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
41677 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
41681 case 'HemisphereLight':
41683 object = new HemisphereLight( data.color, data.groundColor, data.intensity );
41689 object = new LightProbe().fromJSON( data );
41693 case 'SkinnedMesh':
41695 geometry = getGeometry( data.geometry );
41696 material = getMaterial( data.material );
41698 object = new SkinnedMesh( geometry, material );
41700 if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
41701 if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
41702 if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
41708 geometry = getGeometry( data.geometry );
41709 material = getMaterial( data.material );
41711 object = new Mesh( geometry, material );
41715 case 'InstancedMesh':
41717 geometry = getGeometry( data.geometry );
41718 material = getMaterial( data.material );
41719 const count = data.count;
41720 const instanceMatrix = data.instanceMatrix;
41722 object = new InstancedMesh( geometry, material, count );
41723 object.instanceMatrix = new BufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
41729 object = new LOD();
41735 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );
41741 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
41745 case 'LineSegments':
41747 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
41754 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
41760 object = new Sprite( getMaterial( data.material ) );
41766 object = new Group();
41772 object = new Bone();
41778 object = new Object3D();
41782 object.uuid = data.uuid;
41784 if ( data.name !== undefined ) object.name = data.name;
41786 if ( data.matrix !== undefined ) {
41788 object.matrix.fromArray( data.matrix );
41790 if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
41791 if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
41795 if ( data.position !== undefined ) object.position.fromArray( data.position );
41796 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
41797 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
41798 if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
41802 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
41803 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
41805 if ( data.shadow ) {
41807 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
41808 if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
41809 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
41810 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
41811 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
41815 if ( data.visible !== undefined ) object.visible = data.visible;
41816 if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
41817 if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
41818 if ( data.userData !== undefined ) object.userData = data.userData;
41819 if ( data.layers !== undefined ) object.layers.mask = data.layers;
41821 if ( data.children !== undefined ) {
41823 const children = data.children;
41825 for ( let i = 0; i < children.length; i ++ ) {
41827 object.add( this.parseObject( children[ i ], geometries, materials, animations ) );
41833 if ( data.animations !== undefined ) {
41835 const objectAnimations = data.animations;
41837 for ( let i = 0; i < objectAnimations.length; i ++ ) {
41839 const uuid = objectAnimations[ i ];
41841 object.animations.push( animations[ uuid ] );
41847 if ( data.type === 'LOD' ) {
41849 if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
41851 const levels = data.levels;
41853 for ( let l = 0; l < levels.length; l ++ ) {
41855 const level = levels[ l ];
41856 const child = object.getObjectByProperty( 'uuid', level.object );
41858 if ( child !== undefined ) {
41860 object.addLevel( child, level.distance );
41872 bindSkeletons( object, skeletons ) {
41874 if ( Object.keys( skeletons ).length === 0 ) return;
41876 object.traverse( function ( child ) {
41878 if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
41880 const skeleton = skeletons[ child.skeleton ];
41882 if ( skeleton === undefined ) {
41884 console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
41888 child.bind( skeleton, child.bindMatrix );
41900 setTexturePath( value ) {
41902 console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' );
41903 return this.setResourcePath( value );
41909 const TEXTURE_MAPPING = {
41910 UVMapping: UVMapping,
41911 CubeReflectionMapping: CubeReflectionMapping,
41912 CubeRefractionMapping: CubeRefractionMapping,
41913 EquirectangularReflectionMapping: EquirectangularReflectionMapping,
41914 EquirectangularRefractionMapping: EquirectangularRefractionMapping,
41915 CubeUVReflectionMapping: CubeUVReflectionMapping,
41916 CubeUVRefractionMapping: CubeUVRefractionMapping
41919 const TEXTURE_WRAPPING = {
41920 RepeatWrapping: RepeatWrapping,
41921 ClampToEdgeWrapping: ClampToEdgeWrapping,
41922 MirroredRepeatWrapping: MirroredRepeatWrapping
41925 const TEXTURE_FILTER = {
41926 NearestFilter: NearestFilter,
41927 NearestMipmapNearestFilter: NearestMipmapNearestFilter,
41928 NearestMipmapLinearFilter: NearestMipmapLinearFilter,
41929 LinearFilter: LinearFilter,
41930 LinearMipmapNearestFilter: LinearMipmapNearestFilter,
41931 LinearMipmapLinearFilter: LinearMipmapLinearFilter
41934 function ImageBitmapLoader( manager ) {
41936 if ( typeof createImageBitmap === 'undefined' ) {
41938 console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
41942 if ( typeof fetch === 'undefined' ) {
41944 console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
41948 Loader.call( this, manager );
41950 this.options = { premultiplyAlpha: 'none' };
41954 ImageBitmapLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
41956 constructor: ImageBitmapLoader,
41958 isImageBitmapLoader: true,
41960 setOptions: function setOptions( options ) {
41962 this.options = options;
41968 load: function ( url, onLoad, onProgress, onError ) {
41970 if ( url === undefined ) url = '';
41972 if ( this.path !== undefined ) url = this.path + url;
41974 url = this.manager.resolveURL( url );
41976 const scope = this;
41978 const cached = Cache.get( url );
41980 if ( cached !== undefined ) {
41982 scope.manager.itemStart( url );
41984 setTimeout( function () {
41986 if ( onLoad ) onLoad( cached );
41988 scope.manager.itemEnd( url );
41996 const fetchOptions = {};
41997 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
41999 fetch( url, fetchOptions ).then( function ( res ) {
42003 } ).then( function ( blob ) {
42005 return createImageBitmap( blob, scope.options );
42007 } ).then( function ( imageBitmap ) {
42009 Cache.add( url, imageBitmap );
42011 if ( onLoad ) onLoad( imageBitmap );
42013 scope.manager.itemEnd( url );
42015 } ).catch( function ( e ) {
42017 if ( onError ) onError( e );
42019 scope.manager.itemError( url );
42020 scope.manager.itemEnd( url );
42024 scope.manager.itemStart( url );
42030 function ShapePath() {
42032 this.type = 'ShapePath';
42034 this.color = new Color();
42036 this.subPaths = [];
42037 this.currentPath = null;
42041 Object.assign( ShapePath.prototype, {
42043 moveTo: function ( x, y ) {
42045 this.currentPath = new Path();
42046 this.subPaths.push( this.currentPath );
42047 this.currentPath.moveTo( x, y );
42053 lineTo: function ( x, y ) {
42055 this.currentPath.lineTo( x, y );
42061 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
42063 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
42069 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
42071 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
42077 splineThru: function ( pts ) {
42079 this.currentPath.splineThru( pts );
42085 toShapes: function ( isCCW, noHoles ) {
42087 function toShapesNoHoles( inSubpaths ) {
42091 for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
42093 const tmpPath = inSubpaths[ i ];
42095 const tmpShape = new Shape();
42096 tmpShape.curves = tmpPath.curves;
42098 shapes.push( tmpShape );
42106 function isPointInsidePolygon( inPt, inPolygon ) {
42108 const polyLen = inPolygon.length;
42110 // inPt on polygon contour => immediate success or
42111 // toggling of inside/outside at every single! intersection point of an edge
42112 // with the horizontal line through inPt, left of inPt
42113 // not counting lowerY endpoints of edges and whole edges on that line
42114 let inside = false;
42115 for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
42117 let edgeLowPt = inPolygon[ p ];
42118 let edgeHighPt = inPolygon[ q ];
42120 let edgeDx = edgeHighPt.x - edgeLowPt.x;
42121 let edgeDy = edgeHighPt.y - edgeLowPt.y;
42123 if ( Math.abs( edgeDy ) > Number.EPSILON ) {
42126 if ( edgeDy < 0 ) {
42128 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
42129 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
42133 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
42135 if ( inPt.y === edgeLowPt.y ) {
42137 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
42138 // continue; // no intersection or edgeLowPt => doesn't count !!!
42142 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
42143 if ( perpEdge === 0 ) return true; // inPt is on contour ?
42144 if ( perpEdge < 0 ) continue;
42145 inside = ! inside; // true intersection left of inPt
42151 // parallel or collinear
42152 if ( inPt.y !== edgeLowPt.y ) continue; // parallel
42153 // edge lies on the same horizontal line as inPt
42154 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
42155 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
42166 const isClockWise = ShapeUtils.isClockWise;
42168 const subPaths = this.subPaths;
42169 if ( subPaths.length === 0 ) return [];
42171 if ( noHoles === true ) return toShapesNoHoles( subPaths );
42174 let solid, tmpPath, tmpShape;
42177 if ( subPaths.length === 1 ) {
42179 tmpPath = subPaths[ 0 ];
42180 tmpShape = new Shape();
42181 tmpShape.curves = tmpPath.curves;
42182 shapes.push( tmpShape );
42187 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
42188 holesFirst = isCCW ? ! holesFirst : holesFirst;
42190 // console.log("Holes first", holesFirst);
42192 const betterShapeHoles = [];
42193 const newShapes = [];
42194 let newShapeHoles = [];
42198 newShapes[ mainIdx ] = undefined;
42199 newShapeHoles[ mainIdx ] = [];
42201 for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
42203 tmpPath = subPaths[ i ];
42204 tmpPoints = tmpPath.getPoints();
42205 solid = isClockWise( tmpPoints );
42206 solid = isCCW ? ! solid : solid;
42210 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
42212 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
42213 newShapes[ mainIdx ].s.curves = tmpPath.curves;
42215 if ( holesFirst ) mainIdx ++;
42216 newShapeHoles[ mainIdx ] = [];
42218 //console.log('cw', i);
42222 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
42224 //console.log('ccw', i);
42230 // only Holes? -> probably all Shapes with wrong orientation
42231 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
42234 if ( newShapes.length > 1 ) {
42236 let ambiguous = false;
42237 const toChange = [];
42239 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
42241 betterShapeHoles[ sIdx ] = [];
42245 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
42247 const sho = newShapeHoles[ sIdx ];
42249 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
42251 const ho = sho[ hIdx ];
42252 let hole_unassigned = true;
42254 for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
42256 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
42258 if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
42259 if ( hole_unassigned ) {
42261 hole_unassigned = false;
42262 betterShapeHoles[ s2Idx ].push( ho );
42274 if ( hole_unassigned ) {
42276 betterShapeHoles[ sIdx ].push( ho );
42283 // console.log("ambiguous: ", ambiguous);
42285 if ( toChange.length > 0 ) {
42287 // console.log("to change: ", toChange);
42288 if ( ! ambiguous ) newShapeHoles = betterShapeHoles;
42296 for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
42298 tmpShape = newShapes[ i ].s;
42299 shapes.push( tmpShape );
42300 tmpHoles = newShapeHoles[ i ];
42302 for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
42304 tmpShape.holes.push( tmpHoles[ j ].h );
42310 //console.log("shape", shapes);
42318 function Font( data ) {
42320 this.type = 'Font';
42326 Object.assign( Font.prototype, {
42330 generateShapes: function ( text, size = 100 ) {
42333 const paths = createPaths( text, size, this.data );
42335 for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
42337 Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
42347 function createPaths( text, size, data ) {
42349 const chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988
42350 const scale = size / data.resolution;
42351 const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
42355 let offsetX = 0, offsetY = 0;
42357 for ( let i = 0; i < chars.length; i ++ ) {
42359 const char = chars[ i ];
42361 if ( char === '\n' ) {
42364 offsetY -= line_height;
42368 const ret = createPath( char, scale, offsetX, offsetY, data );
42369 offsetX += ret.offsetX;
42370 paths.push( ret.path );
42380 function createPath( char, scale, offsetX, offsetY, data ) {
42382 const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
42386 console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
42392 const path = new ShapePath();
42394 let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
42398 const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
42400 for ( let i = 0, l = outline.length; i < l; ) {
42402 const action = outline[ i ++ ];
42404 switch ( action ) {
42406 case 'm': // moveTo
42408 x = outline[ i ++ ] * scale + offsetX;
42409 y = outline[ i ++ ] * scale + offsetY;
42411 path.moveTo( x, y );
42415 case 'l': // lineTo
42417 x = outline[ i ++ ] * scale + offsetX;
42418 y = outline[ i ++ ] * scale + offsetY;
42420 path.lineTo( x, y );
42424 case 'q': // quadraticCurveTo
42426 cpx = outline[ i ++ ] * scale + offsetX;
42427 cpy = outline[ i ++ ] * scale + offsetY;
42428 cpx1 = outline[ i ++ ] * scale + offsetX;
42429 cpy1 = outline[ i ++ ] * scale + offsetY;
42431 path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
42435 case 'b': // bezierCurveTo
42437 cpx = outline[ i ++ ] * scale + offsetX;
42438 cpy = outline[ i ++ ] * scale + offsetY;
42439 cpx1 = outline[ i ++ ] * scale + offsetX;
42440 cpy1 = outline[ i ++ ] * scale + offsetY;
42441 cpx2 = outline[ i ++ ] * scale + offsetX;
42442 cpy2 = outline[ i ++ ] * scale + offsetY;
42444 path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
42454 return { offsetX: glyph.ha * scale, path: path };
42458 function FontLoader( manager ) {
42460 Loader.call( this, manager );
42464 FontLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
42466 constructor: FontLoader,
42468 load: function ( url, onLoad, onProgress, onError ) {
42470 const scope = this;
42472 const loader = new FileLoader( this.manager );
42473 loader.setPath( this.path );
42474 loader.setRequestHeader( this.requestHeader );
42475 loader.setWithCredentials( scope.withCredentials );
42476 loader.load( url, function ( text ) {
42482 json = JSON.parse( text );
42486 console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
42487 json = JSON.parse( text.substring( 65, text.length - 2 ) );
42491 const font = scope.parse( json );
42493 if ( onLoad ) onLoad( font );
42495 }, onProgress, onError );
42499 parse: function ( json ) {
42501 return new Font( json );
42509 const AudioContext = {
42511 getContext: function () {
42513 if ( _context === undefined ) {
42515 _context = new ( window.AudioContext || window.webkitAudioContext )();
42523 setContext: function ( value ) {
42531 function AudioLoader( manager ) {
42533 Loader.call( this, manager );
42537 AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
42539 constructor: AudioLoader,
42541 load: function ( url, onLoad, onProgress, onError ) {
42543 const scope = this;
42545 const loader = new FileLoader( scope.manager );
42546 loader.setResponseType( 'arraybuffer' );
42547 loader.setPath( scope.path );
42548 loader.setRequestHeader( scope.requestHeader );
42549 loader.setWithCredentials( scope.withCredentials );
42550 loader.load( url, function ( buffer ) {
42554 // Create a copy of the buffer. The `decodeAudioData` method
42555 // detaches the buffer when complete, preventing reuse.
42556 const bufferCopy = buffer.slice( 0 );
42558 const context = AudioContext.getContext();
42559 context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
42561 onLoad( audioBuffer );
42573 console.error( e );
42577 scope.manager.itemError( url );
42581 }, onProgress, onError );
42587 function HemisphereLightProbe( skyColor, groundColor, intensity ) {
42589 LightProbe.call( this, undefined, intensity );
42591 const color1 = new Color().set( skyColor );
42592 const color2 = new Color().set( groundColor );
42594 const sky = new Vector3( color1.r, color1.g, color1.b );
42595 const ground = new Vector3( color2.r, color2.g, color2.b );
42597 // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI );
42598 const c0 = Math.sqrt( Math.PI );
42599 const c1 = c0 * Math.sqrt( 0.75 );
42601 this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 );
42602 this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 );
42606 HemisphereLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
42608 constructor: HemisphereLightProbe,
42610 isHemisphereLightProbe: true,
42612 copy: function ( source ) { // modifying colors not currently supported
42614 LightProbe.prototype.copy.call( this, source );
42620 toJSON: function ( meta ) {
42622 const data = LightProbe.prototype.toJSON.call( this, meta );
42624 // data.sh = this.sh.toArray(); // todo
42632 function AmbientLightProbe( color, intensity ) {
42634 LightProbe.call( this, undefined, intensity );
42636 const color1 = new Color().set( color );
42638 // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI );
42639 this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) );
42643 AmbientLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
42645 constructor: AmbientLightProbe,
42647 isAmbientLightProbe: true,
42649 copy: function ( source ) { // modifying color not currently supported
42651 LightProbe.prototype.copy.call( this, source );
42657 toJSON: function ( meta ) {
42659 const data = LightProbe.prototype.toJSON.call( this, meta );
42661 // data.sh = this.sh.toArray(); // todo
42669 const _eyeRight = new Matrix4();
42670 const _eyeLeft = new Matrix4();
42672 function StereoCamera() {
42674 this.type = 'StereoCamera';
42678 this.eyeSep = 0.064;
42680 this.cameraL = new PerspectiveCamera();
42681 this.cameraL.layers.enable( 1 );
42682 this.cameraL.matrixAutoUpdate = false;
42684 this.cameraR = new PerspectiveCamera();
42685 this.cameraR.layers.enable( 2 );
42686 this.cameraR.matrixAutoUpdate = false;
42700 Object.assign( StereoCamera.prototype, {
42702 update: function ( camera ) {
42704 const cache = this._cache;
42706 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
42707 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
42708 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
42710 if ( needsUpdate ) {
42712 cache.focus = camera.focus;
42713 cache.fov = camera.fov;
42714 cache.aspect = camera.aspect * this.aspect;
42715 cache.near = camera.near;
42716 cache.far = camera.far;
42717 cache.zoom = camera.zoom;
42718 cache.eyeSep = this.eyeSep;
42720 // Off-axis stereoscopic effect based on
42721 // http://paulbourke.net/stereographics/stereorender/
42723 const projectionMatrix = camera.projectionMatrix.clone();
42724 const eyeSepHalf = cache.eyeSep / 2;
42725 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
42726 const ymax = ( cache.near * Math.tan( MathUtils.DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
42729 // translate xOffset
42731 _eyeLeft.elements[ 12 ] = - eyeSepHalf;
42732 _eyeRight.elements[ 12 ] = eyeSepHalf;
42736 xmin = - ymax * cache.aspect + eyeSepOnProjection;
42737 xmax = ymax * cache.aspect + eyeSepOnProjection;
42739 projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
42740 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
42742 this.cameraL.projectionMatrix.copy( projectionMatrix );
42746 xmin = - ymax * cache.aspect - eyeSepOnProjection;
42747 xmax = ymax * cache.aspect - eyeSepOnProjection;
42749 projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
42750 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
42752 this.cameraR.projectionMatrix.copy( projectionMatrix );
42756 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
42757 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
42765 constructor( autoStart ) {
42767 this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
42769 this.startTime = 0;
42771 this.elapsedTime = 0;
42773 this.running = false;
42779 this.startTime = now();
42781 this.oldTime = this.startTime;
42782 this.elapsedTime = 0;
42783 this.running = true;
42789 this.getElapsedTime();
42790 this.running = false;
42791 this.autoStart = false;
42798 return this.elapsedTime;
42806 if ( this.autoStart && ! this.running ) {
42813 if ( this.running ) {
42815 const newTime = now();
42817 diff = ( newTime - this.oldTime ) / 1000;
42818 this.oldTime = newTime;
42820 this.elapsedTime += diff;
42832 return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
42836 const _position$2 = /*@__PURE__*/ new Vector3();
42837 const _quaternion$3 = /*@__PURE__*/ new Quaternion();
42838 const _scale$1 = /*@__PURE__*/ new Vector3();
42839 const _orientation = /*@__PURE__*/ new Vector3();
42841 class AudioListener extends Object3D {
42847 this.type = 'AudioListener';
42849 this.context = AudioContext.getContext();
42851 this.gain = this.context.createGain();
42852 this.gain.connect( this.context.destination );
42854 this.filter = null;
42856 this.timeDelta = 0;
42860 this._clock = new Clock();
42872 if ( this.filter !== null ) {
42874 this.gain.disconnect( this.filter );
42875 this.filter.disconnect( this.context.destination );
42876 this.gain.connect( this.context.destination );
42877 this.filter = null;
42887 return this.filter;
42891 setFilter( value ) {
42893 if ( this.filter !== null ) {
42895 this.gain.disconnect( this.filter );
42896 this.filter.disconnect( this.context.destination );
42900 this.gain.disconnect( this.context.destination );
42904 this.filter = value;
42905 this.gain.connect( this.filter );
42906 this.filter.connect( this.context.destination );
42912 getMasterVolume() {
42914 return this.gain.gain.value;
42918 setMasterVolume( value ) {
42920 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
42926 updateMatrixWorld( force ) {
42928 super.updateMatrixWorld( force );
42930 const listener = this.context.listener;
42931 const up = this.up;
42933 this.timeDelta = this._clock.getDelta();
42935 this.matrixWorld.decompose( _position$2, _quaternion$3, _scale$1 );
42937 _orientation.set( 0, 0, - 1 ).applyQuaternion( _quaternion$3 );
42939 if ( listener.positionX ) {
42941 // code path for Chrome (see #14393)
42943 const endTime = this.context.currentTime + this.timeDelta;
42945 listener.positionX.linearRampToValueAtTime( _position$2.x, endTime );
42946 listener.positionY.linearRampToValueAtTime( _position$2.y, endTime );
42947 listener.positionZ.linearRampToValueAtTime( _position$2.z, endTime );
42948 listener.forwardX.linearRampToValueAtTime( _orientation.x, endTime );
42949 listener.forwardY.linearRampToValueAtTime( _orientation.y, endTime );
42950 listener.forwardZ.linearRampToValueAtTime( _orientation.z, endTime );
42951 listener.upX.linearRampToValueAtTime( up.x, endTime );
42952 listener.upY.linearRampToValueAtTime( up.y, endTime );
42953 listener.upZ.linearRampToValueAtTime( up.z, endTime );
42957 listener.setPosition( _position$2.x, _position$2.y, _position$2.z );
42958 listener.setOrientation( _orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z );
42966 class Audio extends Object3D {
42968 constructor( listener ) {
42972 this.type = 'Audio';
42974 this.listener = listener;
42975 this.context = listener.context;
42977 this.gain = this.context.createGain();
42978 this.gain.connect( listener.getInput() );
42980 this.autoplay = false;
42982 this.buffer = null;
42985 this.loopStart = 0;
42988 this.duration = undefined;
42989 this.playbackRate = 1;
42990 this.isPlaying = false;
42991 this.hasPlaybackControl = true;
42992 this.source = null;
42993 this.sourceType = 'empty';
42995 this._startedAt = 0;
42996 this._progress = 0;
42997 this._connected = false;
43009 setNodeSource( audioNode ) {
43011 this.hasPlaybackControl = false;
43012 this.sourceType = 'audioNode';
43013 this.source = audioNode;
43020 setMediaElementSource( mediaElement ) {
43022 this.hasPlaybackControl = false;
43023 this.sourceType = 'mediaNode';
43024 this.source = this.context.createMediaElementSource( mediaElement );
43031 setMediaStreamSource( mediaStream ) {
43033 this.hasPlaybackControl = false;
43034 this.sourceType = 'mediaStreamNode';
43035 this.source = this.context.createMediaStreamSource( mediaStream );
43042 setBuffer( audioBuffer ) {
43044 this.buffer = audioBuffer;
43045 this.sourceType = 'buffer';
43047 if ( this.autoplay ) this.play();
43053 play( delay = 0 ) {
43055 if ( this.isPlaying === true ) {
43057 console.warn( 'THREE.Audio: Audio is already playing.' );
43062 if ( this.hasPlaybackControl === false ) {
43064 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43069 this._startedAt = this.context.currentTime + delay;
43071 const source = this.context.createBufferSource();
43072 source.buffer = this.buffer;
43073 source.loop = this.loop;
43074 source.loopStart = this.loopStart;
43075 source.loopEnd = this.loopEnd;
43076 source.onended = this.onEnded.bind( this );
43077 source.start( this._startedAt, this._progress + this.offset, this.duration );
43079 this.isPlaying = true;
43081 this.source = source;
43083 this.setDetune( this.detune );
43084 this.setPlaybackRate( this.playbackRate );
43086 return this.connect();
43092 if ( this.hasPlaybackControl === false ) {
43094 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43099 if ( this.isPlaying === true ) {
43101 // update current progress
43103 this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
43105 if ( this.loop === true ) {
43107 // ensure _progress does not exceed duration with looped audios
43109 this._progress = this._progress % ( this.duration || this.buffer.duration );
43113 this.source.stop();
43114 this.source.onended = null;
43116 this.isPlaying = false;
43126 if ( this.hasPlaybackControl === false ) {
43128 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43133 this._progress = 0;
43135 this.source.stop();
43136 this.source.onended = null;
43137 this.isPlaying = false;
43145 if ( this.filters.length > 0 ) {
43147 this.source.connect( this.filters[ 0 ] );
43149 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
43151 this.filters[ i - 1 ].connect( this.filters[ i ] );
43155 this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
43159 this.source.connect( this.getOutput() );
43163 this._connected = true;
43171 if ( this.filters.length > 0 ) {
43173 this.source.disconnect( this.filters[ 0 ] );
43175 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
43177 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
43181 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
43185 this.source.disconnect( this.getOutput() );
43189 this._connected = false;
43197 return this.filters;
43201 setFilters( value ) {
43203 if ( ! value ) value = [];
43205 if ( this._connected === true ) {
43208 this.filters = value.slice();
43213 this.filters = value.slice();
43221 setDetune( value ) {
43223 this.detune = value;
43225 if ( this.source.detune === undefined ) return; // only set detune when available
43227 if ( this.isPlaying === true ) {
43229 this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
43239 return this.detune;
43245 return this.getFilters()[ 0 ];
43249 setFilter( filter ) {
43251 return this.setFilters( filter ? [ filter ] : [] );
43255 setPlaybackRate( value ) {
43257 if ( this.hasPlaybackControl === false ) {
43259 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43264 this.playbackRate = value;
43266 if ( this.isPlaying === true ) {
43268 this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
43276 getPlaybackRate() {
43278 return this.playbackRate;
43284 this.isPlaying = false;
43290 if ( this.hasPlaybackControl === false ) {
43292 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43303 if ( this.hasPlaybackControl === false ) {
43305 console.warn( 'THREE.Audio: this Audio has no playback control.' );
43312 if ( this.isPlaying === true ) {
43314 this.source.loop = this.loop;
43322 setLoopStart( value ) {
43324 this.loopStart = value;
43330 setLoopEnd( value ) {
43332 this.loopEnd = value;
43340 return this.gain.gain.value;
43344 setVolume( value ) {
43346 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
43354 const _position$3 = /*@__PURE__*/ new Vector3();
43355 const _quaternion$4 = /*@__PURE__*/ new Quaternion();
43356 const _scale$2 = /*@__PURE__*/ new Vector3();
43357 const _orientation$1 = /*@__PURE__*/ new Vector3();
43359 class PositionalAudio extends Audio {
43361 constructor( listener ) {
43365 this.panner = this.context.createPanner();
43366 this.panner.panningModel = 'HRTF';
43367 this.panner.connect( this.gain );
43373 return this.panner;
43379 return this.panner.refDistance;
43383 setRefDistance( value ) {
43385 this.panner.refDistance = value;
43391 getRolloffFactor() {
43393 return this.panner.rolloffFactor;
43397 setRolloffFactor( value ) {
43399 this.panner.rolloffFactor = value;
43405 getDistanceModel() {
43407 return this.panner.distanceModel;
43411 setDistanceModel( value ) {
43413 this.panner.distanceModel = value;
43421 return this.panner.maxDistance;
43425 setMaxDistance( value ) {
43427 this.panner.maxDistance = value;
43433 setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
43435 this.panner.coneInnerAngle = coneInnerAngle;
43436 this.panner.coneOuterAngle = coneOuterAngle;
43437 this.panner.coneOuterGain = coneOuterGain;
43443 updateMatrixWorld( force ) {
43445 super.updateMatrixWorld( force );
43447 if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
43449 this.matrixWorld.decompose( _position$3, _quaternion$4, _scale$2 );
43451 _orientation$1.set( 0, 0, 1 ).applyQuaternion( _quaternion$4 );
43453 const panner = this.panner;
43455 if ( panner.positionX ) {
43457 // code path for Chrome and Firefox (see #14393)
43459 const endTime = this.context.currentTime + this.listener.timeDelta;
43461 panner.positionX.linearRampToValueAtTime( _position$3.x, endTime );
43462 panner.positionY.linearRampToValueAtTime( _position$3.y, endTime );
43463 panner.positionZ.linearRampToValueAtTime( _position$3.z, endTime );
43464 panner.orientationX.linearRampToValueAtTime( _orientation$1.x, endTime );
43465 panner.orientationY.linearRampToValueAtTime( _orientation$1.y, endTime );
43466 panner.orientationZ.linearRampToValueAtTime( _orientation$1.z, endTime );
43470 panner.setPosition( _position$3.x, _position$3.y, _position$3.z );
43471 panner.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z );
43479 class AudioAnalyser {
43481 constructor( audio, fftSize = 2048 ) {
43483 this.analyser = audio.context.createAnalyser();
43484 this.analyser.fftSize = fftSize;
43486 this.data = new Uint8Array( this.analyser.frequencyBinCount );
43488 audio.getOutput().connect( this.analyser );
43493 getFrequencyData() {
43495 this.analyser.getByteFrequencyData( this.data );
43501 getAverageFrequency() {
43504 const data = this.getFrequencyData();
43506 for ( let i = 0; i < data.length; i ++ ) {
43508 value += data[ i ];
43512 return value / data.length;
43518 function PropertyMixer( binding, typeName, valueSize ) {
43520 this.binding = binding;
43521 this.valueSize = valueSize;
43524 mixFunctionAdditive,
43527 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
43529 // interpolators can use .buffer as their .result
43530 // the data then goes to 'incoming'
43532 // 'accu0' and 'accu1' are used frame-interleaved for
43533 // the cumulative result and are compared to detect
43536 // 'orig' stores the original state of the property
43538 // 'add' is used for additive cumulative results
43540 // 'work' is optional and is only present for quaternion types. It is used
43541 // to store intermediate quaternion multiplication results
43543 switch ( typeName ) {
43546 mixFunction = this._slerp;
43547 mixFunctionAdditive = this._slerpAdditive;
43548 setIdentity = this._setAdditiveIdentityQuaternion;
43550 this.buffer = new Float64Array( valueSize * 6 );
43551 this._workIndex = 5;
43556 mixFunction = this._select;
43558 // Use the regular mix function and for additive on these types,
43559 // additive is not relevant for non-numeric types
43560 mixFunctionAdditive = this._select;
43562 setIdentity = this._setAdditiveIdentityOther;
43564 this.buffer = new Array( valueSize * 5 );
43568 mixFunction = this._lerp;
43569 mixFunctionAdditive = this._lerpAdditive;
43570 setIdentity = this._setAdditiveIdentityNumeric;
43572 this.buffer = new Float64Array( valueSize * 5 );
43576 this._mixBufferRegion = mixFunction;
43577 this._mixBufferRegionAdditive = mixFunctionAdditive;
43578 this._setIdentity = setIdentity;
43579 this._origIndex = 3;
43580 this._addIndex = 4;
43582 this.cumulativeWeight = 0;
43583 this.cumulativeWeightAdditive = 0;
43586 this.referenceCount = 0;
43590 Object.assign( PropertyMixer.prototype, {
43592 // accumulate data in the 'incoming' region into 'accu<i>'
43593 accumulate: function ( accuIndex, weight ) {
43595 // note: happily accumulating nothing when weight = 0, the caller knows
43596 // the weight and shouldn't have made the call in the first place
43598 const buffer = this.buffer,
43599 stride = this.valueSize,
43600 offset = accuIndex * stride + stride;
43602 let currentWeight = this.cumulativeWeight;
43604 if ( currentWeight === 0 ) {
43606 // accuN := incoming * weight
43608 for ( let i = 0; i !== stride; ++ i ) {
43610 buffer[ offset + i ] = buffer[ i ];
43614 currentWeight = weight;
43618 // accuN := accuN + incoming * weight
43620 currentWeight += weight;
43621 const mix = weight / currentWeight;
43622 this._mixBufferRegion( buffer, offset, 0, mix, stride );
43626 this.cumulativeWeight = currentWeight;
43630 // accumulate data in the 'incoming' region into 'add'
43631 accumulateAdditive: function ( weight ) {
43633 const buffer = this.buffer,
43634 stride = this.valueSize,
43635 offset = stride * this._addIndex;
43637 if ( this.cumulativeWeightAdditive === 0 ) {
43641 this._setIdentity();
43645 // add := add + incoming * weight
43647 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
43648 this.cumulativeWeightAdditive += weight;
43652 // apply the state of 'accu<i>' to the binding when accus differ
43653 apply: function ( accuIndex ) {
43655 const stride = this.valueSize,
43656 buffer = this.buffer,
43657 offset = accuIndex * stride + stride,
43659 weight = this.cumulativeWeight,
43660 weightAdditive = this.cumulativeWeightAdditive,
43662 binding = this.binding;
43664 this.cumulativeWeight = 0;
43665 this.cumulativeWeightAdditive = 0;
43667 if ( weight < 1 ) {
43669 // accuN := accuN + original * ( 1 - cumulativeWeight )
43671 const originalValueOffset = stride * this._origIndex;
43673 this._mixBufferRegion(
43674 buffer, offset, originalValueOffset, 1 - weight, stride );
43678 if ( weightAdditive > 0 ) {
43680 // accuN := accuN + additive accuN
43682 this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
43686 for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
43688 if ( buffer[ i ] !== buffer[ i + stride ] ) {
43690 // value has changed -> update scene graph
43692 binding.setValue( buffer, offset );
43701 // remember the state of the bound property and copy it to both accus
43702 saveOriginalState: function () {
43704 const binding = this.binding;
43706 const buffer = this.buffer,
43707 stride = this.valueSize,
43709 originalValueOffset = stride * this._origIndex;
43711 binding.getValue( buffer, originalValueOffset );
43713 // accu[0..1] := orig -- initially detect changes against the original
43714 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
43716 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
43720 // Add to identity for additive
43721 this._setIdentity();
43723 this.cumulativeWeight = 0;
43724 this.cumulativeWeightAdditive = 0;
43728 // apply the state previously taken via 'saveOriginalState' to the binding
43729 restoreOriginalState: function () {
43731 const originalValueOffset = this.valueSize * 3;
43732 this.binding.setValue( this.buffer, originalValueOffset );
43736 _setAdditiveIdentityNumeric: function () {
43738 const startIndex = this._addIndex * this.valueSize;
43739 const endIndex = startIndex + this.valueSize;
43741 for ( let i = startIndex; i < endIndex; i ++ ) {
43743 this.buffer[ i ] = 0;
43749 _setAdditiveIdentityQuaternion: function () {
43751 this._setAdditiveIdentityNumeric();
43752 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
43756 _setAdditiveIdentityOther: function () {
43758 const startIndex = this._origIndex * this.valueSize;
43759 const targetIndex = this._addIndex * this.valueSize;
43761 for ( let i = 0; i < this.valueSize; i ++ ) {
43763 this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
43772 _select: function ( buffer, dstOffset, srcOffset, t, stride ) {
43776 for ( let i = 0; i !== stride; ++ i ) {
43778 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
43786 _slerp: function ( buffer, dstOffset, srcOffset, t ) {
43788 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
43792 _slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
43794 const workOffset = this._workIndex * stride;
43796 // Store result in intermediate buffer offset
43797 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
43799 // Slerp to the intermediate result
43800 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
43804 _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
43808 for ( let i = 0; i !== stride; ++ i ) {
43810 const j = dstOffset + i;
43812 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
43818 _lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
43820 for ( let i = 0; i !== stride; ++ i ) {
43822 const j = dstOffset + i;
43824 buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
43832 // Characters [].:/ are reserved for track binding syntax.
43833 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
43834 const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
43836 // Attempts to allow node names from any language. ES5's `\w` regexp matches
43837 // only latin characters, and the unicode \p{L} is not yet supported. So
43838 // instead, we exclude reserved characters and match everything else.
43839 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
43840 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
43842 // Parent directories, delimited by '/' or ':'. Currently unused, but must
43843 // be matched to parse the rest of the track name.
43844 const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
43846 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
43847 const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
43849 // Object on target node, and accessor. May not contain reserved
43850 // characters. Accessor may contain any character except closing bracket.
43851 const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
43853 // Property and accessor. May not contain reserved characters. Accessor may
43854 // contain any non-bracket characters.
43855 const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
43857 const _trackRe = new RegExp( ''
43866 const _supportedObjectNames = [ 'material', 'materials', 'bones' ];
43868 function Composite( targetGroup, path, optionalParsedPath ) {
43870 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
43872 this._targetGroup = targetGroup;
43873 this._bindings = targetGroup.subscribe_( path, parsedPath );
43877 Object.assign( Composite.prototype, {
43879 getValue: function ( array, offset ) {
43881 this.bind(); // bind all binding
43883 const firstValidIndex = this._targetGroup.nCachedObjects_,
43884 binding = this._bindings[ firstValidIndex ];
43886 // and only call .getValue on the first
43887 if ( binding !== undefined ) binding.getValue( array, offset );
43891 setValue: function ( array, offset ) {
43893 const bindings = this._bindings;
43895 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
43897 bindings[ i ].setValue( array, offset );
43903 bind: function () {
43905 const bindings = this._bindings;
43907 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
43909 bindings[ i ].bind();
43915 unbind: function () {
43917 const bindings = this._bindings;
43919 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
43921 bindings[ i ].unbind();
43930 function PropertyBinding( rootNode, path, parsedPath ) {
43933 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
43935 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
43937 this.rootNode = rootNode;
43941 Object.assign( PropertyBinding, {
43943 Composite: Composite,
43945 create: function ( root, path, parsedPath ) {
43947 if ( ! ( root && root.isAnimationObjectGroup ) ) {
43949 return new PropertyBinding( root, path, parsedPath );
43953 return new PropertyBinding.Composite( root, path, parsedPath );
43960 * Replaces spaces with underscores and removes unsupported characters from
43961 * node names, to ensure compatibility with parseTrackName().
43963 * @param {string} name Node name to be sanitized.
43966 sanitizeNodeName: function ( name ) {
43968 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
43972 parseTrackName: function ( trackName ) {
43974 const matches = _trackRe.exec( trackName );
43978 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
43983 // directoryName: matches[ 1 ], // (tschw) currently unused
43984 nodeName: matches[ 2 ],
43985 objectName: matches[ 3 ],
43986 objectIndex: matches[ 4 ],
43987 propertyName: matches[ 5 ], // required
43988 propertyIndex: matches[ 6 ]
43991 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
43993 if ( lastDot !== undefined && lastDot !== - 1 ) {
43995 const objectName = results.nodeName.substring( lastDot + 1 );
43997 // Object names must be checked against an allowlist. Otherwise, there
43998 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
43999 // 'bar' could be the objectName, or part of a nodeName (which can
44000 // include '.' characters).
44001 if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
44003 results.nodeName = results.nodeName.substring( 0, lastDot );
44004 results.objectName = objectName;
44010 if ( results.propertyName === null || results.propertyName.length === 0 ) {
44012 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
44020 findNode: function ( root, nodeName ) {
44022 if ( ! nodeName || nodeName === "" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
44028 // search into skeleton bones.
44029 if ( root.skeleton ) {
44031 const bone = root.skeleton.getBoneByName( nodeName );
44033 if ( bone !== undefined ) {
44041 // search into node subtree.
44042 if ( root.children ) {
44044 const searchNodeSubtree = function ( children ) {
44046 for ( let i = 0; i < children.length; i ++ ) {
44048 const childNode = children[ i ];
44050 if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
44056 const result = searchNodeSubtree( childNode.children );
44058 if ( result ) return result;
44066 const subTreeNode = searchNodeSubtree( root.children );
44068 if ( subTreeNode ) {
44070 return subTreeNode;
44082 Object.assign( PropertyBinding.prototype, { // prototype, continued
44084 // these are used to "bind" a nonexistent property
44085 _getValue_unavailable: function () {},
44086 _setValue_unavailable: function () {},
44098 MatrixWorldNeedsUpdate: 2
44101 GetterByBindingType: [
44103 function getValue_direct( buffer, offset ) {
44105 buffer[ offset ] = this.node[ this.propertyName ];
44109 function getValue_array( buffer, offset ) {
44111 const source = this.resolvedProperty;
44113 for ( let i = 0, n = source.length; i !== n; ++ i ) {
44115 buffer[ offset ++ ] = source[ i ];
44121 function getValue_arrayElement( buffer, offset ) {
44123 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
44127 function getValue_toArray( buffer, offset ) {
44129 this.resolvedProperty.toArray( buffer, offset );
44135 SetterByBindingTypeAndVersioning: [
44140 function setValue_direct( buffer, offset ) {
44142 this.targetObject[ this.propertyName ] = buffer[ offset ];
44146 function setValue_direct_setNeedsUpdate( buffer, offset ) {
44148 this.targetObject[ this.propertyName ] = buffer[ offset ];
44149 this.targetObject.needsUpdate = true;
44153 function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
44155 this.targetObject[ this.propertyName ] = buffer[ offset ];
44156 this.targetObject.matrixWorldNeedsUpdate = true;
44164 function setValue_array( buffer, offset ) {
44166 const dest = this.resolvedProperty;
44168 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
44170 dest[ i ] = buffer[ offset ++ ];
44176 function setValue_array_setNeedsUpdate( buffer, offset ) {
44178 const dest = this.resolvedProperty;
44180 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
44182 dest[ i ] = buffer[ offset ++ ];
44186 this.targetObject.needsUpdate = true;
44190 function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
44192 const dest = this.resolvedProperty;
44194 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
44196 dest[ i ] = buffer[ offset ++ ];
44200 this.targetObject.matrixWorldNeedsUpdate = true;
44208 function setValue_arrayElement( buffer, offset ) {
44210 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
44214 function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
44216 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
44217 this.targetObject.needsUpdate = true;
44221 function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
44223 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
44224 this.targetObject.matrixWorldNeedsUpdate = true;
44232 function setValue_fromArray( buffer, offset ) {
44234 this.resolvedProperty.fromArray( buffer, offset );
44238 function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
44240 this.resolvedProperty.fromArray( buffer, offset );
44241 this.targetObject.needsUpdate = true;
44245 function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
44247 this.resolvedProperty.fromArray( buffer, offset );
44248 this.targetObject.matrixWorldNeedsUpdate = true;
44256 getValue: function getValue_unbound( targetArray, offset ) {
44259 this.getValue( targetArray, offset );
44261 // Note: This class uses a State pattern on a per-method basis:
44262 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
44263 // prototype version of these methods with one that represents
44264 // the bound state. When the property is not found, the methods
44269 setValue: function getValue_unbound( sourceArray, offset ) {
44272 this.setValue( sourceArray, offset );
44276 // create getter / setter pair for a property in the scene graph
44277 bind: function () {
44279 let targetObject = this.node;
44280 const parsedPath = this.parsedPath;
44282 const objectName = parsedPath.objectName;
44283 const propertyName = parsedPath.propertyName;
44284 let propertyIndex = parsedPath.propertyIndex;
44286 if ( ! targetObject ) {
44288 targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
44290 this.node = targetObject;
44294 // set fail state so we can just 'return' on error
44295 this.getValue = this._getValue_unavailable;
44296 this.setValue = this._setValue_unavailable;
44298 // ensure there is a value node
44299 if ( ! targetObject ) {
44301 console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
44306 if ( objectName ) {
44308 let objectIndex = parsedPath.objectIndex;
44310 // special cases were we need to reach deeper into the hierarchy to get the face materials....
44311 switch ( objectName ) {
44315 if ( ! targetObject.material ) {
44317 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
44322 if ( ! targetObject.material.materials ) {
44324 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
44329 targetObject = targetObject.material.materials;
44335 if ( ! targetObject.skeleton ) {
44337 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
44342 // potential future optimization: skip this if propertyIndex is already an integer
44343 // and convert the integer string to a true integer.
44345 targetObject = targetObject.skeleton.bones;
44347 // support resolving morphTarget names into indices.
44348 for ( let i = 0; i < targetObject.length; i ++ ) {
44350 if ( targetObject[ i ].name === objectIndex ) {
44363 if ( targetObject[ objectName ] === undefined ) {
44365 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
44370 targetObject = targetObject[ objectName ];
44375 if ( objectIndex !== undefined ) {
44377 if ( targetObject[ objectIndex ] === undefined ) {
44379 console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
44384 targetObject = targetObject[ objectIndex ];
44390 // resolve property
44391 const nodeProperty = targetObject[ propertyName ];
44393 if ( nodeProperty === undefined ) {
44395 const nodeName = parsedPath.nodeName;
44397 console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
44398 '.' + propertyName + ' but it wasn\'t found.', targetObject );
44403 // determine versioning scheme
44404 let versioning = this.Versioning.None;
44406 this.targetObject = targetObject;
44408 if ( targetObject.needsUpdate !== undefined ) { // material
44410 versioning = this.Versioning.NeedsUpdate;
44412 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
44414 versioning = this.Versioning.MatrixWorldNeedsUpdate;
44418 // determine how the property gets bound
44419 let bindingType = this.BindingType.Direct;
44421 if ( propertyIndex !== undefined ) {
44423 // access a sub element of the property array (only primitives are supported right now)
44425 if ( propertyName === "morphTargetInfluences" ) {
44427 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
44429 // support resolving morphTarget names into indices.
44430 if ( ! targetObject.geometry ) {
44432 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
44437 if ( targetObject.geometry.isBufferGeometry ) {
44439 if ( ! targetObject.geometry.morphAttributes ) {
44441 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
44446 if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
44448 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
44455 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this );
44462 bindingType = this.BindingType.ArrayElement;
44464 this.resolvedProperty = nodeProperty;
44465 this.propertyIndex = propertyIndex;
44467 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
44469 // must use copy for Object3D.Euler/Quaternion
44471 bindingType = this.BindingType.HasFromToArray;
44473 this.resolvedProperty = nodeProperty;
44475 } else if ( Array.isArray( nodeProperty ) ) {
44477 bindingType = this.BindingType.EntireArray;
44479 this.resolvedProperty = nodeProperty;
44483 this.propertyName = propertyName;
44487 // select getter / setter
44488 this.getValue = this.GetterByBindingType[ bindingType ];
44489 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
44493 unbind: function () {
44497 // back to the prototype version of getValue / setValue
44498 // note: avoiding to mutate the shape of 'this' via 'delete'
44499 this.getValue = this._getValue_unbound;
44500 this.setValue = this._setValue_unbound;
44506 // DECLARE ALIAS AFTER assign prototype
44507 Object.assign( PropertyBinding.prototype, {
44509 // initial state of these methods that calls 'bind'
44510 _getValue_unbound: PropertyBinding.prototype.getValue,
44511 _setValue_unbound: PropertyBinding.prototype.setValue,
44517 * A group of objects that receives a shared animation state.
44521 * - Add objects you would otherwise pass as 'root' to the
44522 * constructor or the .clipAction method of AnimationMixer.
44524 * - Instead pass this object as 'root'.
44526 * - You can also add and remove objects later when the mixer
44531 * Objects of this class appear as one object to the mixer,
44532 * so cache control of the individual objects must be done
44537 * - The animated properties must be compatible among the
44538 * all objects in the group.
44540 * - A single property can either be controlled through a
44541 * target group or directly, but not both.
44544 function AnimationObjectGroup() {
44546 this.uuid = MathUtils.generateUUID();
44548 // cached objects followed by the active ones
44549 this._objects = Array.prototype.slice.call( arguments );
44551 this.nCachedObjects_ = 0; // threshold
44552 // note: read by PropertyBinding.Composite
44554 const indices = {};
44555 this._indicesByUUID = indices; // for bookkeeping
44557 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
44559 indices[ arguments[ i ].uuid ] = i;
44563 this._paths = []; // inside: string
44564 this._parsedPaths = []; // inside: { we don't care, here }
44565 this._bindings = []; // inside: Array< PropertyBinding >
44566 this._bindingsIndicesByPath = {}; // inside: indices in these arrays
44568 const scope = this;
44575 return scope._objects.length;
44580 return this.total - scope.nCachedObjects_;
44584 get bindingsPerObject() {
44586 return scope._bindings.length;
44594 Object.assign( AnimationObjectGroup.prototype, {
44596 isAnimationObjectGroup: true,
44600 const objects = this._objects,
44601 indicesByUUID = this._indicesByUUID,
44602 paths = this._paths,
44603 parsedPaths = this._parsedPaths,
44604 bindings = this._bindings,
44605 nBindings = bindings.length;
44607 let knownObject = undefined,
44608 nObjects = objects.length,
44609 nCachedObjects = this.nCachedObjects_;
44611 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
44613 const object = arguments[ i ],
44614 uuid = object.uuid;
44615 let index = indicesByUUID[ uuid ];
44617 if ( index === undefined ) {
44619 // unknown object -> add it to the ACTIVE region
44621 index = nObjects ++;
44622 indicesByUUID[ uuid ] = index;
44623 objects.push( object );
44625 // accounting is done, now do the same for all bindings
44627 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
44629 bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
44633 } else if ( index < nCachedObjects ) {
44635 knownObject = objects[ index ];
44637 // move existing object to the ACTIVE region
44639 const firstActiveIndex = -- nCachedObjects,
44640 lastCachedObject = objects[ firstActiveIndex ];
44642 indicesByUUID[ lastCachedObject.uuid ] = index;
44643 objects[ index ] = lastCachedObject;
44645 indicesByUUID[ uuid ] = firstActiveIndex;
44646 objects[ firstActiveIndex ] = object;
44648 // accounting is done, now do the same for all bindings
44650 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
44652 const bindingsForPath = bindings[ j ],
44653 lastCached = bindingsForPath[ firstActiveIndex ];
44655 let binding = bindingsForPath[ index ];
44657 bindingsForPath[ index ] = lastCached;
44659 if ( binding === undefined ) {
44661 // since we do not bother to create new bindings
44662 // for objects that are cached, the binding may
44663 // or may not exist
44665 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
44669 bindingsForPath[ firstActiveIndex ] = binding;
44673 } else if ( objects[ index ] !== knownObject ) {
44675 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
44676 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
44678 } // else the object is already where we want it to be
44682 this.nCachedObjects_ = nCachedObjects;
44686 remove: function () {
44688 const objects = this._objects,
44689 indicesByUUID = this._indicesByUUID,
44690 bindings = this._bindings,
44691 nBindings = bindings.length;
44693 let nCachedObjects = this.nCachedObjects_;
44695 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
44697 const object = arguments[ i ],
44698 uuid = object.uuid,
44699 index = indicesByUUID[ uuid ];
44701 if ( index !== undefined && index >= nCachedObjects ) {
44703 // move existing object into the CACHED region
44705 const lastCachedIndex = nCachedObjects ++,
44706 firstActiveObject = objects[ lastCachedIndex ];
44708 indicesByUUID[ firstActiveObject.uuid ] = index;
44709 objects[ index ] = firstActiveObject;
44711 indicesByUUID[ uuid ] = lastCachedIndex;
44712 objects[ lastCachedIndex ] = object;
44714 // accounting is done, now do the same for all bindings
44716 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
44718 const bindingsForPath = bindings[ j ],
44719 firstActive = bindingsForPath[ lastCachedIndex ],
44720 binding = bindingsForPath[ index ];
44722 bindingsForPath[ index ] = firstActive;
44723 bindingsForPath[ lastCachedIndex ] = binding;
44731 this.nCachedObjects_ = nCachedObjects;
44736 uncache: function () {
44738 const objects = this._objects,
44739 indicesByUUID = this._indicesByUUID,
44740 bindings = this._bindings,
44741 nBindings = bindings.length;
44743 let nCachedObjects = this.nCachedObjects_,
44744 nObjects = objects.length;
44746 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
44748 const object = arguments[ i ],
44749 uuid = object.uuid,
44750 index = indicesByUUID[ uuid ];
44752 if ( index !== undefined ) {
44754 delete indicesByUUID[ uuid ];
44756 if ( index < nCachedObjects ) {
44758 // object is cached, shrink the CACHED region
44760 const firstActiveIndex = -- nCachedObjects,
44761 lastCachedObject = objects[ firstActiveIndex ],
44762 lastIndex = -- nObjects,
44763 lastObject = objects[ lastIndex ];
44765 // last cached object takes this object's place
44766 indicesByUUID[ lastCachedObject.uuid ] = index;
44767 objects[ index ] = lastCachedObject;
44769 // last object goes to the activated slot and pop
44770 indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
44771 objects[ firstActiveIndex ] = lastObject;
44774 // accounting is done, now do the same for all bindings
44776 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
44778 const bindingsForPath = bindings[ j ],
44779 lastCached = bindingsForPath[ firstActiveIndex ],
44780 last = bindingsForPath[ lastIndex ];
44782 bindingsForPath[ index ] = lastCached;
44783 bindingsForPath[ firstActiveIndex ] = last;
44784 bindingsForPath.pop();
44790 // object is active, just swap with the last and pop
44792 const lastIndex = -- nObjects,
44793 lastObject = objects[ lastIndex ];
44795 if ( lastIndex > 0 ) {
44797 indicesByUUID[ lastObject.uuid ] = index;
44801 objects[ index ] = lastObject;
44804 // accounting is done, now do the same for all bindings
44806 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
44808 const bindingsForPath = bindings[ j ];
44810 bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
44811 bindingsForPath.pop();
44815 } // cached or active
44817 } // if object is known
44821 this.nCachedObjects_ = nCachedObjects;
44825 // Internal interface used by befriended PropertyBinding.Composite:
44827 subscribe_: function ( path, parsedPath ) {
44829 // returns an array of bindings for the given path that is changed
44830 // according to the contained objects in the group
44832 const indicesByPath = this._bindingsIndicesByPath;
44833 let index = indicesByPath[ path ];
44834 const bindings = this._bindings;
44836 if ( index !== undefined ) return bindings[ index ];
44838 const paths = this._paths,
44839 parsedPaths = this._parsedPaths,
44840 objects = this._objects,
44841 nObjects = objects.length,
44842 nCachedObjects = this.nCachedObjects_,
44843 bindingsForPath = new Array( nObjects );
44845 index = bindings.length;
44847 indicesByPath[ path ] = index;
44849 paths.push( path );
44850 parsedPaths.push( parsedPath );
44851 bindings.push( bindingsForPath );
44853 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
44855 const object = objects[ i ];
44856 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
44860 return bindingsForPath;
44864 unsubscribe_: function ( path ) {
44866 // tells the group to forget about a property path and no longer
44867 // update the array previously obtained with 'subscribe_'
44869 const indicesByPath = this._bindingsIndicesByPath,
44870 index = indicesByPath[ path ];
44872 if ( index !== undefined ) {
44874 const paths = this._paths,
44875 parsedPaths = this._parsedPaths,
44876 bindings = this._bindings,
44877 lastBindingsIndex = bindings.length - 1,
44878 lastBindings = bindings[ lastBindingsIndex ],
44879 lastBindingsPath = path[ lastBindingsIndex ];
44881 indicesByPath[ lastBindingsPath ] = index;
44883 bindings[ index ] = lastBindings;
44886 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
44889 paths[ index ] = paths[ lastBindingsIndex ];
44898 class AnimationAction {
44900 constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
44902 this._mixer = mixer;
44904 this._localRoot = localRoot;
44905 this.blendMode = blendMode;
44907 const tracks = clip.tracks,
44908 nTracks = tracks.length,
44909 interpolants = new Array( nTracks );
44911 const interpolantSettings = {
44912 endingStart: ZeroCurvatureEnding,
44913 endingEnd: ZeroCurvatureEnding
44916 for ( let i = 0; i !== nTracks; ++ i ) {
44918 const interpolant = tracks[ i ].createInterpolant( null );
44919 interpolants[ i ] = interpolant;
44920 interpolant.settings = interpolantSettings;
44924 this._interpolantSettings = interpolantSettings;
44926 this._interpolants = interpolants; // bound by the mixer
44928 // inside: PropertyMixer (managed by the mixer)
44929 this._propertyBindings = new Array( nTracks );
44931 this._cacheIndex = null; // for the memory manager
44932 this._byClipCacheIndex = null; // for the memory manager
44934 this._timeScaleInterpolant = null;
44935 this._weightInterpolant = null;
44937 this.loop = LoopRepeat;
44938 this._loopCount = - 1;
44940 // global mixer time when the action is to be started
44941 // it's set back to 'null' upon start of the action
44942 this._startTime = null;
44944 // scaled local time of the action
44945 // gets clamped or wrapped to 0..clip.duration according to loop
44948 this.timeScale = 1;
44949 this._effectiveTimeScale = 1;
44952 this._effectiveWeight = 1;
44954 this.repetitions = Infinity; // no. of repetitions when looping
44956 this.paused = false; // true -> zero effective time scale
44957 this.enabled = true; // false -> zero effective weight
44959 this.clampWhenFinished = false;// keep feeding the last frame?
44961 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
44962 this.zeroSlopeAtEnd = true;// clips for start, loop and end
44966 // State & Scheduling
44970 this._mixer._activateAction( this );
44978 this._mixer._deactivateAction( this );
44980 return this.reset();
44986 this.paused = false;
44987 this.enabled = true;
44989 this.time = 0; // restart clip
44990 this._loopCount = - 1;// forget previous loops
44991 this._startTime = null;// forget scheduling
44993 return this.stopFading().stopWarping();
44999 return this.enabled && ! this.paused && this.timeScale !== 0 &&
45000 this._startTime === null && this._mixer._isActiveAction( this );
45004 // return true when play has been called
45007 return this._mixer._isActiveAction( this );
45013 this._startTime = time;
45019 setLoop( mode, repetitions ) {
45022 this.repetitions = repetitions;
45030 // set the weight stopping any scheduled fading
45031 // although .enabled = false yields an effective weight of zero, this
45032 // method does *not* change .enabled, because it would be confusing
45033 setEffectiveWeight( weight ) {
45035 this.weight = weight;
45037 // note: same logic as when updated at runtime
45038 this._effectiveWeight = this.enabled ? weight : 0;
45040 return this.stopFading();
45044 // return the weight considering fading and .enabled
45045 getEffectiveWeight() {
45047 return this._effectiveWeight;
45051 fadeIn( duration ) {
45053 return this._scheduleFading( duration, 0, 1 );
45057 fadeOut( duration ) {
45059 return this._scheduleFading( duration, 1, 0 );
45063 crossFadeFrom( fadeOutAction, duration, warp ) {
45065 fadeOutAction.fadeOut( duration );
45066 this.fadeIn( duration );
45070 const fadeInDuration = this._clip.duration,
45071 fadeOutDuration = fadeOutAction._clip.duration,
45073 startEndRatio = fadeOutDuration / fadeInDuration,
45074 endStartRatio = fadeInDuration / fadeOutDuration;
45076 fadeOutAction.warp( 1.0, startEndRatio, duration );
45077 this.warp( endStartRatio, 1.0, duration );
45085 crossFadeTo( fadeInAction, duration, warp ) {
45087 return fadeInAction.crossFadeFrom( this, duration, warp );
45093 const weightInterpolant = this._weightInterpolant;
45095 if ( weightInterpolant !== null ) {
45097 this._weightInterpolant = null;
45098 this._mixer._takeBackControlInterpolant( weightInterpolant );
45106 // Time Scale Control
45108 // set the time scale stopping any scheduled warping
45109 // although .paused = true yields an effective time scale of zero, this
45110 // method does *not* change .paused, because it would be confusing
45111 setEffectiveTimeScale( timeScale ) {
45113 this.timeScale = timeScale;
45114 this._effectiveTimeScale = this.paused ? 0 : timeScale;
45116 return this.stopWarping();
45120 // return the time scale considering warping and .paused
45121 getEffectiveTimeScale() {
45123 return this._effectiveTimeScale;
45127 setDuration( duration ) {
45129 this.timeScale = this._clip.duration / duration;
45131 return this.stopWarping();
45135 syncWith( action ) {
45137 this.time = action.time;
45138 this.timeScale = action.timeScale;
45140 return this.stopWarping();
45146 return this.warp( this._effectiveTimeScale, 0, duration );
45150 warp( startTimeScale, endTimeScale, duration ) {
45152 const mixer = this._mixer,
45154 timeScale = this.timeScale;
45156 let interpolant = this._timeScaleInterpolant;
45158 if ( interpolant === null ) {
45160 interpolant = mixer._lendControlInterpolant();
45161 this._timeScaleInterpolant = interpolant;
45165 const times = interpolant.parameterPositions,
45166 values = interpolant.sampleValues;
45169 times[ 1 ] = now + duration;
45171 values[ 0 ] = startTimeScale / timeScale;
45172 values[ 1 ] = endTimeScale / timeScale;
45180 const timeScaleInterpolant = this._timeScaleInterpolant;
45182 if ( timeScaleInterpolant !== null ) {
45184 this._timeScaleInterpolant = null;
45185 this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
45193 // Object Accessors
45197 return this._mixer;
45209 return this._localRoot || this._mixer._root;
45215 _update( time, deltaTime, timeDirection, accuIndex ) {
45217 // called by the mixer
45219 if ( ! this.enabled ) {
45221 // call ._updateWeight() to update ._effectiveWeight
45223 this._updateWeight( time );
45228 const startTime = this._startTime;
45230 if ( startTime !== null ) {
45232 // check for scheduled start of action
45234 const timeRunning = ( time - startTime ) * timeDirection;
45235 if ( timeRunning < 0 || timeDirection === 0 ) {
45237 return; // yet to come / don't decide when delta = 0
45243 this._startTime = null; // unschedule
45244 deltaTime = timeDirection * timeRunning;
45248 // apply time scale and advance time
45250 deltaTime *= this._updateTimeScale( time );
45251 const clipTime = this._updateTime( deltaTime );
45253 // note: _updateTime may disable the action resulting in
45254 // an effective weight of 0
45256 const weight = this._updateWeight( time );
45258 if ( weight > 0 ) {
45260 const interpolants = this._interpolants;
45261 const propertyMixers = this._propertyBindings;
45263 switch ( this.blendMode ) {
45265 case AdditiveAnimationBlendMode:
45267 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
45269 interpolants[ j ].evaluate( clipTime );
45270 propertyMixers[ j ].accumulateAdditive( weight );
45276 case NormalAnimationBlendMode:
45279 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
45281 interpolants[ j ].evaluate( clipTime );
45282 propertyMixers[ j ].accumulate( accuIndex, weight );
45292 _updateWeight( time ) {
45296 if ( this.enabled ) {
45298 weight = this.weight;
45299 const interpolant = this._weightInterpolant;
45301 if ( interpolant !== null ) {
45303 const interpolantValue = interpolant.evaluate( time )[ 0 ];
45305 weight *= interpolantValue;
45307 if ( time > interpolant.parameterPositions[ 1 ] ) {
45311 if ( interpolantValue === 0 ) {
45313 // faded out, disable
45314 this.enabled = false;
45324 this._effectiveWeight = weight;
45329 _updateTimeScale( time ) {
45333 if ( ! this.paused ) {
45335 timeScale = this.timeScale;
45337 const interpolant = this._timeScaleInterpolant;
45339 if ( interpolant !== null ) {
45341 const interpolantValue = interpolant.evaluate( time )[ 0 ];
45343 timeScale *= interpolantValue;
45345 if ( time > interpolant.parameterPositions[ 1 ] ) {
45347 this.stopWarping();
45349 if ( timeScale === 0 ) {
45351 // motion has halted, pause
45352 this.paused = true;
45356 // warp done - apply final time scale
45357 this.timeScale = timeScale;
45367 this._effectiveTimeScale = timeScale;
45372 _updateTime( deltaTime ) {
45374 const duration = this._clip.duration;
45375 const loop = this.loop;
45377 let time = this.time + deltaTime;
45378 let loopCount = this._loopCount;
45380 const pingPong = ( loop === LoopPingPong );
45382 if ( deltaTime === 0 ) {
45384 if ( loopCount === - 1 ) return time;
45386 return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
45390 if ( loop === LoopOnce ) {
45392 if ( loopCount === - 1 ) {
45396 this._loopCount = 0;
45397 this._setEndings( true, true, false );
45403 if ( time >= duration ) {
45407 } else if ( time < 0 ) {
45419 if ( this.clampWhenFinished ) this.paused = true;
45420 else this.enabled = false;
45424 this._mixer.dispatchEvent( {
45425 type: 'finished', action: this,
45426 direction: deltaTime < 0 ? - 1 : 1
45431 } else { // repetitive Repeat or PingPong
45433 if ( loopCount === - 1 ) {
45437 if ( deltaTime >= 0 ) {
45441 this._setEndings( true, this.repetitions === 0, pingPong );
45445 // when looping in reverse direction, the initial
45446 // transition through zero counts as a repetition,
45447 // so leave loopCount at -1
45449 this._setEndings( this.repetitions === 0, true, pingPong );
45455 if ( time >= duration || time < 0 ) {
45459 const loopDelta = Math.floor( time / duration ); // signed
45460 time -= duration * loopDelta;
45462 loopCount += Math.abs( loopDelta );
45464 const pending = this.repetitions - loopCount;
45466 if ( pending <= 0 ) {
45468 // have to stop (switch state, clamp time, fire event)
45470 if ( this.clampWhenFinished ) this.paused = true;
45471 else this.enabled = false;
45473 time = deltaTime > 0 ? duration : 0;
45477 this._mixer.dispatchEvent( {
45478 type: 'finished', action: this,
45479 direction: deltaTime > 0 ? 1 : - 1
45486 if ( pending === 1 ) {
45488 // entering the last round
45490 const atStart = deltaTime < 0;
45491 this._setEndings( atStart, ! atStart, pingPong );
45495 this._setEndings( false, false, pingPong );
45499 this._loopCount = loopCount;
45503 this._mixer.dispatchEvent( {
45504 type: 'loop', action: this, loopDelta: loopDelta
45515 if ( pingPong && ( loopCount & 1 ) === 1 ) {
45517 // invert time for the "pong round"
45519 return duration - time;
45529 _setEndings( atStart, atEnd, pingPong ) {
45531 const settings = this._interpolantSettings;
45535 settings.endingStart = ZeroSlopeEnding;
45536 settings.endingEnd = ZeroSlopeEnding;
45540 // assuming for LoopOnce atStart == atEnd == true
45544 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
45548 settings.endingStart = WrapAroundEnding;
45554 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
45558 settings.endingEnd = WrapAroundEnding;
45566 _scheduleFading( duration, weightNow, weightThen ) {
45568 const mixer = this._mixer, now = mixer.time;
45569 let interpolant = this._weightInterpolant;
45571 if ( interpolant === null ) {
45573 interpolant = mixer._lendControlInterpolant();
45574 this._weightInterpolant = interpolant;
45578 const times = interpolant.parameterPositions,
45579 values = interpolant.sampleValues;
45582 values[ 0 ] = weightNow;
45583 times[ 1 ] = now + duration;
45584 values[ 1 ] = weightThen;
45592 function AnimationMixer( root ) {
45595 this._initMemoryManager();
45596 this._accuIndex = 0;
45600 this.timeScale = 1.0;
45604 AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
45606 constructor: AnimationMixer,
45608 _bindAction: function ( action, prototypeAction ) {
45610 const root = action._localRoot || this._root,
45611 tracks = action._clip.tracks,
45612 nTracks = tracks.length,
45613 bindings = action._propertyBindings,
45614 interpolants = action._interpolants,
45615 rootUuid = root.uuid,
45616 bindingsByRoot = this._bindingsByRootAndName;
45618 let bindingsByName = bindingsByRoot[ rootUuid ];
45620 if ( bindingsByName === undefined ) {
45622 bindingsByName = {};
45623 bindingsByRoot[ rootUuid ] = bindingsByName;
45627 for ( let i = 0; i !== nTracks; ++ i ) {
45629 const track = tracks[ i ],
45630 trackName = track.name;
45632 let binding = bindingsByName[ trackName ];
45634 if ( binding !== undefined ) {
45636 bindings[ i ] = binding;
45640 binding = bindings[ i ];
45642 if ( binding !== undefined ) {
45644 // existing binding, make sure the cache knows
45646 if ( binding._cacheIndex === null ) {
45648 ++ binding.referenceCount;
45649 this._addInactiveBinding( binding, rootUuid, trackName );
45657 const path = prototypeAction && prototypeAction.
45658 _propertyBindings[ i ].binding.parsedPath;
45660 binding = new PropertyMixer(
45661 PropertyBinding.create( root, trackName, path ),
45662 track.ValueTypeName, track.getValueSize() );
45664 ++ binding.referenceCount;
45665 this._addInactiveBinding( binding, rootUuid, trackName );
45667 bindings[ i ] = binding;
45671 interpolants[ i ].resultBuffer = binding.buffer;
45677 _activateAction: function ( action ) {
45679 if ( ! this._isActiveAction( action ) ) {
45681 if ( action._cacheIndex === null ) {
45683 // this action has been forgotten by the cache, but the user
45684 // appears to be still using it -> rebind
45686 const rootUuid = ( action._localRoot || this._root ).uuid,
45687 clipUuid = action._clip.uuid,
45688 actionsForClip = this._actionsByClip[ clipUuid ];
45690 this._bindAction( action,
45691 actionsForClip && actionsForClip.knownActions[ 0 ] );
45693 this._addInactiveAction( action, clipUuid, rootUuid );
45697 const bindings = action._propertyBindings;
45699 // increment reference counts / sort out state
45700 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
45702 const binding = bindings[ i ];
45704 if ( binding.useCount ++ === 0 ) {
45706 this._lendBinding( binding );
45707 binding.saveOriginalState();
45713 this._lendAction( action );
45719 _deactivateAction: function ( action ) {
45721 if ( this._isActiveAction( action ) ) {
45723 const bindings = action._propertyBindings;
45725 // decrement reference counts / sort out state
45726 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
45728 const binding = bindings[ i ];
45730 if ( -- binding.useCount === 0 ) {
45732 binding.restoreOriginalState();
45733 this._takeBackBinding( binding );
45739 this._takeBackAction( action );
45747 _initMemoryManager: function () {
45749 this._actions = []; // 'nActiveActions' followed by inactive ones
45750 this._nActiveActions = 0;
45752 this._actionsByClip = {};
45755 // knownActions: Array< AnimationAction > - used as prototypes
45756 // actionByRoot: AnimationAction - lookup
45760 this._bindings = []; // 'nActiveBindings' followed by inactive ones
45761 this._nActiveBindings = 0;
45763 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
45766 this._controlInterpolants = []; // same game as above
45767 this._nActiveControlInterpolants = 0;
45769 const scope = this;
45776 return scope._actions.length;
45781 return scope._nActiveActions;
45788 return scope._bindings.length;
45793 return scope._nActiveBindings;
45797 controlInterpolants: {
45800 return scope._controlInterpolants.length;
45805 return scope._nActiveControlInterpolants;
45814 // Memory management for AnimationAction objects
45816 _isActiveAction: function ( action ) {
45818 const index = action._cacheIndex;
45819 return index !== null && index < this._nActiveActions;
45823 _addInactiveAction: function ( action, clipUuid, rootUuid ) {
45825 const actions = this._actions,
45826 actionsByClip = this._actionsByClip;
45828 let actionsForClip = actionsByClip[ clipUuid ];
45830 if ( actionsForClip === undefined ) {
45834 knownActions: [ action ],
45839 action._byClipCacheIndex = 0;
45841 actionsByClip[ clipUuid ] = actionsForClip;
45845 const knownActions = actionsForClip.knownActions;
45847 action._byClipCacheIndex = knownActions.length;
45848 knownActions.push( action );
45852 action._cacheIndex = actions.length;
45853 actions.push( action );
45855 actionsForClip.actionByRoot[ rootUuid ] = action;
45859 _removeInactiveAction: function ( action ) {
45861 const actions = this._actions,
45862 lastInactiveAction = actions[ actions.length - 1 ],
45863 cacheIndex = action._cacheIndex;
45865 lastInactiveAction._cacheIndex = cacheIndex;
45866 actions[ cacheIndex ] = lastInactiveAction;
45869 action._cacheIndex = null;
45872 const clipUuid = action._clip.uuid,
45873 actionsByClip = this._actionsByClip,
45874 actionsForClip = actionsByClip[ clipUuid ],
45875 knownActionsForClip = actionsForClip.knownActions,
45878 knownActionsForClip[ knownActionsForClip.length - 1 ],
45880 byClipCacheIndex = action._byClipCacheIndex;
45882 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
45883 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
45884 knownActionsForClip.pop();
45886 action._byClipCacheIndex = null;
45889 const actionByRoot = actionsForClip.actionByRoot,
45890 rootUuid = ( action._localRoot || this._root ).uuid;
45892 delete actionByRoot[ rootUuid ];
45894 if ( knownActionsForClip.length === 0 ) {
45896 delete actionsByClip[ clipUuid ];
45900 this._removeInactiveBindingsForAction( action );
45904 _removeInactiveBindingsForAction: function ( action ) {
45906 const bindings = action._propertyBindings;
45908 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
45910 const binding = bindings[ i ];
45912 if ( -- binding.referenceCount === 0 ) {
45914 this._removeInactiveBinding( binding );
45922 _lendAction: function ( action ) {
45924 // [ active actions | inactive actions ]
45925 // [ active actions >| inactive actions ]
45930 const actions = this._actions,
45931 prevIndex = action._cacheIndex,
45933 lastActiveIndex = this._nActiveActions ++,
45935 firstInactiveAction = actions[ lastActiveIndex ];
45937 action._cacheIndex = lastActiveIndex;
45938 actions[ lastActiveIndex ] = action;
45940 firstInactiveAction._cacheIndex = prevIndex;
45941 actions[ prevIndex ] = firstInactiveAction;
45945 _takeBackAction: function ( action ) {
45947 // [ active actions | inactive actions ]
45948 // [ active actions |< inactive actions ]
45953 const actions = this._actions,
45954 prevIndex = action._cacheIndex,
45956 firstInactiveIndex = -- this._nActiveActions,
45958 lastActiveAction = actions[ firstInactiveIndex ];
45960 action._cacheIndex = firstInactiveIndex;
45961 actions[ firstInactiveIndex ] = action;
45963 lastActiveAction._cacheIndex = prevIndex;
45964 actions[ prevIndex ] = lastActiveAction;
45968 // Memory management for PropertyMixer objects
45970 _addInactiveBinding: function ( binding, rootUuid, trackName ) {
45972 const bindingsByRoot = this._bindingsByRootAndName,
45973 bindings = this._bindings;
45975 let bindingByName = bindingsByRoot[ rootUuid ];
45977 if ( bindingByName === undefined ) {
45979 bindingByName = {};
45980 bindingsByRoot[ rootUuid ] = bindingByName;
45984 bindingByName[ trackName ] = binding;
45986 binding._cacheIndex = bindings.length;
45987 bindings.push( binding );
45991 _removeInactiveBinding: function ( binding ) {
45993 const bindings = this._bindings,
45994 propBinding = binding.binding,
45995 rootUuid = propBinding.rootNode.uuid,
45996 trackName = propBinding.path,
45997 bindingsByRoot = this._bindingsByRootAndName,
45998 bindingByName = bindingsByRoot[ rootUuid ],
46000 lastInactiveBinding = bindings[ bindings.length - 1 ],
46001 cacheIndex = binding._cacheIndex;
46003 lastInactiveBinding._cacheIndex = cacheIndex;
46004 bindings[ cacheIndex ] = lastInactiveBinding;
46007 delete bindingByName[ trackName ];
46009 if ( Object.keys( bindingByName ).length === 0 ) {
46011 delete bindingsByRoot[ rootUuid ];
46017 _lendBinding: function ( binding ) {
46019 const bindings = this._bindings,
46020 prevIndex = binding._cacheIndex,
46022 lastActiveIndex = this._nActiveBindings ++,
46024 firstInactiveBinding = bindings[ lastActiveIndex ];
46026 binding._cacheIndex = lastActiveIndex;
46027 bindings[ lastActiveIndex ] = binding;
46029 firstInactiveBinding._cacheIndex = prevIndex;
46030 bindings[ prevIndex ] = firstInactiveBinding;
46034 _takeBackBinding: function ( binding ) {
46036 const bindings = this._bindings,
46037 prevIndex = binding._cacheIndex,
46039 firstInactiveIndex = -- this._nActiveBindings,
46041 lastActiveBinding = bindings[ firstInactiveIndex ];
46043 binding._cacheIndex = firstInactiveIndex;
46044 bindings[ firstInactiveIndex ] = binding;
46046 lastActiveBinding._cacheIndex = prevIndex;
46047 bindings[ prevIndex ] = lastActiveBinding;
46052 // Memory management of Interpolants for weight and time scale
46054 _lendControlInterpolant: function () {
46056 const interpolants = this._controlInterpolants,
46057 lastActiveIndex = this._nActiveControlInterpolants ++;
46059 let interpolant = interpolants[ lastActiveIndex ];
46061 if ( interpolant === undefined ) {
46063 interpolant = new LinearInterpolant(
46064 new Float32Array( 2 ), new Float32Array( 2 ),
46065 1, this._controlInterpolantsResultBuffer );
46067 interpolant.__cacheIndex = lastActiveIndex;
46068 interpolants[ lastActiveIndex ] = interpolant;
46072 return interpolant;
46076 _takeBackControlInterpolant: function ( interpolant ) {
46078 const interpolants = this._controlInterpolants,
46079 prevIndex = interpolant.__cacheIndex,
46081 firstInactiveIndex = -- this._nActiveControlInterpolants,
46083 lastActiveInterpolant = interpolants[ firstInactiveIndex ];
46085 interpolant.__cacheIndex = firstInactiveIndex;
46086 interpolants[ firstInactiveIndex ] = interpolant;
46088 lastActiveInterpolant.__cacheIndex = prevIndex;
46089 interpolants[ prevIndex ] = lastActiveInterpolant;
46093 _controlInterpolantsResultBuffer: new Float32Array( 1 ),
46095 // return an action for a clip optionally using a custom root target
46096 // object (this method allocates a lot of dynamic memory in case a
46097 // previously unknown clip/root combination is specified)
46098 clipAction: function ( clip, optionalRoot, blendMode ) {
46100 const root = optionalRoot || this._root,
46101 rootUuid = root.uuid;
46103 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
46105 const clipUuid = clipObject !== null ? clipObject.uuid : clip;
46107 const actionsForClip = this._actionsByClip[ clipUuid ];
46108 let prototypeAction = null;
46110 if ( blendMode === undefined ) {
46112 if ( clipObject !== null ) {
46114 blendMode = clipObject.blendMode;
46118 blendMode = NormalAnimationBlendMode;
46124 if ( actionsForClip !== undefined ) {
46126 const existingAction = actionsForClip.actionByRoot[ rootUuid ];
46128 if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
46130 return existingAction;
46134 // we know the clip, so we don't have to parse all
46135 // the bindings again but can just copy
46136 prototypeAction = actionsForClip.knownActions[ 0 ];
46138 // also, take the clip from the prototype action
46139 if ( clipObject === null )
46140 clipObject = prototypeAction._clip;
46144 // clip must be known when specified via string
46145 if ( clipObject === null ) return null;
46147 // allocate all resources required to run it
46148 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
46150 this._bindAction( newAction, prototypeAction );
46152 // and make the action known to the memory manager
46153 this._addInactiveAction( newAction, clipUuid, rootUuid );
46159 // get an existing action
46160 existingAction: function ( clip, optionalRoot ) {
46162 const root = optionalRoot || this._root,
46163 rootUuid = root.uuid,
46165 clipObject = typeof clip === 'string' ?
46166 AnimationClip.findByName( root, clip ) : clip,
46168 clipUuid = clipObject ? clipObject.uuid : clip,
46170 actionsForClip = this._actionsByClip[ clipUuid ];
46172 if ( actionsForClip !== undefined ) {
46174 return actionsForClip.actionByRoot[ rootUuid ] || null;
46182 // deactivates all previously scheduled actions
46183 stopAllAction: function () {
46185 const actions = this._actions,
46186 nActions = this._nActiveActions;
46188 for ( let i = nActions - 1; i >= 0; -- i ) {
46190 actions[ i ].stop();
46198 // advance the time and update apply the animation
46199 update: function ( deltaTime ) {
46201 deltaTime *= this.timeScale;
46203 const actions = this._actions,
46204 nActions = this._nActiveActions,
46206 time = this.time += deltaTime,
46207 timeDirection = Math.sign( deltaTime ),
46209 accuIndex = this._accuIndex ^= 1;
46211 // run active actions
46213 for ( let i = 0; i !== nActions; ++ i ) {
46215 const action = actions[ i ];
46217 action._update( time, deltaTime, timeDirection, accuIndex );
46221 // update scene graph
46223 const bindings = this._bindings,
46224 nBindings = this._nActiveBindings;
46226 for ( let i = 0; i !== nBindings; ++ i ) {
46228 bindings[ i ].apply( accuIndex );
46236 // Allows you to seek to a specific time in an animation.
46237 setTime: function ( timeInSeconds ) {
46239 this.time = 0; // Zero out time attribute for AnimationMixer object;
46240 for ( let i = 0; i < this._actions.length; i ++ ) {
46242 this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
46246 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
46250 // return this mixer's root target object
46251 getRoot: function () {
46257 // free all resources specific to a particular clip
46258 uncacheClip: function ( clip ) {
46260 const actions = this._actions,
46261 clipUuid = clip.uuid,
46262 actionsByClip = this._actionsByClip,
46263 actionsForClip = actionsByClip[ clipUuid ];
46265 if ( actionsForClip !== undefined ) {
46267 // note: just calling _removeInactiveAction would mess up the
46268 // iteration state and also require updating the state we can
46271 const actionsToRemove = actionsForClip.knownActions;
46273 for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
46275 const action = actionsToRemove[ i ];
46277 this._deactivateAction( action );
46279 const cacheIndex = action._cacheIndex,
46280 lastInactiveAction = actions[ actions.length - 1 ];
46282 action._cacheIndex = null;
46283 action._byClipCacheIndex = null;
46285 lastInactiveAction._cacheIndex = cacheIndex;
46286 actions[ cacheIndex ] = lastInactiveAction;
46289 this._removeInactiveBindingsForAction( action );
46293 delete actionsByClip[ clipUuid ];
46299 // free all resources specific to a particular root target object
46300 uncacheRoot: function ( root ) {
46302 const rootUuid = root.uuid,
46303 actionsByClip = this._actionsByClip;
46305 for ( const clipUuid in actionsByClip ) {
46307 const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
46308 action = actionByRoot[ rootUuid ];
46310 if ( action !== undefined ) {
46312 this._deactivateAction( action );
46313 this._removeInactiveAction( action );
46319 const bindingsByRoot = this._bindingsByRootAndName,
46320 bindingByName = bindingsByRoot[ rootUuid ];
46322 if ( bindingByName !== undefined ) {
46324 for ( const trackName in bindingByName ) {
46326 const binding = bindingByName[ trackName ];
46327 binding.restoreOriginalState();
46328 this._removeInactiveBinding( binding );
46336 // remove a targeted clip from the cache
46337 uncacheAction: function ( clip, optionalRoot ) {
46339 const action = this.existingAction( clip, optionalRoot );
46341 if ( action !== null ) {
46343 this._deactivateAction( action );
46344 this._removeInactiveAction( action );
46354 constructor( value ) {
46356 if ( typeof value === 'string' ) {
46358 console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
46359 value = arguments[ 1 ];
46363 this.value = value;
46369 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
46375 function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
46377 InterleavedBuffer.call( this, array, stride );
46379 this.meshPerAttribute = meshPerAttribute || 1;
46383 InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
46385 constructor: InstancedInterleavedBuffer,
46387 isInstancedInterleavedBuffer: true,
46389 copy: function ( source ) {
46391 InterleavedBuffer.prototype.copy.call( this, source );
46393 this.meshPerAttribute = source.meshPerAttribute;
46399 clone: function ( data ) {
46401 const ib = InterleavedBuffer.prototype.clone.call( this, data );
46403 ib.meshPerAttribute = this.meshPerAttribute;
46409 toJSON: function ( data ) {
46411 const json = InterleavedBuffer.prototype.toJSON.call( this, data );
46413 json.isInstancedInterleavedBuffer = true;
46414 json.meshPerAttribute = this.meshPerAttribute;
46422 function GLBufferAttribute( buffer, type, itemSize, elementSize, count ) {
46424 this.buffer = buffer;
46426 this.itemSize = itemSize;
46427 this.elementSize = elementSize;
46428 this.count = count;
46434 Object.defineProperty( GLBufferAttribute.prototype, 'needsUpdate', {
46436 set: function ( value ) {
46438 if ( value === true ) this.version ++;
46444 Object.assign( GLBufferAttribute.prototype, {
46446 isGLBufferAttribute: true,
46448 setBuffer: function ( buffer ) {
46450 this.buffer = buffer;
46456 setType: function ( type, elementSize ) {
46459 this.elementSize = elementSize;
46465 setItemSize: function ( itemSize ) {
46467 this.itemSize = itemSize;
46473 setCount: function ( count ) {
46475 this.count = count;
46483 function Raycaster( origin, direction, near, far ) {
46485 this.ray = new Ray( origin, direction );
46486 // direction is assumed to be normalized (for accurate distance calculations)
46488 this.near = near || 0;
46489 this.far = far || Infinity;
46490 this.camera = null;
46491 this.layers = new Layers();
46495 Line: { threshold: 1 },
46497 Points: { threshold: 1 },
46501 Object.defineProperties( this.params, {
46505 console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
46506 return this.Points;
46514 function ascSort( a, b ) {
46516 return a.distance - b.distance;
46520 function intersectObject( object, raycaster, intersects, recursive ) {
46522 if ( object.layers.test( raycaster.layers ) ) {
46524 object.raycast( raycaster, intersects );
46528 if ( recursive === true ) {
46530 const children = object.children;
46532 for ( let i = 0, l = children.length; i < l; i ++ ) {
46534 intersectObject( children[ i ], raycaster, intersects, true );
46542 Object.assign( Raycaster.prototype, {
46544 set: function ( origin, direction ) {
46546 // direction is assumed to be normalized (for accurate distance calculations)
46548 this.ray.set( origin, direction );
46552 setFromCamera: function ( coords, camera ) {
46554 if ( ( camera && camera.isPerspectiveCamera ) ) {
46556 this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
46557 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
46558 this.camera = camera;
46560 } else if ( ( camera && camera.isOrthographicCamera ) ) {
46562 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
46563 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
46564 this.camera = camera;
46568 console.error( 'THREE.Raycaster: Unsupported camera type.' );
46574 intersectObject: function ( object, recursive, optionalTarget ) {
46576 const intersects = optionalTarget || [];
46578 intersectObject( object, this, intersects, recursive );
46580 intersects.sort( ascSort );
46586 intersectObjects: function ( objects, recursive, optionalTarget ) {
46588 const intersects = optionalTarget || [];
46590 if ( Array.isArray( objects ) === false ) {
46592 console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
46597 for ( let i = 0, l = objects.length; i < l; i ++ ) {
46599 intersectObject( objects[ i ], this, intersects, recursive );
46603 intersects.sort( ascSort );
46612 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
46614 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
46615 * The azimuthal angle (theta) is measured from the positive z-axis.
46620 constructor( radius = 1, phi = 0, theta = 0 ) {
46622 this.radius = radius;
46623 this.phi = phi; // polar angle
46624 this.theta = theta; // azimuthal angle
46630 set( radius, phi, theta ) {
46632 this.radius = radius;
46634 this.theta = theta;
46642 return new this.constructor().copy( this );
46648 this.radius = other.radius;
46649 this.phi = other.phi;
46650 this.theta = other.theta;
46656 // restrict phi to be betwee EPS and PI-EPS
46659 const EPS = 0.000001;
46660 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
46666 setFromVector3( v ) {
46668 return this.setFromCartesianCoords( v.x, v.y, v.z );
46672 setFromCartesianCoords( x, y, z ) {
46674 this.radius = Math.sqrt( x * x + y * y + z * z );
46676 if ( this.radius === 0 ) {
46683 this.theta = Math.atan2( x, z );
46684 this.phi = Math.acos( MathUtils.clamp( y / this.radius, - 1, 1 ) );
46695 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
46698 class Cylindrical {
46700 constructor( radius, theta, y ) {
46702 this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
46703 this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
46704 this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
46710 set( radius, theta, y ) {
46712 this.radius = radius;
46713 this.theta = theta;
46722 return new this.constructor().copy( this );
46728 this.radius = other.radius;
46729 this.theta = other.theta;
46736 setFromVector3( v ) {
46738 return this.setFromCartesianCoords( v.x, v.y, v.z );
46742 setFromCartesianCoords( x, y, z ) {
46744 this.radius = Math.sqrt( x * x + z * z );
46745 this.theta = Math.atan2( x, z );
46754 const _vector$7 = /*@__PURE__*/ new Vector2();
46758 constructor( min, max ) {
46760 Object.defineProperty( this, 'isBox2', { value: true } );
46762 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
46763 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
46769 this.min.copy( min );
46770 this.max.copy( max );
46776 setFromPoints( points ) {
46780 for ( let i = 0, il = points.length; i < il; i ++ ) {
46782 this.expandByPoint( points[ i ] );
46790 setFromCenterAndSize( center, size ) {
46792 const halfSize = _vector$7.copy( size ).multiplyScalar( 0.5 );
46793 this.min.copy( center ).sub( halfSize );
46794 this.max.copy( center ).add( halfSize );
46802 return new this.constructor().copy( this );
46808 this.min.copy( box.min );
46809 this.max.copy( box.max );
46817 this.min.x = this.min.y = + Infinity;
46818 this.max.x = this.max.y = - Infinity;
46826 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
46828 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
46832 getCenter( target ) {
46834 if ( target === undefined ) {
46836 console.warn( 'THREE.Box2: .getCenter() target is now required' );
46837 target = new Vector2();
46841 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
46845 getSize( target ) {
46847 if ( target === undefined ) {
46849 console.warn( 'THREE.Box2: .getSize() target is now required' );
46850 target = new Vector2();
46854 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
46858 expandByPoint( point ) {
46860 this.min.min( point );
46861 this.max.max( point );
46867 expandByVector( vector ) {
46869 this.min.sub( vector );
46870 this.max.add( vector );
46876 expandByScalar( scalar ) {
46878 this.min.addScalar( - scalar );
46879 this.max.addScalar( scalar );
46885 containsPoint( point ) {
46887 return point.x < this.min.x || point.x > this.max.x ||
46888 point.y < this.min.y || point.y > this.max.y ? false : true;
46892 containsBox( box ) {
46894 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
46895 this.min.y <= box.min.y && box.max.y <= this.max.y;
46899 getParameter( point, target ) {
46901 // This can potentially have a divide by zero if the box
46902 // has a size dimension of 0.
46904 if ( target === undefined ) {
46906 console.warn( 'THREE.Box2: .getParameter() target is now required' );
46907 target = new Vector2();
46912 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
46913 ( point.y - this.min.y ) / ( this.max.y - this.min.y )
46918 intersectsBox( box ) {
46920 // using 4 splitting planes to rule out intersections
46922 return box.max.x < this.min.x || box.min.x > this.max.x ||
46923 box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
46927 clampPoint( point, target ) {
46929 if ( target === undefined ) {
46931 console.warn( 'THREE.Box2: .clampPoint() target is now required' );
46932 target = new Vector2();
46936 return target.copy( point ).clamp( this.min, this.max );
46940 distanceToPoint( point ) {
46942 const clampedPoint = _vector$7.copy( point ).clamp( this.min, this.max );
46943 return clampedPoint.sub( point ).length();
46949 this.min.max( box.min );
46950 this.max.min( box.max );
46958 this.min.min( box.min );
46959 this.max.max( box.max );
46965 translate( offset ) {
46967 this.min.add( offset );
46968 this.max.add( offset );
46976 return box.min.equals( this.min ) && box.max.equals( this.max );
46982 const _startP = /*@__PURE__*/ new Vector3();
46983 const _startEnd = /*@__PURE__*/ new Vector3();
46987 constructor( start, end ) {
46989 this.start = ( start !== undefined ) ? start : new Vector3();
46990 this.end = ( end !== undefined ) ? end : new Vector3();
46994 set( start, end ) {
46996 this.start.copy( start );
46997 this.end.copy( end );
47005 return new this.constructor().copy( this );
47011 this.start.copy( line.start );
47012 this.end.copy( line.end );
47018 getCenter( target ) {
47020 if ( target === undefined ) {
47022 console.warn( 'THREE.Line3: .getCenter() target is now required' );
47023 target = new Vector3();
47027 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
47033 if ( target === undefined ) {
47035 console.warn( 'THREE.Line3: .delta() target is now required' );
47036 target = new Vector3();
47040 return target.subVectors( this.end, this.start );
47046 return this.start.distanceToSquared( this.end );
47052 return this.start.distanceTo( this.end );
47058 if ( target === undefined ) {
47060 console.warn( 'THREE.Line3: .at() target is now required' );
47061 target = new Vector3();
47065 return this.delta( target ).multiplyScalar( t ).add( this.start );
47069 closestPointToPointParameter( point, clampToLine ) {
47071 _startP.subVectors( point, this.start );
47072 _startEnd.subVectors( this.end, this.start );
47074 const startEnd2 = _startEnd.dot( _startEnd );
47075 const startEnd_startP = _startEnd.dot( _startP );
47077 let t = startEnd_startP / startEnd2;
47079 if ( clampToLine ) {
47081 t = MathUtils.clamp( t, 0, 1 );
47089 closestPointToPoint( point, clampToLine, target ) {
47091 const t = this.closestPointToPointParameter( point, clampToLine );
47093 if ( target === undefined ) {
47095 console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' );
47096 target = new Vector3();
47100 return this.delta( target ).multiplyScalar( t ).add( this.start );
47104 applyMatrix4( matrix ) {
47106 this.start.applyMatrix4( matrix );
47107 this.end.applyMatrix4( matrix );
47115 return line.start.equals( this.start ) && line.end.equals( this.end );
47121 function ImmediateRenderObject( material ) {
47123 Object3D.call( this );
47125 this.material = material;
47126 this.render = function ( /* renderCallback */ ) {};
47128 this.hasPositions = false;
47129 this.hasNormals = false;
47130 this.hasColors = false;
47131 this.hasUvs = false;
47133 this.positionArray = null;
47134 this.normalArray = null;
47135 this.colorArray = null;
47136 this.uvArray = null;
47142 ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
47143 ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
47145 ImmediateRenderObject.prototype.isImmediateRenderObject = true;
47147 const _vector$8 = /*@__PURE__*/ new Vector3();
47149 class SpotLightHelper extends Object3D {
47151 constructor( light, color ) {
47154 this.light = light;
47155 this.light.updateMatrixWorld();
47157 this.matrix = light.matrixWorld;
47158 this.matrixAutoUpdate = false;
47160 this.color = color;
47162 const geometry = new BufferGeometry();
47164 const positions = [
47167 0, 0, 0, - 1, 0, 1,
47172 for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
47174 const p1 = ( i / l ) * Math.PI * 2;
47175 const p2 = ( j / l ) * Math.PI * 2;
47178 Math.cos( p1 ), Math.sin( p1 ), 1,
47179 Math.cos( p2 ), Math.sin( p2 ), 1
47184 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
47186 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
47188 this.cone = new LineSegments( geometry, material );
47189 this.add( this.cone );
47197 this.cone.geometry.dispose();
47198 this.cone.material.dispose();
47204 this.light.updateMatrixWorld();
47206 const coneLength = this.light.distance ? this.light.distance : 1000;
47207 const coneWidth = coneLength * Math.tan( this.light.angle );
47209 this.cone.scale.set( coneWidth, coneWidth, coneLength );
47211 _vector$8.setFromMatrixPosition( this.light.target.matrixWorld );
47213 this.cone.lookAt( _vector$8 );
47215 if ( this.color !== undefined ) {
47217 this.cone.material.color.set( this.color );
47221 this.cone.material.color.copy( this.light.color );
47229 const _vector$9 = /*@__PURE__*/ new Vector3();
47230 const _boneMatrix = /*@__PURE__*/ new Matrix4();
47231 const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
47234 class SkeletonHelper extends LineSegments {
47236 constructor( object ) {
47238 const bones = getBoneList( object );
47240 const geometry = new BufferGeometry();
47242 const vertices = [];
47245 const color1 = new Color( 0, 0, 1 );
47246 const color2 = new Color( 0, 1, 0 );
47248 for ( let i = 0; i < bones.length; i ++ ) {
47250 const bone = bones[ i ];
47252 if ( bone.parent && bone.parent.isBone ) {
47254 vertices.push( 0, 0, 0 );
47255 vertices.push( 0, 0, 0 );
47256 colors.push( color1.r, color1.g, color1.b );
47257 colors.push( color2.r, color2.g, color2.b );
47263 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47264 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47266 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
47268 super( geometry, material );
47270 this.type = 'SkeletonHelper';
47271 this.isSkeletonHelper = true;
47273 this.root = object;
47274 this.bones = bones;
47276 this.matrix = object.matrixWorld;
47277 this.matrixAutoUpdate = false;
47281 updateMatrixWorld( force ) {
47283 const bones = this.bones;
47285 const geometry = this.geometry;
47286 const position = geometry.getAttribute( 'position' );
47288 _matrixWorldInv.copy( this.root.matrixWorld ).invert();
47290 for ( let i = 0, j = 0; i < bones.length; i ++ ) {
47292 const bone = bones[ i ];
47294 if ( bone.parent && bone.parent.isBone ) {
47296 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
47297 _vector$9.setFromMatrixPosition( _boneMatrix );
47298 position.setXYZ( j, _vector$9.x, _vector$9.y, _vector$9.z );
47300 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
47301 _vector$9.setFromMatrixPosition( _boneMatrix );
47302 position.setXYZ( j + 1, _vector$9.x, _vector$9.y, _vector$9.z );
47310 geometry.getAttribute( 'position' ).needsUpdate = true;
47312 super.updateMatrixWorld( force );
47319 function getBoneList( object ) {
47321 const boneList = [];
47323 if ( object && object.isBone ) {
47325 boneList.push( object );
47329 for ( let i = 0; i < object.children.length; i ++ ) {
47331 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
47339 class PointLightHelper extends Mesh {
47341 constructor( light, sphereSize, color ) {
47343 const geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
47344 const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
47346 super( geometry, material );
47348 this.light = light;
47349 this.light.updateMatrixWorld();
47351 this.color = color;
47353 this.type = 'PointLightHelper';
47355 this.matrix = this.light.matrixWorld;
47356 this.matrixAutoUpdate = false;
47362 // TODO: delete this comment?
47363 const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 );
47364 const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
47366 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
47367 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
47369 const d = light.distance;
47373 this.lightDistance.visible = false;
47377 this.lightDistance.scale.set( d, d, d );
47381 this.add( this.lightDistance );
47388 this.geometry.dispose();
47389 this.material.dispose();
47395 if ( this.color !== undefined ) {
47397 this.material.color.set( this.color );
47401 this.material.color.copy( this.light.color );
47406 const d = this.light.distance;
47410 this.lightDistance.visible = false;
47414 this.lightDistance.visible = true;
47415 this.lightDistance.scale.set( d, d, d );
47424 const _vector$a = /*@__PURE__*/ new Vector3();
47425 const _color1 = /*@__PURE__*/ new Color();
47426 const _color2 = /*@__PURE__*/ new Color();
47428 class HemisphereLightHelper extends Object3D {
47430 constructor( light, size, color ) {
47433 this.light = light;
47434 this.light.updateMatrixWorld();
47436 this.matrix = light.matrixWorld;
47437 this.matrixAutoUpdate = false;
47439 this.color = color;
47441 const geometry = new OctahedronBufferGeometry( size );
47442 geometry.rotateY( Math.PI * 0.5 );
47444 this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
47445 if ( this.color === undefined ) this.material.vertexColors = true;
47447 const position = geometry.getAttribute( 'position' );
47448 const colors = new Float32Array( position.count * 3 );
47450 geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
47452 this.add( new Mesh( geometry, this.material ) );
47460 this.children[ 0 ].geometry.dispose();
47461 this.children[ 0 ].material.dispose();
47467 const mesh = this.children[ 0 ];
47469 if ( this.color !== undefined ) {
47471 this.material.color.set( this.color );
47475 const colors = mesh.geometry.getAttribute( 'color' );
47477 _color1.copy( this.light.color );
47478 _color2.copy( this.light.groundColor );
47480 for ( let i = 0, l = colors.count; i < l; i ++ ) {
47482 const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
47484 colors.setXYZ( i, color.r, color.g, color.b );
47488 colors.needsUpdate = true;
47492 mesh.lookAt( _vector$a.setFromMatrixPosition( this.light.matrixWorld ).negate() );
47498 class GridHelper extends LineSegments {
47500 constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
47502 color1 = new Color( color1 );
47503 color2 = new Color( color2 );
47505 const center = divisions / 2;
47506 const step = size / divisions;
47507 const halfSize = size / 2;
47509 const vertices = [], colors = [];
47511 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
47513 vertices.push( - halfSize, 0, k, halfSize, 0, k );
47514 vertices.push( k, 0, - halfSize, k, 0, halfSize );
47516 const color = i === center ? color1 : color2;
47518 color.toArray( colors, j ); j += 3;
47519 color.toArray( colors, j ); j += 3;
47520 color.toArray( colors, j ); j += 3;
47521 color.toArray( colors, j ); j += 3;
47525 const geometry = new BufferGeometry();
47526 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47527 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47529 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
47531 super( geometry, material );
47533 this.type = 'GridHelper';
47539 class PolarGridHelper extends LineSegments {
47541 constructor( radius = 10, radials = 16, circles = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
47543 color1 = new Color( color1 );
47544 color2 = new Color( color2 );
47546 const vertices = [];
47549 // create the radials
47551 for ( let i = 0; i <= radials; i ++ ) {
47553 const v = ( i / radials ) * ( Math.PI * 2 );
47555 const x = Math.sin( v ) * radius;
47556 const z = Math.cos( v ) * radius;
47558 vertices.push( 0, 0, 0 );
47559 vertices.push( x, 0, z );
47561 const color = ( i & 1 ) ? color1 : color2;
47563 colors.push( color.r, color.g, color.b );
47564 colors.push( color.r, color.g, color.b );
47568 // create the circles
47570 for ( let i = 0; i <= circles; i ++ ) {
47572 const color = ( i & 1 ) ? color1 : color2;
47574 const r = radius - ( radius / circles * i );
47576 for ( let j = 0; j < divisions; j ++ ) {
47580 let v = ( j / divisions ) * ( Math.PI * 2 );
47582 let x = Math.sin( v ) * r;
47583 let z = Math.cos( v ) * r;
47585 vertices.push( x, 0, z );
47586 colors.push( color.r, color.g, color.b );
47590 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
47592 x = Math.sin( v ) * r;
47593 z = Math.cos( v ) * r;
47595 vertices.push( x, 0, z );
47596 colors.push( color.r, color.g, color.b );
47602 const geometry = new BufferGeometry();
47603 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47604 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47606 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
47608 super( geometry, material );
47610 this.type = 'PolarGridHelper';
47616 const _v1$6 = /*@__PURE__*/ new Vector3();
47617 const _v2$3 = /*@__PURE__*/ new Vector3();
47618 const _v3$1 = /*@__PURE__*/ new Vector3();
47620 class DirectionalLightHelper extends Object3D {
47622 constructor( light, size, color ) {
47625 this.light = light;
47626 this.light.updateMatrixWorld();
47628 this.matrix = light.matrixWorld;
47629 this.matrixAutoUpdate = false;
47631 this.color = color;
47633 if ( size === undefined ) size = 1;
47635 let geometry = new BufferGeometry();
47636 geometry.setAttribute( 'position', new Float32BufferAttribute( [
47644 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
47646 this.lightPlane = new Line( geometry, material );
47647 this.add( this.lightPlane );
47649 geometry = new BufferGeometry();
47650 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
47652 this.targetLine = new Line( geometry, material );
47653 this.add( this.targetLine );
47661 this.lightPlane.geometry.dispose();
47662 this.lightPlane.material.dispose();
47663 this.targetLine.geometry.dispose();
47664 this.targetLine.material.dispose();
47670 _v1$6.setFromMatrixPosition( this.light.matrixWorld );
47671 _v2$3.setFromMatrixPosition( this.light.target.matrixWorld );
47672 _v3$1.subVectors( _v2$3, _v1$6 );
47674 this.lightPlane.lookAt( _v2$3 );
47676 if ( this.color !== undefined ) {
47678 this.lightPlane.material.color.set( this.color );
47679 this.targetLine.material.color.set( this.color );
47683 this.lightPlane.material.color.copy( this.light.color );
47684 this.targetLine.material.color.copy( this.light.color );
47688 this.targetLine.lookAt( _v2$3 );
47689 this.targetLine.scale.z = _v3$1.length();
47695 const _vector$b = /*@__PURE__*/ new Vector3();
47696 const _camera = /*@__PURE__*/ new Camera();
47699 * - shows frustum, line of sight and up of the camera
47700 * - suitable for fast updates
47701 * - based on frustum visualization in lightgl.js shadowmap example
47702 * http://evanw.github.com/lightgl.js/tests/shadowmap.html
47705 class CameraHelper extends LineSegments {
47707 constructor( camera ) {
47709 const geometry = new BufferGeometry();
47710 const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
47712 const vertices = [];
47715 const pointMap = {};
47719 const colorFrustum = new Color( 0xffaa00 );
47720 const colorCone = new Color( 0xff0000 );
47721 const colorUp = new Color( 0x00aaff );
47722 const colorTarget = new Color( 0xffffff );
47723 const colorCross = new Color( 0x333333 );
47727 addLine( 'n1', 'n2', colorFrustum );
47728 addLine( 'n2', 'n4', colorFrustum );
47729 addLine( 'n4', 'n3', colorFrustum );
47730 addLine( 'n3', 'n1', colorFrustum );
47734 addLine( 'f1', 'f2', colorFrustum );
47735 addLine( 'f2', 'f4', colorFrustum );
47736 addLine( 'f4', 'f3', colorFrustum );
47737 addLine( 'f3', 'f1', colorFrustum );
47741 addLine( 'n1', 'f1', colorFrustum );
47742 addLine( 'n2', 'f2', colorFrustum );
47743 addLine( 'n3', 'f3', colorFrustum );
47744 addLine( 'n4', 'f4', colorFrustum );
47748 addLine( 'p', 'n1', colorCone );
47749 addLine( 'p', 'n2', colorCone );
47750 addLine( 'p', 'n3', colorCone );
47751 addLine( 'p', 'n4', colorCone );
47755 addLine( 'u1', 'u2', colorUp );
47756 addLine( 'u2', 'u3', colorUp );
47757 addLine( 'u3', 'u1', colorUp );
47761 addLine( 'c', 't', colorTarget );
47762 addLine( 'p', 'c', colorCross );
47766 addLine( 'cn1', 'cn2', colorCross );
47767 addLine( 'cn3', 'cn4', colorCross );
47769 addLine( 'cf1', 'cf2', colorCross );
47770 addLine( 'cf3', 'cf4', colorCross );
47772 function addLine( a, b, color ) {
47774 addPoint( a, color );
47775 addPoint( b, color );
47779 function addPoint( id, color ) {
47781 vertices.push( 0, 0, 0 );
47782 colors.push( color.r, color.g, color.b );
47784 if ( pointMap[ id ] === undefined ) {
47786 pointMap[ id ] = [];
47790 pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
47794 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47795 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47797 super( geometry, material );
47799 this.type = 'CameraHelper';
47801 this.camera = camera;
47802 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
47804 this.matrix = camera.matrixWorld;
47805 this.matrixAutoUpdate = false;
47807 this.pointMap = pointMap;
47815 const geometry = this.geometry;
47816 const pointMap = this.pointMap;
47818 const w = 1, h = 1;
47820 // we need just camera projection matrix inverse
47821 // world matrix must be identity
47823 _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
47827 setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
47828 setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
47832 setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
47833 setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
47834 setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
47835 setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
47839 setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
47840 setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
47841 setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
47842 setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
47846 setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
47847 setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
47848 setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
47852 setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
47853 setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
47854 setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
47855 setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
47857 setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
47858 setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
47859 setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
47860 setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
47862 geometry.getAttribute( 'position' ).needsUpdate = true;
47869 function setPoint( point, pointMap, geometry, camera, x, y, z ) {
47871 _vector$b.set( x, y, z ).unproject( camera );
47873 const points = pointMap[ point ];
47875 if ( points !== undefined ) {
47877 const position = geometry.getAttribute( 'position' );
47879 for ( let i = 0, l = points.length; i < l; i ++ ) {
47881 position.setXYZ( points[ i ], _vector$b.x, _vector$b.y, _vector$b.z );
47889 const _box$3 = /*@__PURE__*/ new Box3();
47891 class BoxHelper extends LineSegments {
47893 constructor( object, color = 0xffff00 ) {
47895 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 ] );
47896 const positions = new Float32Array( 8 * 3 );
47898 const geometry = new BufferGeometry();
47899 geometry.setIndex( new BufferAttribute( indices, 1 ) );
47900 geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
47902 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
47904 this.object = object;
47905 this.type = 'BoxHelper';
47907 this.matrixAutoUpdate = false;
47915 if ( object !== undefined ) {
47917 console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
47921 if ( this.object !== undefined ) {
47923 _box$3.setFromObject( this.object );
47927 if ( _box$3.isEmpty() ) return;
47929 const min = _box$3.min;
47930 const max = _box$3.max;
47938 0: max.x, max.y, max.z
47939 1: min.x, max.y, max.z
47940 2: min.x, min.y, max.z
47941 3: max.x, min.y, max.z
47942 4: max.x, max.y, min.z
47943 5: min.x, max.y, min.z
47944 6: min.x, min.y, min.z
47945 7: max.x, min.y, min.z
47948 const position = this.geometry.attributes.position;
47949 const array = position.array;
47951 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
47952 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
47953 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
47954 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
47955 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
47956 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
47957 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
47958 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
47960 position.needsUpdate = true;
47962 this.geometry.computeBoundingSphere();
47967 setFromObject( object ) {
47969 this.object = object;
47978 LineSegments.prototype.copy.call( this, source );
47980 this.object = source.object;
47988 class Box3Helper extends LineSegments {
47990 constructor( box, color = 0xffff00 ) {
47992 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 ] );
47994 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 ];
47996 const geometry = new BufferGeometry();
47998 geometry.setIndex( new BufferAttribute( indices, 1 ) );
48000 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
48002 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
48006 this.type = 'Box3Helper';
48008 this.geometry.computeBoundingSphere();
48012 updateMatrixWorld( force ) {
48014 const box = this.box;
48016 if ( box.isEmpty() ) return;
48018 box.getCenter( this.position );
48020 box.getSize( this.scale );
48022 this.scale.multiplyScalar( 0.5 );
48024 super.updateMatrixWorld( force );
48030 class PlaneHelper extends Line {
48032 constructor( plane, size = 1, hex = 0xffff00 ) {
48036 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 ];
48038 const geometry = new BufferGeometry();
48039 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
48040 geometry.computeBoundingSphere();
48042 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
48044 this.type = 'PlaneHelper';
48046 this.plane = plane;
48050 const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
48052 const geometry2 = new BufferGeometry();
48053 geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
48054 geometry2.computeBoundingSphere();
48056 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
48060 updateMatrixWorld( force ) {
48062 let scale = - this.plane.constant;
48064 if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
48066 this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
48068 this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
48070 this.lookAt( this.plane.normal );
48072 super.updateMatrixWorld( force );
48078 const _axis = /*@__PURE__*/ new Vector3();
48079 let _lineGeometry, _coneGeometry;
48081 class ArrowHelper extends Object3D {
48083 constructor( dir, origin, length, color, headLength, headWidth ) {
48086 // dir is assumed to be normalized
48088 this.type = 'ArrowHelper';
48090 if ( dir === undefined ) dir = new Vector3( 0, 0, 1 );
48091 if ( origin === undefined ) origin = new Vector3( 0, 0, 0 );
48092 if ( length === undefined ) length = 1;
48093 if ( color === undefined ) color = 0xffff00;
48094 if ( headLength === undefined ) headLength = 0.2 * length;
48095 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
48097 if ( _lineGeometry === undefined ) {
48099 _lineGeometry = new BufferGeometry();
48100 _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
48102 _coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
48103 _coneGeometry.translate( 0, - 0.5, 0 );
48107 this.position.copy( origin );
48109 this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
48110 this.line.matrixAutoUpdate = false;
48111 this.add( this.line );
48113 this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
48114 this.cone.matrixAutoUpdate = false;
48115 this.add( this.cone );
48117 this.setDirection( dir );
48118 this.setLength( length, headLength, headWidth );
48122 setDirection( dir ) {
48124 // dir is assumed to be normalized
48126 if ( dir.y > 0.99999 ) {
48128 this.quaternion.set( 0, 0, 0, 1 );
48130 } else if ( dir.y < - 0.99999 ) {
48132 this.quaternion.set( 1, 0, 0, 0 );
48136 _axis.set( dir.z, 0, - dir.x ).normalize();
48138 const radians = Math.acos( dir.y );
48140 this.quaternion.setFromAxisAngle( _axis, radians );
48146 setLength( length, headLength, headWidth ) {
48148 if ( headLength === undefined ) headLength = 0.2 * length;
48149 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
48151 this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
48152 this.line.updateMatrix();
48154 this.cone.scale.set( headWidth, headLength, headWidth );
48155 this.cone.position.y = length;
48156 this.cone.updateMatrix();
48160 setColor( color ) {
48162 this.line.material.color.set( color );
48163 this.cone.material.color.set( color );
48169 super.copy( source, false );
48171 this.line.copy( source.line );
48172 this.cone.copy( source.cone );
48180 class AxesHelper extends LineSegments {
48182 constructor( size = 1 ) {
48185 0, 0, 0, size, 0, 0,
48186 0, 0, 0, 0, size, 0,
48187 0, 0, 0, 0, 0, size
48191 1, 0, 0, 1, 0.6, 0,
48192 0, 1, 0, 0.6, 1, 0,
48196 const geometry = new BufferGeometry();
48197 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
48198 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
48200 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
48202 super( geometry, material );
48204 this.type = 'AxesHelper';
48210 const _floatView = new Float32Array( 1 );
48211 const _int32View = new Int32Array( _floatView.buffer );
48213 const DataUtils = {
48215 // Converts float32 to float16 (stored as uint16 value).
48217 toHalfFloat: function ( val ) {
48219 // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
48221 /* This method is faster than the OpenEXR implementation (very often
48222 * used, eg. in Ogre), with the additional benefit of rounding, inspired
48223 * by James Tursa?s half-precision code. */
48225 _floatView[ 0 ] = val;
48226 const x = _int32View[ 0 ];
48228 let bits = ( x >> 16 ) & 0x8000; /* Get the sign */
48229 let m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
48230 const e = ( x >> 23 ) & 0xff; /* Using int is faster here */
48232 /* If zero, or denormal, or exponent underflows too much for a denormal
48233 * half, return signed zero. */
48234 if ( e < 103 ) return bits;
48236 /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
48240 /* If exponent was 0xff and one mantissa bit was set, it means NaN,
48241 * not Inf, so make sure we set one mantissa bit too. */
48242 bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
48247 /* If exponent underflows but not too much, return a denormal */
48251 /* Extra rounding may overflow and set mantissa to 0 and exponent
48252 * to 1, which is OK. */
48253 bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
48258 bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
48259 /* Extra rounding. An overflow will set mantissa to 0 and increment
48260 * the exponent, which is OK. */
48270 const SIZE_MAX = Math.pow( 2, LOD_MAX );
48272 // The standard deviations (radians) associated with the extra mips. These are
48273 // chosen to approximate a Trowbridge-Reitz distribution function times the
48274 // geometric shadowing function. These sigma values squared must match the
48275 // variance #defines in cube_uv_reflection_fragment.glsl.js.
48276 const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
48278 const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
48280 // The maximum length of the blur for loop. Smaller sigmas will use fewer
48281 // samples and exit early, but not recompile the shader.
48282 const MAX_SAMPLES = 20;
48284 const ENCODINGS = {
48285 [ LinearEncoding ]: 0,
48286 [ sRGBEncoding ]: 1,
48287 [ RGBEEncoding ]: 2,
48288 [ RGBM7Encoding ]: 3,
48289 [ RGBM16Encoding ]: 4,
48290 [ RGBDEncoding ]: 5,
48291 [ GammaEncoding ]: 6
48294 const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
48295 const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
48296 let _oldTarget = null;
48299 const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
48300 const INV_PHI = 1 / PHI;
48302 // Vertices of a dodecahedron (except the opposites, which represent the
48303 // same axis), used as axis directions evenly spread on a sphere.
48304 const _axisDirections = [
48305 /*@__PURE__*/ new Vector3( 1, 1, 1 ),
48306 /*@__PURE__*/ new Vector3( - 1, 1, 1 ),
48307 /*@__PURE__*/ new Vector3( 1, 1, - 1 ),
48308 /*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
48309 /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
48310 /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
48311 /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
48312 /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
48313 /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
48314 /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
48317 * This class generates a Prefiltered, Mipmapped Radiance Environment Map
48318 * (PMREM) from a cubeMap environment texture. This allows different levels of
48319 * blur to be quickly accessed based on material roughness. It is packed into a
48320 * special CubeUV format that allows us to perform custom interpolation so that
48321 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
48322 * chain, it only goes down to the LOD_MIN level (above), and then creates extra
48323 * even more filtered 'mips' at the same LOD_MIN resolution, associated with
48324 * higher roughness levels. In this way we maintain resolution to smoothly
48325 * interpolate diffuse lighting while limiting sampling computation.
48328 class PMREMGenerator {
48330 constructor( renderer ) {
48332 this._renderer = renderer;
48333 this._pingPongRenderTarget = null;
48335 this._blurMaterial = _getBlurShader( MAX_SAMPLES );
48336 this._equirectShader = null;
48337 this._cubemapShader = null;
48339 this._compileMaterial( this._blurMaterial );
48344 * Generates a PMREM from a supplied Scene, which can be faster than using an
48345 * image if networking bandwidth is low. Optional sigma specifies a blur radius
48346 * in radians to be applied to the scene before PMREM generation. Optional near
48347 * and far planes ensure the scene is rendered in its entirety (the cubeCamera
48348 * is placed at the origin).
48350 fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
48352 _oldTarget = this._renderer.getRenderTarget();
48353 const cubeUVRenderTarget = this._allocateTargets();
48355 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
48358 this._blur( cubeUVRenderTarget, 0, 0, sigma );
48362 this._applyPMREM( cubeUVRenderTarget );
48363 this._cleanup( cubeUVRenderTarget );
48365 return cubeUVRenderTarget;
48370 * Generates a PMREM from an equirectangular texture, which can be either LDR
48371 * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
48372 * as this matches best with the 256 x 256 cubemap output.
48374 fromEquirectangular( equirectangular ) {
48376 return this._fromTexture( equirectangular );
48381 * Generates a PMREM from an cubemap texture, which can be either LDR
48382 * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
48383 * as this matches best with the 256 x 256 cubemap output.
48385 fromCubemap( cubemap ) {
48387 return this._fromTexture( cubemap );
48392 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
48393 * your texture's network fetch for increased concurrency.
48395 compileCubemapShader() {
48397 if ( this._cubemapShader === null ) {
48399 this._cubemapShader = _getCubemapShader();
48400 this._compileMaterial( this._cubemapShader );
48407 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
48408 * your texture's network fetch for increased concurrency.
48410 compileEquirectangularShader() {
48412 if ( this._equirectShader === null ) {
48414 this._equirectShader = _getEquirectShader();
48415 this._compileMaterial( this._equirectShader );
48422 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
48423 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
48424 * one of them will cause any others to also become unusable.
48428 this._blurMaterial.dispose();
48430 if ( this._cubemapShader !== null ) this._cubemapShader.dispose();
48431 if ( this._equirectShader !== null ) this._equirectShader.dispose();
48433 for ( let i = 0; i < _lodPlanes.length; i ++ ) {
48435 _lodPlanes[ i ].dispose();
48441 // private interface
48443 _cleanup( outputTarget ) {
48445 this._pingPongRenderTarget.dispose();
48446 this._renderer.setRenderTarget( _oldTarget );
48447 outputTarget.scissorTest = false;
48448 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
48452 _fromTexture( texture ) {
48454 _oldTarget = this._renderer.getRenderTarget();
48455 const cubeUVRenderTarget = this._allocateTargets( texture );
48456 this._textureToCubeUV( texture, cubeUVRenderTarget );
48457 this._applyPMREM( cubeUVRenderTarget );
48458 this._cleanup( cubeUVRenderTarget );
48460 return cubeUVRenderTarget;
48464 _allocateTargets( texture ) { // warning: null texture is valid
48467 magFilter: NearestFilter,
48468 minFilter: NearestFilter,
48469 generateMipmaps: false,
48470 type: UnsignedByteType,
48471 format: RGBEFormat,
48472 encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding,
48476 const cubeUVRenderTarget = _createRenderTarget( params );
48477 cubeUVRenderTarget.depthBuffer = texture ? false : true;
48478 this._pingPongRenderTarget = _createRenderTarget( params );
48479 return cubeUVRenderTarget;
48483 _compileMaterial( material ) {
48485 const tmpMesh = new Mesh( _lodPlanes[ 0 ], material );
48486 this._renderer.compile( tmpMesh, _flatCamera );
48490 _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
48494 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
48495 const upSign = [ 1, - 1, 1, 1, 1, 1 ];
48496 const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
48497 const renderer = this._renderer;
48499 const outputEncoding = renderer.outputEncoding;
48500 const toneMapping = renderer.toneMapping;
48501 const clearColor = renderer.getClearColor();
48502 const clearAlpha = renderer.getClearAlpha();
48504 renderer.toneMapping = NoToneMapping;
48505 renderer.outputEncoding = LinearEncoding;
48507 let background = scene.background;
48508 if ( background && background.isColor ) {
48510 background.convertSRGBToLinear();
48511 // Convert linear to RGBE
48512 const maxComponent = Math.max( background.r, background.g, background.b );
48513 const fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 );
48514 background = background.multiplyScalar( Math.pow( 2.0, - fExp ) );
48515 const alpha = ( fExp + 128.0 ) / 255.0;
48516 renderer.setClearColor( background, alpha );
48517 scene.background = null;
48521 for ( let i = 0; i < 6; i ++ ) {
48526 cubeCamera.up.set( 0, upSign[ i ], 0 );
48527 cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
48529 } else if ( col == 1 ) {
48531 cubeCamera.up.set( 0, 0, upSign[ i ] );
48532 cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
48536 cubeCamera.up.set( 0, upSign[ i ], 0 );
48537 cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
48541 _setViewport( cubeUVRenderTarget,
48542 col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX );
48543 renderer.setRenderTarget( cubeUVRenderTarget );
48544 renderer.render( scene, cubeCamera );
48548 renderer.toneMapping = toneMapping;
48549 renderer.outputEncoding = outputEncoding;
48550 renderer.setClearColor( clearColor, clearAlpha );
48554 _textureToCubeUV( texture, cubeUVRenderTarget ) {
48556 const renderer = this._renderer;
48558 if ( texture.isCubeTexture ) {
48560 if ( this._cubemapShader == null ) {
48562 this._cubemapShader = _getCubemapShader();
48568 if ( this._equirectShader == null ) {
48570 this._equirectShader = _getEquirectShader();
48576 const material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader;
48577 const mesh = new Mesh( _lodPlanes[ 0 ], material );
48579 const uniforms = material.uniforms;
48581 uniforms[ 'envMap' ].value = texture;
48583 if ( ! texture.isCubeTexture ) {
48585 uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height );
48589 uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ];
48590 uniforms[ 'outputEncoding' ].value = ENCODINGS[ cubeUVRenderTarget.texture.encoding ];
48592 _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
48594 renderer.setRenderTarget( cubeUVRenderTarget );
48595 renderer.render( mesh, _flatCamera );
48599 _applyPMREM( cubeUVRenderTarget ) {
48601 const renderer = this._renderer;
48602 const autoClear = renderer.autoClear;
48603 renderer.autoClear = false;
48605 for ( let i = 1; i < TOTAL_LODS; i ++ ) {
48607 const sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] );
48609 const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
48611 this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
48615 renderer.autoClear = autoClear;
48620 * This is a two-pass Gaussian blur for a cubemap. Normally this is done
48621 * vertically and horizontally, but this breaks down on a cube. Here we apply
48622 * the blur latitudinally (around the poles), and then longitudinally (towards
48623 * the poles) to approximate the orthogonally-separable blur. It is least
48624 * accurate at the poles, but still does a decent job.
48626 _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
48628 const pingPongRenderTarget = this._pingPongRenderTarget;
48631 cubeUVRenderTarget,
48632 pingPongRenderTarget,
48640 pingPongRenderTarget,
48641 cubeUVRenderTarget,
48650 _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
48652 const renderer = this._renderer;
48653 const blurMaterial = this._blurMaterial;
48655 if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
48658 'blur direction must be either latitudinal or longitudinal!' );
48662 // Number of standard deviations at which to cut off the discrete approximation.
48663 const STANDARD_DEVIATIONS = 3;
48665 const blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial );
48666 const blurUniforms = blurMaterial.uniforms;
48668 const pixels = _sizeLods[ lodIn ] - 1;
48669 const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
48670 const sigmaPixels = sigmaRadians / radiansPerPixel;
48671 const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
48673 if ( samples > MAX_SAMPLES ) {
48675 console.warn( `sigmaRadians, ${
48676 sigmaRadians}, is too large and will clip, as it requested ${
48677 samples} samples when the maximum is set to ${MAX_SAMPLES}` );
48681 const weights = [];
48684 for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
48686 const x = i / sigmaPixels;
48687 const weight = Math.exp( - x * x / 2 );
48688 weights.push( weight );
48694 } else if ( i < samples ) {
48702 for ( let i = 0; i < weights.length; i ++ ) {
48704 weights[ i ] = weights[ i ] / sum;
48708 blurUniforms[ 'envMap' ].value = targetIn.texture;
48709 blurUniforms[ 'samples' ].value = samples;
48710 blurUniforms[ 'weights' ].value = weights;
48711 blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
48715 blurUniforms[ 'poleAxis' ].value = poleAxis;
48719 blurUniforms[ 'dTheta' ].value = radiansPerPixel;
48720 blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
48721 blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
48722 blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
48724 const outputSize = _sizeLods[ lodOut ];
48725 const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );
48726 const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 );
48728 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
48729 renderer.setRenderTarget( targetOut );
48730 renderer.render( blurMesh, _flatCamera );
48736 function _isLDR( texture ) {
48738 if ( texture === undefined || texture.type !== UnsignedByteType ) return false;
48740 return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding;
48744 function _createPlanes() {
48746 const _lodPlanes = [];
48747 const _sizeLods = [];
48748 const _sigmas = [];
48752 for ( let i = 0; i < TOTAL_LODS; i ++ ) {
48754 const sizeLod = Math.pow( 2, lod );
48755 _sizeLods.push( sizeLod );
48756 let sigma = 1.0 / sizeLod;
48758 if ( i > LOD_MAX - LOD_MIN ) {
48760 sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ];
48762 } else if ( i == 0 ) {
48768 _sigmas.push( sigma );
48770 const texelSize = 1.0 / ( sizeLod - 1 );
48771 const min = - texelSize / 2;
48772 const max = 1 + texelSize / 2;
48773 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
48775 const cubeFaces = 6;
48776 const vertices = 6;
48777 const positionSize = 3;
48779 const faceIndexSize = 1;
48781 const position = new Float32Array( positionSize * vertices * cubeFaces );
48782 const uv = new Float32Array( uvSize * vertices * cubeFaces );
48783 const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
48785 for ( let face = 0; face < cubeFaces; face ++ ) {
48787 const x = ( face % 3 ) * 2 / 3 - 1;
48788 const y = face > 2 ? 0 : - 1;
48789 const coordinates = [
48792 x + 2 / 3, y + 1, 0,
48794 x + 2 / 3, y + 1, 0,
48797 position.set( coordinates, positionSize * vertices * face );
48798 uv.set( uv1, uvSize * vertices * face );
48799 const fill = [ face, face, face, face, face, face ];
48800 faceIndex.set( fill, faceIndexSize * vertices * face );
48804 const planes = new BufferGeometry();
48805 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
48806 planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
48807 planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
48808 _lodPlanes.push( planes );
48810 if ( lod > LOD_MIN ) {
48818 return { _lodPlanes, _sizeLods, _sigmas };
48822 function _createRenderTarget( params ) {
48824 const cubeUVRenderTarget = new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params );
48825 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
48826 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
48827 cubeUVRenderTarget.scissorTest = true;
48828 return cubeUVRenderTarget;
48832 function _setViewport( target, x, y, width, height ) {
48834 target.viewport.set( x, y, width, height );
48835 target.scissor.set( x, y, width, height );
48839 function _getBlurShader( maxSamples ) {
48841 const weights = new Float32Array( maxSamples );
48842 const poleAxis = new Vector3( 0, 1, 0 );
48843 const shaderMaterial = new RawShaderMaterial( {
48845 name: 'SphericalGaussianBlur',
48847 defines: { 'n': maxSamples },
48850 'envMap': { value: null },
48851 'samples': { value: 1 },
48852 'weights': { value: weights },
48853 'latitudinal': { value: false },
48854 'dTheta': { value: 0 },
48855 'mipInt': { value: 0 },
48856 'poleAxis': { value: poleAxis },
48857 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
48858 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
48861 vertexShader: _getCommonVertexShader(),
48863 fragmentShader: /* glsl */`
48865 precision mediump float;
48866 precision mediump int;
48868 varying vec3 vOutputDirection;
48870 uniform sampler2D envMap;
48871 uniform int samples;
48872 uniform float weights[ n ];
48873 uniform bool latitudinal;
48874 uniform float dTheta;
48875 uniform float mipInt;
48876 uniform vec3 poleAxis;
48878 ${ _getEncodings() }
48880 #define ENVMAP_TYPE_CUBE_UV
48881 #include <cube_uv_reflection_fragment>
48883 vec3 getSample( float theta, vec3 axis ) {
48885 float cosTheta = cos( theta );
48886 // Rodrigues' axis-angle rotation
48887 vec3 sampleDirection = vOutputDirection * cosTheta
48888 + cross( axis, vOutputDirection ) * sin( theta )
48889 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
48891 return bilinearCubeUV( envMap, sampleDirection, mipInt );
48897 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
48899 if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
48901 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
48905 axis = normalize( axis );
48907 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
48908 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
48910 for ( int i = 1; i < n; i++ ) {
48912 if ( i >= samples ) {
48918 float theta = dTheta * float( i );
48919 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
48920 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
48924 gl_FragColor = linearToOutputTexel( gl_FragColor );
48929 blending: NoBlending,
48935 return shaderMaterial;
48939 function _getEquirectShader() {
48941 const texelSize = new Vector2( 1, 1 );
48942 const shaderMaterial = new RawShaderMaterial( {
48944 name: 'EquirectangularToCubeUV',
48947 'envMap': { value: null },
48948 'texelSize': { value: texelSize },
48949 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
48950 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
48953 vertexShader: _getCommonVertexShader(),
48955 fragmentShader: /* glsl */`
48957 precision mediump float;
48958 precision mediump int;
48960 varying vec3 vOutputDirection;
48962 uniform sampler2D envMap;
48963 uniform vec2 texelSize;
48965 ${ _getEncodings() }
48971 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
48973 vec3 outputDirection = normalize( vOutputDirection );
48974 vec2 uv = equirectUv( outputDirection );
48976 vec2 f = fract( uv / texelSize - 0.5 );
48977 uv -= f * texelSize;
48978 vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
48979 uv.x += texelSize.x;
48980 vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
48981 uv.y += texelSize.y;
48982 vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
48983 uv.x -= texelSize.x;
48984 vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
48986 vec3 tm = mix( tl, tr, f.x );
48987 vec3 bm = mix( bl, br, f.x );
48988 gl_FragColor.rgb = mix( tm, bm, f.y );
48990 gl_FragColor = linearToOutputTexel( gl_FragColor );
48995 blending: NoBlending,
49001 return shaderMaterial;
49005 function _getCubemapShader() {
49007 const shaderMaterial = new RawShaderMaterial( {
49009 name: 'CubemapToCubeUV',
49012 'envMap': { value: null },
49013 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
49014 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
49017 vertexShader: _getCommonVertexShader(),
49019 fragmentShader: /* glsl */`
49021 precision mediump float;
49022 precision mediump int;
49024 varying vec3 vOutputDirection;
49026 uniform samplerCube envMap;
49028 ${ _getEncodings() }
49032 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
49033 gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;
49034 gl_FragColor = linearToOutputTexel( gl_FragColor );
49039 blending: NoBlending,
49045 return shaderMaterial;
49049 function _getCommonVertexShader() {
49053 precision mediump float;
49054 precision mediump int;
49056 attribute vec3 position;
49058 attribute float faceIndex;
49060 varying vec3 vOutputDirection;
49062 // RH coordinate system; PMREM face-indexing convention
49063 vec3 getDirection( vec2 uv, float face ) {
49065 uv = 2.0 * uv - 1.0;
49067 vec3 direction = vec3( uv, 1.0 );
49069 if ( face == 0.0 ) {
49071 direction = direction.zyx; // ( 1, v, u ) pos x
49073 } else if ( face == 1.0 ) {
49075 direction = direction.xzy;
49076 direction.xz *= -1.0; // ( -u, 1, -v ) pos y
49078 } else if ( face == 2.0 ) {
49080 direction.x *= -1.0; // ( -u, v, 1 ) pos z
49082 } else if ( face == 3.0 ) {
49084 direction = direction.zyx;
49085 direction.xz *= -1.0; // ( -1, v, -u ) neg x
49087 } else if ( face == 4.0 ) {
49089 direction = direction.xzy;
49090 direction.xy *= -1.0; // ( -u, -1, v ) neg y
49092 } else if ( face == 5.0 ) {
49094 direction.z *= -1.0; // ( u, v, -1 ) neg z
49104 vOutputDirection = getDirection( uv, faceIndex );
49105 gl_Position = vec4( position, 1.0 );
49112 function _getEncodings() {
49116 uniform int inputEncoding;
49117 uniform int outputEncoding;
49119 #include <encodings_pars_fragment>
49121 vec4 inputTexelToLinear( vec4 value ) {
49123 if ( inputEncoding == 0 ) {
49127 } else if ( inputEncoding == 1 ) {
49129 return sRGBToLinear( value );
49131 } else if ( inputEncoding == 2 ) {
49133 return RGBEToLinear( value );
49135 } else if ( inputEncoding == 3 ) {
49137 return RGBMToLinear( value, 7.0 );
49139 } else if ( inputEncoding == 4 ) {
49141 return RGBMToLinear( value, 16.0 );
49143 } else if ( inputEncoding == 5 ) {
49145 return RGBDToLinear( value, 256.0 );
49149 return GammaToLinear( value, 2.2 );
49155 vec4 linearToOutputTexel( vec4 value ) {
49157 if ( outputEncoding == 0 ) {
49161 } else if ( outputEncoding == 1 ) {
49163 return LinearTosRGB( value );
49165 } else if ( outputEncoding == 2 ) {
49167 return LinearToRGBE( value );
49169 } else if ( outputEncoding == 3 ) {
49171 return LinearToRGBM( value, 7.0 );
49173 } else if ( outputEncoding == 4 ) {
49175 return LinearToRGBM( value, 16.0 );
49177 } else if ( outputEncoding == 5 ) {
49179 return LinearToRGBD( value, 256.0 );
49183 return LinearToGamma( value, 2.2 );
49189 vec4 envMapTexelToLinear( vec4 color ) {
49191 return inputTexelToLinear( color );
49198 function Face4( a, b, c, d, normal, color, materialIndex ) {
49200 console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
49201 return new Face3( a, b, c, normal, color, materialIndex );
49205 const LineStrip = 0;
49206 const LinePieces = 1;
49207 const NoColors = 0;
49208 const FaceColors = 1;
49209 const VertexColors = 2;
49211 function MeshFaceMaterial( materials ) {
49213 console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );
49218 function MultiMaterial( materials = [] ) {
49220 console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );
49221 materials.isMultiMaterial = true;
49222 materials.materials = materials;
49223 materials.clone = function () {
49225 return materials.slice();
49233 function PointCloud( geometry, material ) {
49235 console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
49236 return new Points( geometry, material );
49240 function Particle( material ) {
49242 console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
49243 return new Sprite( material );
49247 function ParticleSystem( geometry, material ) {
49249 console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
49250 return new Points( geometry, material );
49254 function PointCloudMaterial( parameters ) {
49256 console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
49257 return new PointsMaterial( parameters );
49261 function ParticleBasicMaterial( parameters ) {
49263 console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
49264 return new PointsMaterial( parameters );
49268 function ParticleSystemMaterial( parameters ) {
49270 console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
49271 return new PointsMaterial( parameters );
49275 function Vertex( x, y, z ) {
49277 console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
49278 return new Vector3( x, y, z );
49284 function DynamicBufferAttribute( array, itemSize ) {
49286 console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead.' );
49287 return new BufferAttribute( array, itemSize ).setUsage( DynamicDrawUsage );
49291 function Int8Attribute( array, itemSize ) {
49293 console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
49294 return new Int8BufferAttribute( array, itemSize );
49298 function Uint8Attribute( array, itemSize ) {
49300 console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
49301 return new Uint8BufferAttribute( array, itemSize );
49305 function Uint8ClampedAttribute( array, itemSize ) {
49307 console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
49308 return new Uint8ClampedBufferAttribute( array, itemSize );
49312 function Int16Attribute( array, itemSize ) {
49314 console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
49315 return new Int16BufferAttribute( array, itemSize );
49319 function Uint16Attribute( array, itemSize ) {
49321 console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
49322 return new Uint16BufferAttribute( array, itemSize );
49326 function Int32Attribute( array, itemSize ) {
49328 console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
49329 return new Int32BufferAttribute( array, itemSize );
49333 function Uint32Attribute( array, itemSize ) {
49335 console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
49336 return new Uint32BufferAttribute( array, itemSize );
49340 function Float32Attribute( array, itemSize ) {
49342 console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
49343 return new Float32BufferAttribute( array, itemSize );
49347 function Float64Attribute( array, itemSize ) {
49349 console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
49350 return new Float64BufferAttribute( array, itemSize );
49356 Curve.create = function ( construct, getPoint ) {
49358 console.log( 'THREE.Curve.create() has been deprecated' );
49360 construct.prototype = Object.create( Curve.prototype );
49361 construct.prototype.constructor = construct;
49362 construct.prototype.getPoint = getPoint;
49370 Object.assign( CurvePath.prototype, {
49372 createPointsGeometry: function ( divisions ) {
49374 console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
49376 // generate geometry from path points (for Line or Points objects)
49378 const pts = this.getPoints( divisions );
49379 return this.createGeometry( pts );
49383 createSpacedPointsGeometry: function ( divisions ) {
49385 console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
49387 // generate geometry from equidistant sampling along the path
49389 const pts = this.getSpacedPoints( divisions );
49390 return this.createGeometry( pts );
49394 createGeometry: function ( points ) {
49396 console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
49398 const geometry = new Geometry();
49400 for ( let i = 0, l = points.length; i < l; i ++ ) {
49402 const point = points[ i ];
49403 geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
49415 Object.assign( Path.prototype, {
49417 fromPoints: function ( points ) {
49419 console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
49420 return this.setFromPoints( points );
49428 function ClosedSplineCurve3( points ) {
49430 console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
49432 CatmullRomCurve3.call( this, points );
49433 this.type = 'catmullrom';
49434 this.closed = true;
49438 ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
49442 function SplineCurve3( points ) {
49444 console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
49446 CatmullRomCurve3.call( this, points );
49447 this.type = 'catmullrom';
49451 SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
49455 function Spline( points ) {
49457 console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
49459 CatmullRomCurve3.call( this, points );
49460 this.type = 'catmullrom';
49464 Spline.prototype = Object.create( CatmullRomCurve3.prototype );
49466 Object.assign( Spline.prototype, {
49468 initFromArray: function ( /* a */ ) {
49470 console.error( 'THREE.Spline: .initFromArray() has been removed.' );
49473 getControlPointsArray: function ( /* optionalTarget */ ) {
49475 console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
49478 reparametrizeByArcLength: function ( /* samplingCoef */ ) {
49480 console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
49488 function AxisHelper( size ) {
49490 console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' );
49491 return new AxesHelper( size );
49495 function BoundingBoxHelper( object, color ) {
49497 console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
49498 return new BoxHelper( object, color );
49502 function EdgesHelper( object, hex ) {
49504 console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
49505 return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
49509 GridHelper.prototype.setColors = function () {
49511 console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
49515 SkeletonHelper.prototype.update = function () {
49517 console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
49521 function WireframeHelper( object, hex ) {
49523 console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
49524 return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
49530 Object.assign( Loader.prototype, {
49532 extractUrlBase: function ( url ) {
49534 console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
49535 return LoaderUtils.extractUrlBase( url );
49541 Loader.Handlers = {
49543 add: function ( /* regex, loader */ ) {
49545 console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' );
49549 get: function ( /* file */ ) {
49551 console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' );
49557 function XHRLoader( manager ) {
49559 console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
49560 return new FileLoader( manager );
49564 function BinaryTextureLoader( manager ) {
49566 console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
49567 return new DataTextureLoader( manager );
49573 Object.assign( Box2.prototype, {
49575 center: function ( optionalTarget ) {
49577 console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
49578 return this.getCenter( optionalTarget );
49581 empty: function () {
49583 console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
49584 return this.isEmpty();
49587 isIntersectionBox: function ( box ) {
49589 console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
49590 return this.intersectsBox( box );
49593 size: function ( optionalTarget ) {
49595 console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
49596 return this.getSize( optionalTarget );
49601 Object.assign( Box3.prototype, {
49603 center: function ( optionalTarget ) {
49605 console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
49606 return this.getCenter( optionalTarget );
49609 empty: function () {
49611 console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
49612 return this.isEmpty();
49615 isIntersectionBox: function ( box ) {
49617 console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
49618 return this.intersectsBox( box );
49621 isIntersectionSphere: function ( sphere ) {
49623 console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
49624 return this.intersectsSphere( sphere );
49627 size: function ( optionalTarget ) {
49629 console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
49630 return this.getSize( optionalTarget );
49635 Object.assign( Sphere.prototype, {
49637 empty: function () {
49639 console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' );
49640 return this.isEmpty();
49646 Frustum.prototype.setFromMatrix = function ( m ) {
49648 console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' );
49649 return this.setFromProjectionMatrix( m );
49653 Line3.prototype.center = function ( optionalTarget ) {
49655 console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
49656 return this.getCenter( optionalTarget );
49660 Object.assign( MathUtils, {
49662 random16: function () {
49664 console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' );
49665 return Math.random();
49669 nearestPowerOfTwo: function ( value ) {
49671 console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' );
49672 return MathUtils.floorPowerOfTwo( value );
49676 nextPowerOfTwo: function ( value ) {
49678 console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' );
49679 return MathUtils.ceilPowerOfTwo( value );
49685 Object.assign( Matrix3.prototype, {
49687 flattenToArrayOffset: function ( array, offset ) {
49689 console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
49690 return this.toArray( array, offset );
49693 multiplyVector3: function ( vector ) {
49695 console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
49696 return vector.applyMatrix3( this );
49699 multiplyVector3Array: function ( /* a */ ) {
49701 console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
49704 applyToBufferAttribute: function ( attribute ) {
49706 console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' );
49707 return attribute.applyMatrix3( this );
49710 applyToVector3Array: function ( /* array, offset, length */ ) {
49712 console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
49715 getInverse: function ( matrix ) {
49717 console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
49718 return this.copy( matrix ).invert();
49724 Object.assign( Matrix4.prototype, {
49726 extractPosition: function ( m ) {
49728 console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
49729 return this.copyPosition( m );
49732 flattenToArrayOffset: function ( array, offset ) {
49734 console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
49735 return this.toArray( array, offset );
49738 getPosition: function () {
49740 console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
49741 return new Vector3().setFromMatrixColumn( this, 3 );
49744 setRotationFromQuaternion: function ( q ) {
49746 console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
49747 return this.makeRotationFromQuaternion( q );
49750 multiplyToArray: function () {
49752 console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
49755 multiplyVector3: function ( vector ) {
49757 console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
49758 return vector.applyMatrix4( this );
49761 multiplyVector4: function ( vector ) {
49763 console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
49764 return vector.applyMatrix4( this );
49767 multiplyVector3Array: function ( /* a */ ) {
49769 console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
49772 rotateAxis: function ( v ) {
49774 console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
49775 v.transformDirection( this );
49778 crossVector: function ( vector ) {
49780 console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
49781 return vector.applyMatrix4( this );
49784 translate: function () {
49786 console.error( 'THREE.Matrix4: .translate() has been removed.' );
49789 rotateX: function () {
49791 console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
49794 rotateY: function () {
49796 console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
49799 rotateZ: function () {
49801 console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
49804 rotateByAxis: function () {
49806 console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
49809 applyToBufferAttribute: function ( attribute ) {
49811 console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' );
49812 return attribute.applyMatrix4( this );
49815 applyToVector3Array: function ( /* array, offset, length */ ) {
49817 console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
49820 makeFrustum: function ( left, right, bottom, top, near, far ) {
49822 console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
49823 return this.makePerspective( left, right, top, bottom, near, far );
49826 getInverse: function ( matrix ) {
49828 console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
49829 return this.copy( matrix ).invert();
49835 Plane.prototype.isIntersectionLine = function ( line ) {
49837 console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
49838 return this.intersectsLine( line );
49842 Object.assign( Quaternion.prototype, {
49844 multiplyVector3: function ( vector ) {
49846 console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
49847 return vector.applyQuaternion( this );
49850 inverse: function ( ) {
49852 console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' );
49853 return this.invert();
49859 Object.assign( Ray.prototype, {
49861 isIntersectionBox: function ( box ) {
49863 console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
49864 return this.intersectsBox( box );
49867 isIntersectionPlane: function ( plane ) {
49869 console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
49870 return this.intersectsPlane( plane );
49873 isIntersectionSphere: function ( sphere ) {
49875 console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
49876 return this.intersectsSphere( sphere );
49882 Object.assign( Triangle.prototype, {
49884 area: function () {
49886 console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
49887 return this.getArea();
49890 barycoordFromPoint: function ( point, target ) {
49892 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
49893 return this.getBarycoord( point, target );
49896 midpoint: function ( target ) {
49898 console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
49899 return this.getMidpoint( target );
49902 normal: function ( target ) {
49904 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
49905 return this.getNormal( target );
49908 plane: function ( target ) {
49910 console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
49911 return this.getPlane( target );
49917 Object.assign( Triangle, {
49919 barycoordFromPoint: function ( point, a, b, c, target ) {
49921 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
49922 return Triangle.getBarycoord( point, a, b, c, target );
49925 normal: function ( a, b, c, target ) {
49927 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
49928 return Triangle.getNormal( a, b, c, target );
49934 Object.assign( Shape.prototype, {
49936 extractAllPoints: function ( divisions ) {
49938 console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
49939 return this.extractPoints( divisions );
49942 extrude: function ( options ) {
49944 console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
49945 return new ExtrudeGeometry( this, options );
49948 makeGeometry: function ( options ) {
49950 console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
49951 return new ShapeGeometry( this, options );
49957 Object.assign( Vector2.prototype, {
49959 fromAttribute: function ( attribute, index, offset ) {
49961 console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
49962 return this.fromBufferAttribute( attribute, index, offset );
49965 distanceToManhattan: function ( v ) {
49967 console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
49968 return this.manhattanDistanceTo( v );
49971 lengthManhattan: function () {
49973 console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
49974 return this.manhattanLength();
49980 Object.assign( Vector3.prototype, {
49982 setEulerFromRotationMatrix: function () {
49984 console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
49987 setEulerFromQuaternion: function () {
49989 console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
49992 getPositionFromMatrix: function ( m ) {
49994 console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
49995 return this.setFromMatrixPosition( m );
49998 getScaleFromMatrix: function ( m ) {
50000 console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
50001 return this.setFromMatrixScale( m );
50004 getColumnFromMatrix: function ( index, matrix ) {
50006 console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
50007 return this.setFromMatrixColumn( matrix, index );
50010 applyProjection: function ( m ) {
50012 console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
50013 return this.applyMatrix4( m );
50016 fromAttribute: function ( attribute, index, offset ) {
50018 console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
50019 return this.fromBufferAttribute( attribute, index, offset );
50022 distanceToManhattan: function ( v ) {
50024 console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
50025 return this.manhattanDistanceTo( v );
50028 lengthManhattan: function () {
50030 console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
50031 return this.manhattanLength();
50037 Object.assign( Vector4.prototype, {
50039 fromAttribute: function ( attribute, index, offset ) {
50041 console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
50042 return this.fromBufferAttribute( attribute, index, offset );
50045 lengthManhattan: function () {
50047 console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
50048 return this.manhattanLength();
50056 Object.assign( Geometry.prototype, {
50058 computeTangents: function () {
50060 console.error( 'THREE.Geometry: .computeTangents() has been removed.' );
50063 computeLineDistances: function () {
50065 console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' );
50068 applyMatrix: function ( matrix ) {
50070 console.warn( 'THREE.Geometry: .applyMatrix() has been renamed to .applyMatrix4().' );
50071 return this.applyMatrix4( matrix );
50077 Object.assign( Object3D.prototype, {
50079 getChildByName: function ( name ) {
50081 console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
50082 return this.getObjectByName( name );
50085 renderDepth: function () {
50087 console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
50090 translate: function ( distance, axis ) {
50092 console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
50093 return this.translateOnAxis( axis, distance );
50096 getWorldRotation: function () {
50098 console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
50101 applyMatrix: function ( matrix ) {
50103 console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' );
50104 return this.applyMatrix4( matrix );
50110 Object.defineProperties( Object3D.prototype, {
50115 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
50116 return this.rotation.order;
50119 set: function ( value ) {
50121 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
50122 this.rotation.order = value;
50129 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
50134 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
50141 Object.assign( Mesh.prototype, {
50143 setDrawMode: function () {
50145 console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
50151 Object.defineProperties( Mesh.prototype, {
50156 console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' );
50157 return TrianglesDrawMode;
50162 console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
50169 Object.defineProperties( LOD.prototype, {
50174 console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
50175 return this.levels;
50182 Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
50186 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
50191 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
50197 SkinnedMesh.prototype.initBones = function () {
50199 console.error( 'THREE.SkinnedMesh: initBones() has been removed.' );
50203 Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
50207 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
50208 return this.arcLengthDivisions;
50211 set: function ( value ) {
50213 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
50214 this.arcLengthDivisions = value;
50222 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
50224 console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
50225 "Use .setFocalLength and .filmGauge for a photographic setup." );
50227 if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
50228 this.setFocalLength( focalLength );
50234 Object.defineProperties( Light.prototype, {
50238 console.warn( 'THREE.Light: .onlyShadow has been removed.' );
50243 set: function ( value ) {
50245 console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
50246 this.shadow.camera.fov = value;
50250 shadowCameraLeft: {
50251 set: function ( value ) {
50253 console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
50254 this.shadow.camera.left = value;
50258 shadowCameraRight: {
50259 set: function ( value ) {
50261 console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
50262 this.shadow.camera.right = value;
50267 set: function ( value ) {
50269 console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
50270 this.shadow.camera.top = value;
50274 shadowCameraBottom: {
50275 set: function ( value ) {
50277 console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
50278 this.shadow.camera.bottom = value;
50282 shadowCameraNear: {
50283 set: function ( value ) {
50285 console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
50286 this.shadow.camera.near = value;
50291 set: function ( value ) {
50293 console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
50294 this.shadow.camera.far = value;
50298 shadowCameraVisible: {
50301 console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
50306 set: function ( value ) {
50308 console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
50309 this.shadow.bias = value;
50316 console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
50321 set: function ( value ) {
50323 console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
50324 this.shadow.mapSize.width = value;
50329 set: function ( value ) {
50331 console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
50332 this.shadow.mapSize.height = value;
50340 Object.defineProperties( BufferAttribute.prototype, {
50345 console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
50346 return this.array.length;
50353 console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
50354 return this.usage === DynamicDrawUsage;
50357 set: function ( /* value */ ) {
50359 console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
50360 this.setUsage( DynamicDrawUsage );
50367 Object.assign( BufferAttribute.prototype, {
50368 setDynamic: function ( value ) {
50370 console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' );
50371 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
50375 copyIndicesArray: function ( /* indices */ ) {
50377 console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
50380 setArray: function ( /* array */ ) {
50382 console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
50387 Object.assign( BufferGeometry.prototype, {
50389 addIndex: function ( index ) {
50391 console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
50392 this.setIndex( index );
50395 addAttribute: function ( name, attribute ) {
50397 console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' );
50399 if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
50401 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
50403 return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
50407 if ( name === 'index' ) {
50409 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
50410 this.setIndex( attribute );
50416 return this.setAttribute( name, attribute );
50419 addDrawCall: function ( start, count, indexOffset ) {
50421 if ( indexOffset !== undefined ) {
50423 console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
50427 console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
50428 this.addGroup( start, count );
50431 clearDrawCalls: function () {
50433 console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
50434 this.clearGroups();
50437 computeTangents: function () {
50439 console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );
50442 computeOffsets: function () {
50444 console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
50447 removeAttribute: function ( name ) {
50449 console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' );
50451 return this.deleteAttribute( name );
50454 applyMatrix: function ( matrix ) {
50456 console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' );
50457 return this.applyMatrix4( matrix );
50463 Object.defineProperties( BufferGeometry.prototype, {
50468 console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
50469 return this.groups;
50476 console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
50477 return this.groups;
50484 Object.defineProperties( InstancedBufferGeometry.prototype, {
50486 maxInstancedCount: {
50489 console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
50490 return this.instanceCount;
50493 set: function ( value ) {
50495 console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
50496 this.instanceCount = value;
50503 Object.defineProperties( Raycaster.prototype, {
50508 console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
50509 return this.params.Line.threshold;
50512 set: function ( value ) {
50514 console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
50515 this.params.Line.threshold = value;
50522 Object.defineProperties( InterleavedBuffer.prototype, {
50527 console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
50528 return this.usage === DynamicDrawUsage;
50531 set: function ( value ) {
50533 console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
50534 this.setUsage( value );
50541 Object.assign( InterleavedBuffer.prototype, {
50542 setDynamic: function ( value ) {
50544 console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' );
50545 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
50549 setArray: function ( /* array */ ) {
50551 console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
50558 Object.assign( ExtrudeBufferGeometry.prototype, {
50560 getArrays: function () {
50562 console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' );
50566 addShapeList: function () {
50568 console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' );
50572 addShape: function () {
50574 console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' );
50582 Object.assign( Scene.prototype, {
50584 dispose: function () {
50586 console.error( 'THREE.Scene: .dispose() has been removed.' );
50594 Object.defineProperties( Uniform.prototype, {
50599 console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
50604 value: function () {
50606 console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
50616 Object.defineProperties( Material.prototype, {
50621 console.warn( 'THREE.Material: .wrapAround has been removed.' );
50626 console.warn( 'THREE.Material: .wrapAround has been removed.' );
50634 console.warn( 'THREE.Material: .overdraw has been removed.' );
50639 console.warn( 'THREE.Material: .overdraw has been removed.' );
50647 console.warn( 'THREE.Material: .wrapRGB has been removed.' );
50648 return new Color();
50656 console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
50659 set: function ( value ) {
50661 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
50662 this.flatShading = ( value === FlatShading );
50670 console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
50671 return this.stencilFuncMask;
50674 set: function ( value ) {
50676 console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
50677 this.stencilFuncMask = value;
50684 Object.defineProperties( MeshPhongMaterial.prototype, {
50689 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
50695 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
50702 Object.defineProperties( MeshPhysicalMaterial.prototype, {
50707 console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
50708 return this.transmission;
50711 set: function ( value ) {
50713 console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
50714 this.transmission = value;
50721 Object.defineProperties( ShaderMaterial.prototype, {
50726 console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
50727 return this.extensions.derivatives;
50730 set: function ( value ) {
50732 console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
50733 this.extensions.derivatives = value;
50742 Object.assign( WebGLRenderer.prototype, {
50744 clearTarget: function ( renderTarget, color, depth, stencil ) {
50746 console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' );
50747 this.setRenderTarget( renderTarget );
50748 this.clear( color, depth, stencil );
50751 animate: function ( callback ) {
50753 console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
50754 this.setAnimationLoop( callback );
50757 getCurrentRenderTarget: function () {
50759 console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
50760 return this.getRenderTarget();
50763 getMaxAnisotropy: function () {
50765 console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
50766 return this.capabilities.getMaxAnisotropy();
50769 getPrecision: function () {
50771 console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
50772 return this.capabilities.precision;
50775 resetGLState: function () {
50777 console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
50778 return this.state.reset();
50781 supportsFloatTextures: function () {
50783 console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
50784 return this.extensions.get( 'OES_texture_float' );
50787 supportsHalfFloatTextures: function () {
50789 console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
50790 return this.extensions.get( 'OES_texture_half_float' );
50793 supportsStandardDerivatives: function () {
50795 console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
50796 return this.extensions.get( 'OES_standard_derivatives' );
50799 supportsCompressedTextureS3TC: function () {
50801 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
50802 return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
50805 supportsCompressedTexturePVRTC: function () {
50807 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
50808 return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
50811 supportsBlendMinMax: function () {
50813 console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
50814 return this.extensions.get( 'EXT_blend_minmax' );
50817 supportsVertexTextures: function () {
50819 console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
50820 return this.capabilities.vertexTextures;
50823 supportsInstancedArrays: function () {
50825 console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
50826 return this.extensions.get( 'ANGLE_instanced_arrays' );
50829 enableScissorTest: function ( boolean ) {
50831 console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
50832 this.setScissorTest( boolean );
50835 initMaterial: function () {
50837 console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
50840 addPrePlugin: function () {
50842 console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
50845 addPostPlugin: function () {
50847 console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
50850 updateShadowMap: function () {
50852 console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
50855 setFaceCulling: function () {
50857 console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
50860 allocTextureUnit: function () {
50862 console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' );
50865 setTexture: function () {
50867 console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' );
50870 setTexture2D: function () {
50872 console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' );
50875 setTextureCube: function () {
50877 console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' );
50880 getActiveMipMapLevel: function () {
50882 console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' );
50883 return this.getActiveMipmapLevel();
50889 Object.defineProperties( WebGLRenderer.prototype, {
50891 shadowMapEnabled: {
50894 return this.shadowMap.enabled;
50897 set: function ( value ) {
50899 console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
50900 this.shadowMap.enabled = value;
50907 return this.shadowMap.type;
50910 set: function ( value ) {
50912 console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
50913 this.shadowMap.type = value;
50917 shadowMapCullFace: {
50920 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
50924 set: function ( /* value */ ) {
50926 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
50933 console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' );
50934 return this.getContext();
50941 console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' );
50949 console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
50955 console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
50962 console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
50966 set: function ( value ) {
50968 console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
50969 this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding;
50973 toneMappingWhitePoint: {
50976 console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
50982 console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
50989 Object.defineProperties( WebGLShadowMap.prototype, {
50994 console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
50998 set: function ( /* cullFace */ ) {
51000 console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
51004 renderReverseSided: {
51007 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
51013 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
51017 renderSingleSided: {
51020 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
51026 console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
51033 function WebGLRenderTargetCube( width, height, options ) {
51035 console.warn( 'THREE.WebGLRenderTargetCube( width, height, options ) is now WebGLCubeRenderTarget( size, options ).' );
51036 return new WebGLCubeRenderTarget( width, options );
51042 Object.defineProperties( WebGLRenderTarget.prototype, {
51047 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
51048 return this.texture.wrapS;
51051 set: function ( value ) {
51053 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
51054 this.texture.wrapS = value;
51061 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
51062 return this.texture.wrapT;
51065 set: function ( value ) {
51067 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
51068 this.texture.wrapT = value;
51075 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
51076 return this.texture.magFilter;
51079 set: function ( value ) {
51081 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
51082 this.texture.magFilter = value;
51089 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
51090 return this.texture.minFilter;
51093 set: function ( value ) {
51095 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
51096 this.texture.minFilter = value;
51103 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
51104 return this.texture.anisotropy;
51107 set: function ( value ) {
51109 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
51110 this.texture.anisotropy = value;
51117 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
51118 return this.texture.offset;
51121 set: function ( value ) {
51123 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
51124 this.texture.offset = value;
51131 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
51132 return this.texture.repeat;
51135 set: function ( value ) {
51137 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
51138 this.texture.repeat = value;
51145 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
51146 return this.texture.format;
51149 set: function ( value ) {
51151 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
51152 this.texture.format = value;
51159 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
51160 return this.texture.type;
51163 set: function ( value ) {
51165 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
51166 this.texture.type = value;
51173 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
51174 return this.texture.generateMipmaps;
51177 set: function ( value ) {
51179 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
51180 this.texture.generateMipmaps = value;
51189 Object.defineProperties( Audio.prototype, {
51192 value: function ( file ) {
51194 console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
51195 const scope = this;
51196 const audioLoader = new AudioLoader();
51197 audioLoader.load( file, function ( buffer ) {
51199 scope.setBuffer( buffer );
51209 console.warn( 'THREE.Audio: .startTime is now .play( delay ).' );
51216 AudioAnalyser.prototype.getData = function () {
51218 console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
51219 return this.getFrequencyData();
51225 CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
51227 console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
51228 return this.update( renderer, scene );
51232 CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) {
51234 console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' );
51235 return this.renderTarget.clear( renderer, color, depth, stencil );
51241 const GeometryUtils = {
51243 merge: function ( geometry1, geometry2, materialIndexOffset ) {
51245 console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
51248 if ( geometry2.isMesh ) {
51250 geometry2.matrixAutoUpdate && geometry2.updateMatrix();
51252 matrix = geometry2.matrix;
51253 geometry2 = geometry2.geometry;
51257 geometry1.merge( geometry2, matrix, materialIndexOffset );
51261 center: function ( geometry ) {
51263 console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
51264 return geometry.center();
51270 ImageUtils.crossOrigin = undefined;
51272 ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) {
51274 console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
51276 const loader = new TextureLoader();
51277 loader.setCrossOrigin( this.crossOrigin );
51279 const texture = loader.load( url, onLoad, undefined, onError );
51281 if ( mapping ) texture.mapping = mapping;
51287 ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) {
51289 console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
51291 const loader = new CubeTextureLoader();
51292 loader.setCrossOrigin( this.crossOrigin );
51294 const texture = loader.load( urls, onLoad, undefined, onError );
51296 if ( mapping ) texture.mapping = mapping;
51302 ImageUtils.loadCompressedTexture = function () {
51304 console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
51308 ImageUtils.loadCompressedTextureCube = function () {
51310 console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
51316 function CanvasRenderer() {
51318 console.error( 'THREE.CanvasRenderer has been removed' );
51324 function JSONLoader() {
51326 console.error( 'THREE.JSONLoader has been removed.' );
51332 const SceneUtils = {
51334 createMultiMaterialObject: function ( /* geometry, materials */ ) {
51336 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
51340 detach: function ( /* child, parent, scene */ ) {
51342 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
51346 attach: function ( /* child, scene, parent */ ) {
51348 console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' );
51356 function LensFlare() {
51358 console.error( 'THREE.LensFlare has been moved to /examples/jsm/objects/Lensflare.js' );
51362 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
51364 /* eslint-disable no-undef */
51365 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
51366 revision: REVISION,
51368 /* eslint-enable no-undef */
51372 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, BoxBufferGeometry, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasRenderer, CanvasTexture, CatmullRomCurve3, CineonToneMapping, CircleBufferGeometry, CircleGeometry, ClampToEdgeWrapping, Clock, ClosedSplineCurve3, Color, ColorKeyframeTrack, CompressedTexture, CompressedTextureLoader, ConeBufferGeometry, ConeGeometry, CubeCamera, BoxGeometry as CubeGeometry, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubeUVRefractionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderBufferGeometry, CylinderGeometry, Cylindrical, DataTexture, DataTexture2DArray, DataTexture3D, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronBufferGeometry, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicBufferAttribute, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EdgesHelper, EllipseCurve, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeBufferGeometry, ExtrudeGeometry, Face3, Face4, FaceColors, FileLoader, FlatShading, Float16BufferAttribute, Float32Attribute, Float32BufferAttribute, Float64Attribute, Float64BufferAttribute, FloatType, Fog, FogExp2, Font, FontLoader, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GammaEncoding, Geometry, GeometryUtils, GreaterDepth, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, HemisphereLightProbe, 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, 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, OctahedronBufferGeometry, OctahedronGeometry, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, ParametricBufferGeometry, ParametricGeometry, Particle, ParticleBasicMaterial, ParticleSystem, ParticleSystemMaterial, Path, PerspectiveCamera, Plane, PlaneBufferGeometry, PlaneGeometry, PlaneHelper, PointCloud, PointCloudMaterial, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, 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, 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, ShapeBufferGeometry, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, SmoothShading, Sphere, 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, TetrahedronBufferGeometry, TetrahedronGeometry, TextBufferGeometry, TextGeometry, Texture, TextureLoader, TorusBufferGeometry, TorusGeometry, TorusKnotBufferGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, 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 };