1 (function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (factory((global.THREE = global.THREE || {})));
5 }(this, (function (exports) { 'use strict';
9 if ( Number.EPSILON === undefined ) {
11 Number.EPSILON = Math.pow( 2, - 52 );
15 if ( Number.isInteger === undefined ) {
18 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
20 Number.isInteger = function ( value ) {
22 return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;
30 if ( Math.sign === undefined ) {
32 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
34 Math.sign = function ( x ) {
36 return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
42 if ( Function.prototype.name === undefined ) {
45 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
47 Object.defineProperty( Function.prototype, 'name', {
51 return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
59 if ( Object.assign === undefined ) {
62 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
66 Object.assign = function ( target ) {
70 if ( target === undefined || target === null ) {
72 throw new TypeError( 'Cannot convert undefined or null to object' );
76 var output = Object( target );
78 for ( var index = 1; index < arguments.length; index ++ ) {
80 var source = arguments[ index ];
82 if ( source !== undefined && source !== null ) {
84 for ( var nextKey in source ) {
86 if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
88 output[ nextKey ] = source[ nextKey ];
107 * https://github.com/mrdoob/eventdispatcher.js/
110 function EventDispatcher() {}
112 Object.assign( EventDispatcher.prototype, {
114 addEventListener: function ( type, listener ) {
116 if ( this._listeners === undefined ) this._listeners = {};
118 var listeners = this._listeners;
120 if ( listeners[ type ] === undefined ) {
122 listeners[ type ] = [];
126 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
128 listeners[ type ].push( listener );
134 hasEventListener: function ( type, listener ) {
136 if ( this._listeners === undefined ) return false;
138 var listeners = this._listeners;
140 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
144 removeEventListener: function ( type, listener ) {
146 if ( this._listeners === undefined ) return;
148 var listeners = this._listeners;
149 var listenerArray = listeners[ type ];
151 if ( listenerArray !== undefined ) {
153 var index = listenerArray.indexOf( listener );
155 if ( index !== - 1 ) {
157 listenerArray.splice( index, 1 );
165 dispatchEvent: function ( event ) {
167 if ( this._listeners === undefined ) return;
169 var listeners = this._listeners;
170 var listenerArray = listeners[ event.type ];
172 if ( listenerArray !== undefined ) {
176 var array = listenerArray.slice( 0 );
178 for ( var i = 0, l = array.length; i < l; i ++ ) {
180 array[ i ].call( this, event );
191 var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
192 var CullFaceNone = 0;
193 var CullFaceBack = 1;
194 var CullFaceFront = 2;
195 var CullFaceFrontBack = 3;
196 var FrontFaceDirectionCW = 0;
197 var FrontFaceDirectionCCW = 1;
198 var BasicShadowMap = 0;
199 var PCFShadowMap = 1;
200 var PCFSoftShadowMap = 2;
205 var SmoothShading = 2;
208 var VertexColors = 2;
210 var NormalBlending = 1;
211 var AdditiveBlending = 2;
212 var SubtractiveBlending = 3;
213 var MultiplyBlending = 4;
214 var CustomBlending = 5;
215 var AddEquation = 100;
216 var SubtractEquation = 101;
217 var ReverseSubtractEquation = 102;
218 var MinEquation = 103;
219 var MaxEquation = 104;
220 var ZeroFactor = 200;
222 var SrcColorFactor = 202;
223 var OneMinusSrcColorFactor = 203;
224 var SrcAlphaFactor = 204;
225 var OneMinusSrcAlphaFactor = 205;
226 var DstAlphaFactor = 206;
227 var OneMinusDstAlphaFactor = 207;
228 var DstColorFactor = 208;
229 var OneMinusDstColorFactor = 209;
230 var SrcAlphaSaturateFactor = 210;
234 var LessEqualDepth = 3;
236 var GreaterEqualDepth = 5;
237 var GreaterDepth = 6;
238 var NotEqualDepth = 7;
239 var MultiplyOperation = 0;
240 var MixOperation = 1;
241 var AddOperation = 2;
242 var NoToneMapping = 0;
243 var LinearToneMapping = 1;
244 var ReinhardToneMapping = 2;
245 var Uncharted2ToneMapping = 3;
246 var CineonToneMapping = 4;
248 var CubeReflectionMapping = 301;
249 var CubeRefractionMapping = 302;
250 var EquirectangularReflectionMapping = 303;
251 var EquirectangularRefractionMapping = 304;
252 var SphericalReflectionMapping = 305;
253 var CubeUVReflectionMapping = 306;
254 var CubeUVRefractionMapping = 307;
255 var RepeatWrapping = 1000;
256 var ClampToEdgeWrapping = 1001;
257 var MirroredRepeatWrapping = 1002;
258 var NearestFilter = 1003;
259 var NearestMipMapNearestFilter = 1004;
260 var NearestMipMapLinearFilter = 1005;
261 var LinearFilter = 1006;
262 var LinearMipMapNearestFilter = 1007;
263 var LinearMipMapLinearFilter = 1008;
264 var UnsignedByteType = 1009;
266 var ShortType = 1011;
267 var UnsignedShortType = 1012;
269 var UnsignedIntType = 1014;
270 var FloatType = 1015;
271 var HalfFloatType = 1016;
272 var UnsignedShort4444Type = 1017;
273 var UnsignedShort5551Type = 1018;
274 var UnsignedShort565Type = 1019;
275 var UnsignedInt248Type = 1020;
276 var AlphaFormat = 1021;
277 var RGBFormat = 1022;
278 var RGBAFormat = 1023;
279 var LuminanceFormat = 1024;
280 var LuminanceAlphaFormat = 1025;
281 var RGBEFormat = RGBAFormat;
282 var DepthFormat = 1026;
283 var DepthStencilFormat = 1027;
284 var RGB_S3TC_DXT1_Format = 2001;
285 var RGBA_S3TC_DXT1_Format = 2002;
286 var RGBA_S3TC_DXT3_Format = 2003;
287 var RGBA_S3TC_DXT5_Format = 2004;
288 var RGB_PVRTC_4BPPV1_Format = 2100;
289 var RGB_PVRTC_2BPPV1_Format = 2101;
290 var RGBA_PVRTC_4BPPV1_Format = 2102;
291 var RGBA_PVRTC_2BPPV1_Format = 2103;
292 var RGB_ETC1_Format = 2151;
294 var LoopRepeat = 2201;
295 var LoopPingPong = 2202;
296 var InterpolateDiscrete = 2300;
297 var InterpolateLinear = 2301;
298 var InterpolateSmooth = 2302;
299 var ZeroCurvatureEnding = 2400;
300 var ZeroSlopeEnding = 2401;
301 var WrapAroundEnding = 2402;
302 var TrianglesDrawMode = 0;
303 var TriangleStripDrawMode = 1;
304 var TriangleFanDrawMode = 2;
305 var LinearEncoding = 3000;
306 var sRGBEncoding = 3001;
307 var GammaEncoding = 3007;
308 var RGBEEncoding = 3002;
309 var LogLuvEncoding = 3003;
310 var RGBM7Encoding = 3004;
311 var RGBM16Encoding = 3005;
312 var RGBDEncoding = 3006;
313 var BasicDepthPacking = 3200;
314 var RGBADepthPacking = 3201;
317 * @author alteredq / http://alteredqualia.com/
318 * @author mrdoob / http://mrdoob.com/
323 DEG2RAD: Math.PI / 180,
324 RAD2DEG: 180 / Math.PI,
326 generateUUID: function () {
328 // http://www.broofa.com/Tools/Math.uuid.htm
330 var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
331 var uuid = new Array( 36 );
334 return function generateUUID() {
336 for ( var i = 0; i < 36; i ++ ) {
338 if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
342 } else if ( i === 14 ) {
348 if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
351 uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
357 return uuid.join( '' );
363 clamp: function ( value, min, max ) {
365 return Math.max( min, Math.min( max, value ) );
369 // compute euclidian modulo of m % n
370 // https://en.wikipedia.org/wiki/Modulo_operation
372 euclideanModulo: function ( n, m ) {
374 return ( ( n % m ) + m ) % m;
378 // Linear mapping from range <a1, a2> to range <b1, b2>
380 mapLinear: function ( x, a1, a2, b1, b2 ) {
382 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
386 // https://en.wikipedia.org/wiki/Linear_interpolation
388 lerp: function ( x, y, t ) {
390 return ( 1 - t ) * x + t * y;
394 // http://en.wikipedia.org/wiki/Smoothstep
396 smoothstep: function ( x, min, max ) {
398 if ( x <= min ) return 0;
399 if ( x >= max ) return 1;
401 x = ( x - min ) / ( max - min );
403 return x * x * ( 3 - 2 * x );
407 smootherstep: function ( x, min, max ) {
409 if ( x <= min ) return 0;
410 if ( x >= max ) return 1;
412 x = ( x - min ) / ( max - min );
414 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
418 // Random integer from <low, high> interval
420 randInt: function ( low, high ) {
422 return low + Math.floor( Math.random() * ( high - low + 1 ) );
426 // Random float from <low, high> interval
428 randFloat: function ( low, high ) {
430 return low + Math.random() * ( high - low );
434 // Random float from <-range/2, range/2> interval
436 randFloatSpread: function ( range ) {
438 return range * ( 0.5 - Math.random() );
442 degToRad: function ( degrees ) {
444 return degrees * _Math.DEG2RAD;
448 radToDeg: function ( radians ) {
450 return radians * _Math.RAD2DEG;
454 isPowerOfTwo: function ( value ) {
456 return ( value & ( value - 1 ) ) === 0 && value !== 0;
460 nearestPowerOfTwo: function ( value ) {
462 return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );
466 nextPowerOfTwo: function ( value ) {
473 value |= value >> 16;
483 * @author mrdoob / http://mrdoob.com/
484 * @author philogb / http://blog.thejit.org/
485 * @author egraether / http://egraether.com/
486 * @author zz85 / http://www.lab4games.net/zz85/blog
489 function Vector2( x, y ) {
496 Object.defineProperties( Vector2.prototype, {
506 set: function ( value ) {
522 set: function ( value ) {
532 Object.assign( Vector2.prototype, {
536 set: function ( x, y ) {
545 setScalar: function ( scalar ) {
554 setX: function ( x ) {
562 setY: function ( y ) {
570 setComponent: function ( index, value ) {
574 case 0: this.x = value; break;
575 case 1: this.y = value; break;
576 default: throw new Error( 'index is out of range: ' + index );
584 getComponent: function ( index ) {
588 case 0: return this.x;
589 case 1: return this.y;
590 default: throw new Error( 'index is out of range: ' + index );
598 return new this.constructor( this.x, this.y );
602 copy: function ( v ) {
611 add: function ( v, w ) {
613 if ( w !== undefined ) {
615 console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
616 return this.addVectors( v, w );
627 addScalar: function ( s ) {
636 addVectors: function ( a, b ) {
645 addScaledVector: function ( v, s ) {
654 sub: function ( v, w ) {
656 if ( w !== undefined ) {
658 console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
659 return this.subVectors( v, w );
670 subScalar: function ( s ) {
679 subVectors: function ( a, b ) {
688 multiply: function ( v ) {
697 multiplyScalar: function ( scalar ) {
706 divide: function ( v ) {
715 divideScalar: function ( scalar ) {
717 return this.multiplyScalar( 1 / scalar );
721 min: function ( v ) {
723 this.x = Math.min( this.x, v.x );
724 this.y = Math.min( this.y, v.y );
730 max: function ( v ) {
732 this.x = Math.max( this.x, v.x );
733 this.y = Math.max( this.y, v.y );
739 clamp: function ( min, max ) {
741 // assumes min < max, componentwise
743 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
744 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
750 clampScalar: function () {
752 var min = new Vector2();
753 var max = new Vector2();
755 return function clampScalar( minVal, maxVal ) {
757 min.set( minVal, minVal );
758 max.set( maxVal, maxVal );
760 return this.clamp( min, max );
766 clampLength: function ( min, max ) {
768 var length = this.length();
770 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
776 this.x = Math.floor( this.x );
777 this.y = Math.floor( this.y );
785 this.x = Math.ceil( this.x );
786 this.y = Math.ceil( this.y );
794 this.x = Math.round( this.x );
795 this.y = Math.round( this.y );
801 roundToZero: function () {
803 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
804 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
810 negate: function () {
819 dot: function ( v ) {
821 return this.x * v.x + this.y * v.y;
825 lengthSq: function () {
827 return this.x * this.x + this.y * this.y;
831 length: function () {
833 return Math.sqrt( this.x * this.x + this.y * this.y );
837 lengthManhattan: function() {
839 return Math.abs( this.x ) + Math.abs( this.y );
843 normalize: function () {
845 return this.divideScalar( this.length() || 1 );
851 // computes the angle in radians with respect to the positive x-axis
853 var angle = Math.atan2( this.y, this.x );
855 if ( angle < 0 ) angle += 2 * Math.PI;
861 distanceTo: function ( v ) {
863 return Math.sqrt( this.distanceToSquared( v ) );
867 distanceToSquared: function ( v ) {
869 var dx = this.x - v.x, dy = this.y - v.y;
870 return dx * dx + dy * dy;
874 distanceToManhattan: function ( v ) {
876 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
880 setLength: function ( length ) {
882 return this.normalize().multiplyScalar( length );
886 lerp: function ( v, alpha ) {
888 this.x += ( v.x - this.x ) * alpha;
889 this.y += ( v.y - this.y ) * alpha;
895 lerpVectors: function ( v1, v2, alpha ) {
897 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
901 equals: function ( v ) {
903 return ( ( v.x === this.x ) && ( v.y === this.y ) );
907 fromArray: function ( array, offset ) {
909 if ( offset === undefined ) offset = 0;
911 this.x = array[ offset ];
912 this.y = array[ offset + 1 ];
918 toArray: function ( array, offset ) {
920 if ( array === undefined ) array = [];
921 if ( offset === undefined ) offset = 0;
923 array[ offset ] = this.x;
924 array[ offset + 1 ] = this.y;
930 fromBufferAttribute: function ( attribute, index, offset ) {
932 if ( offset !== undefined ) {
934 console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
938 this.x = attribute.getX( index );
939 this.y = attribute.getY( index );
945 rotateAround: function ( center, angle ) {
947 var c = Math.cos( angle ), s = Math.sin( angle );
949 var x = this.x - center.x;
950 var y = this.y - center.y;
952 this.x = x * c - y * s + center.x;
953 this.y = x * s + y * c + center.y;
962 * @author mrdoob / http://mrdoob.com/
963 * @author alteredq / http://alteredqualia.com/
964 * @author szimek / https://github.com/szimek/
969 function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
971 Object.defineProperty( this, 'id', { value: textureId ++ } );
973 this.uuid = _Math.generateUUID();
977 this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
980 this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
982 this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
983 this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
985 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
986 this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
988 this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
990 this.format = format !== undefined ? format : RGBAFormat;
991 this.type = type !== undefined ? type : UnsignedByteType;
993 this.offset = new Vector2( 0, 0 );
994 this.repeat = new Vector2( 1, 1 );
996 this.generateMipmaps = true;
997 this.premultiplyAlpha = false;
999 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
1001 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
1003 // Also changing the encoding after already used by a Material will not automatically make the Material
1004 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
1005 this.encoding = encoding !== undefined ? encoding : LinearEncoding;
1008 this.onUpdate = null;
1012 Texture.DEFAULT_IMAGE = undefined;
1013 Texture.DEFAULT_MAPPING = UVMapping;
1015 Object.defineProperty( Texture.prototype, "needsUpdate", {
1017 set: function ( value ) {
1019 if ( value === true ) this.version ++;
1025 Object.assign( Texture.prototype, EventDispatcher.prototype, {
1027 constructor: Texture,
1031 clone: function () {
1033 return new this.constructor().copy( this );
1037 copy: function ( source ) {
1039 this.name = source.name;
1041 this.image = source.image;
1042 this.mipmaps = source.mipmaps.slice( 0 );
1044 this.mapping = source.mapping;
1046 this.wrapS = source.wrapS;
1047 this.wrapT = source.wrapT;
1049 this.magFilter = source.magFilter;
1050 this.minFilter = source.minFilter;
1052 this.anisotropy = source.anisotropy;
1054 this.format = source.format;
1055 this.type = source.type;
1057 this.offset.copy( source.offset );
1058 this.repeat.copy( source.repeat );
1060 this.generateMipmaps = source.generateMipmaps;
1061 this.premultiplyAlpha = source.premultiplyAlpha;
1062 this.flipY = source.flipY;
1063 this.unpackAlignment = source.unpackAlignment;
1064 this.encoding = source.encoding;
1070 toJSON: function ( meta ) {
1072 if ( meta.textures[ this.uuid ] !== undefined ) {
1074 return meta.textures[ this.uuid ];
1078 function getDataURL( image ) {
1082 if ( image instanceof HTMLCanvasElement ) {
1088 canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
1089 canvas.width = image.width;
1090 canvas.height = image.height;
1092 var context = canvas.getContext( '2d' );
1094 if ( image instanceof ImageData ) {
1096 context.putImageData( image, 0, 0 );
1100 context.drawImage( image, 0, 0, image.width, image.height );
1106 if ( canvas.width > 2048 || canvas.height > 2048 ) {
1108 return canvas.toDataURL( 'image/jpeg', 0.6 );
1112 return canvas.toDataURL( 'image/png' );
1122 generator: 'Texture.toJSON'
1128 mapping: this.mapping,
1130 repeat: [ this.repeat.x, this.repeat.y ],
1131 offset: [ this.offset.x, this.offset.y ],
1132 wrap: [ this.wrapS, this.wrapT ],
1134 minFilter: this.minFilter,
1135 magFilter: this.magFilter,
1136 anisotropy: this.anisotropy,
1141 if ( this.image !== undefined ) {
1143 // TODO: Move to THREE.Image
1145 var image = this.image;
1147 if ( image.uuid === undefined ) {
1149 image.uuid = _Math.generateUUID(); // UGH
1153 if ( meta.images[ image.uuid ] === undefined ) {
1155 meta.images[ image.uuid ] = {
1157 url: getDataURL( image )
1162 output.image = image.uuid;
1166 meta.textures[ this.uuid ] = output;
1172 dispose: function () {
1174 this.dispatchEvent( { type: 'dispose' } );
1178 transformUv: function ( uv ) {
1180 if ( this.mapping !== UVMapping ) return;
1182 uv.multiply( this.repeat );
1183 uv.add( this.offset );
1185 if ( uv.x < 0 || uv.x > 1 ) {
1187 switch ( this.wrapS ) {
1189 case RepeatWrapping:
1191 uv.x = uv.x - Math.floor( uv.x );
1194 case ClampToEdgeWrapping:
1196 uv.x = uv.x < 0 ? 0 : 1;
1199 case MirroredRepeatWrapping:
1201 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
1203 uv.x = Math.ceil( uv.x ) - uv.x;
1207 uv.x = uv.x - Math.floor( uv.x );
1216 if ( uv.y < 0 || uv.y > 1 ) {
1218 switch ( this.wrapT ) {
1220 case RepeatWrapping:
1222 uv.y = uv.y - Math.floor( uv.y );
1225 case ClampToEdgeWrapping:
1227 uv.y = uv.y < 0 ? 0 : 1;
1230 case MirroredRepeatWrapping:
1232 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
1234 uv.y = Math.ceil( uv.y ) - uv.y;
1238 uv.y = uv.y - Math.floor( uv.y );
1258 * @author supereggbert / http://www.paulbrunt.co.uk/
1259 * @author philogb / http://blog.thejit.org/
1260 * @author mikael emtinger / http://gomo.se/
1261 * @author egraether / http://egraether.com/
1262 * @author WestLangley / http://github.com/WestLangley
1265 function Vector4( x, y, z, w ) {
1270 this.w = ( w !== undefined ) ? w : 1;
1274 Object.assign( Vector4.prototype, {
1278 set: function ( x, y, z, w ) {
1289 setScalar: function ( scalar ) {
1300 setX: function ( x ) {
1308 setY: function ( y ) {
1316 setZ: function ( z ) {
1324 setW: function ( w ) {
1332 setComponent: function ( index, value ) {
1336 case 0: this.x = value; break;
1337 case 1: this.y = value; break;
1338 case 2: this.z = value; break;
1339 case 3: this.w = value; break;
1340 default: throw new Error( 'index is out of range: ' + index );
1348 getComponent: function ( index ) {
1352 case 0: return this.x;
1353 case 1: return this.y;
1354 case 2: return this.z;
1355 case 3: return this.w;
1356 default: throw new Error( 'index is out of range: ' + index );
1362 clone: function () {
1364 return new this.constructor( this.x, this.y, this.z, this.w );
1368 copy: function ( v ) {
1373 this.w = ( v.w !== undefined ) ? v.w : 1;
1379 add: function ( v, w ) {
1381 if ( w !== undefined ) {
1383 console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
1384 return this.addVectors( v, w );
1397 addScalar: function ( s ) {
1408 addVectors: function ( a, b ) {
1419 addScaledVector: function ( v, s ) {
1430 sub: function ( v, w ) {
1432 if ( w !== undefined ) {
1434 console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
1435 return this.subVectors( v, w );
1448 subScalar: function ( s ) {
1459 subVectors: function ( a, b ) {
1470 multiplyScalar: function ( scalar ) {
1481 applyMatrix4: function ( m ) {
1483 var x = this.x, y = this.y, z = this.z, w = this.w;
1486 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
1487 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
1488 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
1489 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
1495 divideScalar: function ( scalar ) {
1497 return this.multiplyScalar( 1 / scalar );
1501 setAxisAngleFromQuaternion: function ( q ) {
1503 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
1505 // q is assumed to be normalized
1507 this.w = 2 * Math.acos( q.w );
1509 var s = Math.sqrt( 1 - q.w * q.w );
1529 setAxisAngleFromRotationMatrix: function ( m ) {
1531 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
1533 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
1535 var angle, x, y, z, // variables for result
1536 epsilon = 0.01, // margin to allow for rounding errors
1537 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
1541 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
1542 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
1543 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
1545 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
1546 ( Math.abs( m13 - m31 ) < epsilon ) &&
1547 ( Math.abs( m23 - m32 ) < epsilon ) ) {
1549 // singularity found
1550 // first check for identity matrix which must have +1 for all terms
1551 // in leading diagonal and zero in other terms
1553 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
1554 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
1555 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
1556 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
1558 // this singularity is identity matrix so angle = 0
1560 this.set( 1, 0, 0, 0 );
1562 return this; // zero angle, arbitrary axis
1566 // otherwise this singularity is angle = 180
1570 var xx = ( m11 + 1 ) / 2;
1571 var yy = ( m22 + 1 ) / 2;
1572 var zz = ( m33 + 1 ) / 2;
1573 var xy = ( m12 + m21 ) / 4;
1574 var xz = ( m13 + m31 ) / 4;
1575 var yz = ( m23 + m32 ) / 4;
1577 if ( ( xx > yy ) && ( xx > zz ) ) {
1579 // m11 is the largest diagonal term
1581 if ( xx < epsilon ) {
1589 x = Math.sqrt( xx );
1595 } else if ( yy > zz ) {
1597 // m22 is the largest diagonal term
1599 if ( yy < epsilon ) {
1607 y = Math.sqrt( yy );
1615 // m33 is the largest diagonal term so base result on this
1617 if ( zz < epsilon ) {
1625 z = Math.sqrt( zz );
1633 this.set( x, y, z, angle );
1635 return this; // return 180 deg rotation
1639 // as we have reached here there are no singularities so we can handle normally
1641 var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
1642 ( m13 - m31 ) * ( m13 - m31 ) +
1643 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
1645 if ( Math.abs( s ) < 0.001 ) s = 1;
1647 // prevent divide by zero, should not happen if matrix is orthogonal and should be
1648 // caught by singularity test above, but I've left it in just in case
1650 this.x = ( m32 - m23 ) / s;
1651 this.y = ( m13 - m31 ) / s;
1652 this.z = ( m21 - m12 ) / s;
1653 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
1659 min: function ( v ) {
1661 this.x = Math.min( this.x, v.x );
1662 this.y = Math.min( this.y, v.y );
1663 this.z = Math.min( this.z, v.z );
1664 this.w = Math.min( this.w, v.w );
1670 max: function ( v ) {
1672 this.x = Math.max( this.x, v.x );
1673 this.y = Math.max( this.y, v.y );
1674 this.z = Math.max( this.z, v.z );
1675 this.w = Math.max( this.w, v.w );
1681 clamp: function ( min, max ) {
1683 // assumes min < max, componentwise
1685 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
1686 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
1687 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
1688 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
1694 clampScalar: function () {
1698 return function clampScalar( minVal, maxVal ) {
1700 if ( min === undefined ) {
1702 min = new Vector4();
1703 max = new Vector4();
1707 min.set( minVal, minVal, minVal, minVal );
1708 max.set( maxVal, maxVal, maxVal, maxVal );
1710 return this.clamp( min, max );
1716 clampLength: function ( min, max ) {
1718 var length = this.length();
1720 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
1724 floor: function () {
1726 this.x = Math.floor( this.x );
1727 this.y = Math.floor( this.y );
1728 this.z = Math.floor( this.z );
1729 this.w = Math.floor( this.w );
1737 this.x = Math.ceil( this.x );
1738 this.y = Math.ceil( this.y );
1739 this.z = Math.ceil( this.z );
1740 this.w = Math.ceil( this.w );
1746 round: function () {
1748 this.x = Math.round( this.x );
1749 this.y = Math.round( this.y );
1750 this.z = Math.round( this.z );
1751 this.w = Math.round( this.w );
1757 roundToZero: function () {
1759 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
1760 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
1761 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
1762 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
1768 negate: function () {
1779 dot: function ( v ) {
1781 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
1785 lengthSq: function () {
1787 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
1791 length: function () {
1793 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
1797 lengthManhattan: function () {
1799 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
1803 normalize: function () {
1805 return this.divideScalar( this.length() || 1 );
1809 setLength: function ( length ) {
1811 return this.normalize().multiplyScalar( length );
1815 lerp: function ( v, alpha ) {
1817 this.x += ( v.x - this.x ) * alpha;
1818 this.y += ( v.y - this.y ) * alpha;
1819 this.z += ( v.z - this.z ) * alpha;
1820 this.w += ( v.w - this.w ) * alpha;
1826 lerpVectors: function ( v1, v2, alpha ) {
1828 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
1832 equals: function ( v ) {
1834 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
1838 fromArray: function ( array, offset ) {
1840 if ( offset === undefined ) offset = 0;
1842 this.x = array[ offset ];
1843 this.y = array[ offset + 1 ];
1844 this.z = array[ offset + 2 ];
1845 this.w = array[ offset + 3 ];
1851 toArray: function ( array, offset ) {
1853 if ( array === undefined ) array = [];
1854 if ( offset === undefined ) offset = 0;
1856 array[ offset ] = this.x;
1857 array[ offset + 1 ] = this.y;
1858 array[ offset + 2 ] = this.z;
1859 array[ offset + 3 ] = this.w;
1865 fromBufferAttribute: function ( attribute, index, offset ) {
1867 if ( offset !== undefined ) {
1869 console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
1873 this.x = attribute.getX( index );
1874 this.y = attribute.getY( index );
1875 this.z = attribute.getZ( index );
1876 this.w = attribute.getW( index );
1885 * @author szimek / https://github.com/szimek/
1886 * @author alteredq / http://alteredqualia.com/
1887 * @author Marius Kintel / https://github.com/kintel
1891 In options, we can specify:
1892 * Texture parameters for an auto-generated target texture
1893 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
1895 function WebGLRenderTarget( width, height, options ) {
1897 this.uuid = _Math.generateUUID();
1900 this.height = height;
1902 this.scissor = new Vector4( 0, 0, width, height );
1903 this.scissorTest = false;
1905 this.viewport = new Vector4( 0, 0, width, height );
1907 options = options || {};
1909 if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
1911 this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
1913 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
1914 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
1915 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
1919 Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, {
1921 isWebGLRenderTarget: true,
1923 setSize: function ( width, height ) {
1925 if ( this.width !== width || this.height !== height ) {
1928 this.height = height;
1934 this.viewport.set( 0, 0, width, height );
1935 this.scissor.set( 0, 0, width, height );
1939 clone: function () {
1941 return new this.constructor().copy( this );
1945 copy: function ( source ) {
1947 this.width = source.width;
1948 this.height = source.height;
1950 this.viewport.copy( source.viewport );
1952 this.texture = source.texture.clone();
1954 this.depthBuffer = source.depthBuffer;
1955 this.stencilBuffer = source.stencilBuffer;
1956 this.depthTexture = source.depthTexture;
1962 dispose: function () {
1964 this.dispatchEvent( { type: 'dispose' } );
1971 * @author alteredq / http://alteredqualia.com
1974 function WebGLRenderTargetCube( width, height, options ) {
1976 WebGLRenderTarget.call( this, width, height, options );
1978 this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
1979 this.activeMipMapLevel = 0;
1983 WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
1984 WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
1986 WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
1989 * @author mikael emtinger / http://gomo.se/
1990 * @author alteredq / http://alteredqualia.com/
1991 * @author WestLangley / http://github.com/WestLangley
1992 * @author bhouston / http://clara.io
1995 function Quaternion( x, y, z, w ) {
2000 this._w = ( w !== undefined ) ? w : 1;
2004 Object.assign( Quaternion, {
2006 slerp: function ( qa, qb, qm, t ) {
2008 return qm.copy( qa ).slerp( qb, t );
2012 slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
2014 // fuzz-free, array-based Quaternion SLERP operation
2016 var x0 = src0[ srcOffset0 + 0 ],
2017 y0 = src0[ srcOffset0 + 1 ],
2018 z0 = src0[ srcOffset0 + 2 ],
2019 w0 = src0[ srcOffset0 + 3 ],
2021 x1 = src1[ srcOffset1 + 0 ],
2022 y1 = src1[ srcOffset1 + 1 ],
2023 z1 = src1[ srcOffset1 + 2 ],
2024 w1 = src1[ srcOffset1 + 3 ];
2026 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
2030 cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
2032 dir = ( cos >= 0 ? 1 : - 1 ),
2033 sqrSin = 1 - cos * cos;
2035 // Skip the Slerp for tiny steps to avoid numeric problems:
2036 if ( sqrSin > Number.EPSILON ) {
2038 var sin = Math.sqrt( sqrSin ),
2039 len = Math.atan2( sin, cos * dir );
2041 s = Math.sin( s * len ) / sin;
2042 t = Math.sin( t * len ) / sin;
2048 x0 = x0 * s + x1 * tDir;
2049 y0 = y0 * s + y1 * tDir;
2050 z0 = z0 * s + z1 * tDir;
2051 w0 = w0 * s + w1 * tDir;
2053 // Normalize in case we just did a lerp:
2054 if ( s === 1 - t ) {
2056 var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
2067 dst[ dstOffset ] = x0;
2068 dst[ dstOffset + 1 ] = y0;
2069 dst[ dstOffset + 2 ] = z0;
2070 dst[ dstOffset + 3 ] = w0;
2076 Object.defineProperties( Quaternion.prototype, {
2086 set: function ( value ) {
2089 this.onChangeCallback();
2103 set: function ( value ) {
2106 this.onChangeCallback();
2120 set: function ( value ) {
2123 this.onChangeCallback();
2137 set: function ( value ) {
2140 this.onChangeCallback();
2148 Object.assign( Quaternion.prototype, {
2150 set: function ( x, y, z, w ) {
2157 this.onChangeCallback();
2163 clone: function () {
2165 return new this.constructor( this._x, this._y, this._z, this._w );
2169 copy: function ( quaternion ) {
2171 this._x = quaternion.x;
2172 this._y = quaternion.y;
2173 this._z = quaternion.z;
2174 this._w = quaternion.w;
2176 this.onChangeCallback();
2182 setFromEuler: function ( euler, update ) {
2184 if ( ! ( euler && euler.isEuler ) ) {
2186 throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
2190 var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
2192 // http://www.mathworks.com/matlabcentral/fileexchange/
2193 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
2194 // content/SpinCalc.m
2199 var c1 = cos( x / 2 );
2200 var c2 = cos( y / 2 );
2201 var c3 = cos( z / 2 );
2203 var s1 = sin( x / 2 );
2204 var s2 = sin( y / 2 );
2205 var s3 = sin( z / 2 );
2207 if ( order === 'XYZ' ) {
2209 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2210 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2211 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2212 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2214 } else if ( order === 'YXZ' ) {
2216 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2217 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2218 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2219 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2221 } else if ( order === 'ZXY' ) {
2223 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2224 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2225 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2226 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2228 } else if ( order === 'ZYX' ) {
2230 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2231 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2232 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2233 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2235 } else if ( order === 'YZX' ) {
2237 this._x = s1 * c2 * c3 + c1 * s2 * s3;
2238 this._y = c1 * s2 * c3 + s1 * c2 * s3;
2239 this._z = c1 * c2 * s3 - s1 * s2 * c3;
2240 this._w = c1 * c2 * c3 - s1 * s2 * s3;
2242 } else if ( order === 'XZY' ) {
2244 this._x = s1 * c2 * c3 - c1 * s2 * s3;
2245 this._y = c1 * s2 * c3 - s1 * c2 * s3;
2246 this._z = c1 * c2 * s3 + s1 * s2 * c3;
2247 this._w = c1 * c2 * c3 + s1 * s2 * s3;
2251 if ( update !== false ) this.onChangeCallback();
2257 setFromAxisAngle: function ( axis, angle ) {
2259 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
2261 // assumes axis is normalized
2263 var halfAngle = angle / 2, s = Math.sin( halfAngle );
2265 this._x = axis.x * s;
2266 this._y = axis.y * s;
2267 this._z = axis.z * s;
2268 this._w = Math.cos( halfAngle );
2270 this.onChangeCallback();
2276 setFromRotationMatrix: function ( m ) {
2278 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
2280 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2282 var te = m.elements,
2284 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2285 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2286 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
2288 trace = m11 + m22 + m33,
2293 s = 0.5 / Math.sqrt( trace + 1.0 );
2296 this._x = ( m32 - m23 ) * s;
2297 this._y = ( m13 - m31 ) * s;
2298 this._z = ( m21 - m12 ) * s;
2300 } else if ( m11 > m22 && m11 > m33 ) {
2302 s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
2304 this._w = ( m32 - m23 ) / s;
2306 this._y = ( m12 + m21 ) / s;
2307 this._z = ( m13 + m31 ) / s;
2309 } else if ( m22 > m33 ) {
2311 s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
2313 this._w = ( m13 - m31 ) / s;
2314 this._x = ( m12 + m21 ) / s;
2316 this._z = ( m23 + m32 ) / s;
2320 s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
2322 this._w = ( m21 - m12 ) / s;
2323 this._x = ( m13 + m31 ) / s;
2324 this._y = ( m23 + m32 ) / s;
2329 this.onChangeCallback();
2335 setFromUnitVectors: function () {
2337 // assumes direction vectors vFrom and vTo are normalized
2339 var v1 = new Vector3();
2344 return function setFromUnitVectors( vFrom, vTo ) {
2346 if ( v1 === undefined ) v1 = new Vector3();
2348 r = vFrom.dot( vTo ) + 1;
2354 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
2356 v1.set( - vFrom.y, vFrom.x, 0 );
2360 v1.set( 0, - vFrom.z, vFrom.y );
2366 v1.crossVectors( vFrom, vTo );
2375 return this.normalize();
2381 inverse: function () {
2383 return this.conjugate().normalize();
2387 conjugate: function () {
2393 this.onChangeCallback();
2399 dot: function ( v ) {
2401 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
2405 lengthSq: function () {
2407 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
2411 length: function () {
2413 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
2417 normalize: function () {
2419 var l = this.length();
2432 this._x = this._x * l;
2433 this._y = this._y * l;
2434 this._z = this._z * l;
2435 this._w = this._w * l;
2439 this.onChangeCallback();
2445 multiply: function ( q, p ) {
2447 if ( p !== undefined ) {
2449 console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
2450 return this.multiplyQuaternions( q, p );
2454 return this.multiplyQuaternions( this, q );
2458 premultiply: function ( q ) {
2460 return this.multiplyQuaternions( q, this );
2464 multiplyQuaternions: function ( a, b ) {
2466 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
2468 var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
2469 var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
2471 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
2472 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
2473 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
2474 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
2476 this.onChangeCallback();
2482 slerp: function ( qb, t ) {
2484 if ( t === 0 ) return this;
2485 if ( t === 1 ) return this.copy( qb );
2487 var x = this._x, y = this._y, z = this._z, w = this._w;
2489 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
2491 var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
2493 if ( cosHalfTheta < 0 ) {
2500 cosHalfTheta = - cosHalfTheta;
2508 if ( cosHalfTheta >= 1.0 ) {
2519 var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
2521 if ( Math.abs( sinHalfTheta ) < 0.001 ) {
2523 this._w = 0.5 * ( w + this._w );
2524 this._x = 0.5 * ( x + this._x );
2525 this._y = 0.5 * ( y + this._y );
2526 this._z = 0.5 * ( z + this._z );
2532 var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
2533 var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
2534 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
2536 this._w = ( w * ratioA + this._w * ratioB );
2537 this._x = ( x * ratioA + this._x * ratioB );
2538 this._y = ( y * ratioA + this._y * ratioB );
2539 this._z = ( z * ratioA + this._z * ratioB );
2541 this.onChangeCallback();
2547 equals: function ( quaternion ) {
2549 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
2553 fromArray: function ( array, offset ) {
2555 if ( offset === undefined ) offset = 0;
2557 this._x = array[ offset ];
2558 this._y = array[ offset + 1 ];
2559 this._z = array[ offset + 2 ];
2560 this._w = array[ offset + 3 ];
2562 this.onChangeCallback();
2568 toArray: function ( array, offset ) {
2570 if ( array === undefined ) array = [];
2571 if ( offset === undefined ) offset = 0;
2573 array[ offset ] = this._x;
2574 array[ offset + 1 ] = this._y;
2575 array[ offset + 2 ] = this._z;
2576 array[ offset + 3 ] = this._w;
2582 onChange: function ( callback ) {
2584 this.onChangeCallback = callback;
2590 onChangeCallback: function () {}
2595 * @author mrdoob / http://mrdoob.com/
2596 * @author kile / http://kile.stravaganza.org/
2597 * @author philogb / http://blog.thejit.org/
2598 * @author mikael emtinger / http://gomo.se/
2599 * @author egraether / http://egraether.com/
2600 * @author WestLangley / http://github.com/WestLangley
2603 function Vector3( x, y, z ) {
2611 Object.assign( Vector3.prototype, {
2615 set: function ( x, y, z ) {
2625 setScalar: function ( scalar ) {
2635 setX: function ( x ) {
2643 setY: function ( y ) {
2651 setZ: function ( z ) {
2659 setComponent: function ( index, value ) {
2663 case 0: this.x = value; break;
2664 case 1: this.y = value; break;
2665 case 2: this.z = value; break;
2666 default: throw new Error( 'index is out of range: ' + index );
2674 getComponent: function ( index ) {
2678 case 0: return this.x;
2679 case 1: return this.y;
2680 case 2: return this.z;
2681 default: throw new Error( 'index is out of range: ' + index );
2687 clone: function () {
2689 return new this.constructor( this.x, this.y, this.z );
2693 copy: function ( v ) {
2703 add: function ( v, w ) {
2705 if ( w !== undefined ) {
2707 console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
2708 return this.addVectors( v, w );
2720 addScalar: function ( s ) {
2730 addVectors: function ( a, b ) {
2740 addScaledVector: function ( v, s ) {
2750 sub: function ( v, w ) {
2752 if ( w !== undefined ) {
2754 console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
2755 return this.subVectors( v, w );
2767 subScalar: function ( s ) {
2777 subVectors: function ( a, b ) {
2787 multiply: function ( v, w ) {
2789 if ( w !== undefined ) {
2791 console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
2792 return this.multiplyVectors( v, w );
2804 multiplyScalar: function ( scalar ) {
2814 multiplyVectors: function ( a, b ) {
2824 applyEuler: function () {
2826 var quaternion = new Quaternion();
2828 return function applyEuler( euler ) {
2830 if ( ! ( euler && euler.isEuler ) ) {
2832 console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
2836 return this.applyQuaternion( quaternion.setFromEuler( euler ) );
2842 applyAxisAngle: function () {
2844 var quaternion = new Quaternion();
2846 return function applyAxisAngle( axis, angle ) {
2848 return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
2854 applyMatrix3: function ( m ) {
2856 var x = this.x, y = this.y, z = this.z;
2859 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
2860 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
2861 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
2867 applyMatrix4: function ( m ) {
2869 var x = this.x, y = this.y, z = this.z;
2872 var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
2874 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
2875 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
2876 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
2882 applyQuaternion: function ( q ) {
2884 var x = this.x, y = this.y, z = this.z;
2885 var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
2887 // calculate quat * vector
2889 var ix = qw * x + qy * z - qz * y;
2890 var iy = qw * y + qz * x - qx * z;
2891 var iz = qw * z + qx * y - qy * x;
2892 var iw = - qx * x - qy * y - qz * z;
2894 // calculate result * inverse quat
2896 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
2897 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
2898 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
2904 project: function () {
2906 var matrix = new Matrix4();
2908 return function project( camera ) {
2910 matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
2911 return this.applyMatrix4( matrix );
2917 unproject: function () {
2919 var matrix = new Matrix4();
2921 return function unproject( camera ) {
2923 matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
2924 return this.applyMatrix4( matrix );
2930 transformDirection: function ( m ) {
2932 // input: THREE.Matrix4 affine matrix
2933 // vector interpreted as a direction
2935 var x = this.x, y = this.y, z = this.z;
2938 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
2939 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
2940 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
2942 return this.normalize();
2946 divide: function ( v ) {
2956 divideScalar: function ( scalar ) {
2958 return this.multiplyScalar( 1 / scalar );
2962 min: function ( v ) {
2964 this.x = Math.min( this.x, v.x );
2965 this.y = Math.min( this.y, v.y );
2966 this.z = Math.min( this.z, v.z );
2972 max: function ( v ) {
2974 this.x = Math.max( this.x, v.x );
2975 this.y = Math.max( this.y, v.y );
2976 this.z = Math.max( this.z, v.z );
2982 clamp: function ( min, max ) {
2984 // assumes min < max, componentwise
2986 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2987 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2988 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
2994 clampScalar: function () {
2996 var min = new Vector3();
2997 var max = new Vector3();
2999 return function clampScalar( minVal, maxVal ) {
3001 min.set( minVal, minVal, minVal );
3002 max.set( maxVal, maxVal, maxVal );
3004 return this.clamp( min, max );
3010 clampLength: function ( min, max ) {
3012 var length = this.length();
3014 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
3018 floor: function () {
3020 this.x = Math.floor( this.x );
3021 this.y = Math.floor( this.y );
3022 this.z = Math.floor( this.z );
3030 this.x = Math.ceil( this.x );
3031 this.y = Math.ceil( this.y );
3032 this.z = Math.ceil( this.z );
3038 round: function () {
3040 this.x = Math.round( this.x );
3041 this.y = Math.round( this.y );
3042 this.z = Math.round( this.z );
3048 roundToZero: function () {
3050 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
3051 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
3052 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
3058 negate: function () {
3068 dot: function ( v ) {
3070 return this.x * v.x + this.y * v.y + this.z * v.z;
3074 // TODO lengthSquared?
3076 lengthSq: function () {
3078 return this.x * this.x + this.y * this.y + this.z * this.z;
3082 length: function () {
3084 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
3088 lengthManhattan: function () {
3090 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
3094 normalize: function () {
3096 return this.divideScalar( this.length() || 1 );
3100 setLength: function ( length ) {
3102 return this.normalize().multiplyScalar( length );
3106 lerp: function ( v, alpha ) {
3108 this.x += ( v.x - this.x ) * alpha;
3109 this.y += ( v.y - this.y ) * alpha;
3110 this.z += ( v.z - this.z ) * alpha;
3116 lerpVectors: function ( v1, v2, alpha ) {
3118 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
3122 cross: function ( v, w ) {
3124 if ( w !== undefined ) {
3126 console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
3127 return this.crossVectors( v, w );
3131 var x = this.x, y = this.y, z = this.z;
3133 this.x = y * v.z - z * v.y;
3134 this.y = z * v.x - x * v.z;
3135 this.z = x * v.y - y * v.x;
3141 crossVectors: function ( a, b ) {
3143 var ax = a.x, ay = a.y, az = a.z;
3144 var bx = b.x, by = b.y, bz = b.z;
3146 this.x = ay * bz - az * by;
3147 this.y = az * bx - ax * bz;
3148 this.z = ax * by - ay * bx;
3154 projectOnVector: function ( vector ) {
3156 var scalar = vector.dot( this ) / vector.lengthSq();
3158 return this.copy( vector ).multiplyScalar( scalar );
3162 projectOnPlane: function () {
3164 var v1 = new Vector3();
3166 return function projectOnPlane( planeNormal ) {
3168 v1.copy( this ).projectOnVector( planeNormal );
3170 return this.sub( v1 );
3176 reflect: function () {
3178 // reflect incident vector off plane orthogonal to normal
3179 // normal is assumed to have unit length
3181 var v1 = new Vector3();
3183 return function reflect( normal ) {
3185 return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
3191 angleTo: function ( v ) {
3193 var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
3195 // clamp, to handle numerical problems
3197 return Math.acos( _Math.clamp( theta, - 1, 1 ) );
3201 distanceTo: function ( v ) {
3203 return Math.sqrt( this.distanceToSquared( v ) );
3207 distanceToSquared: function ( v ) {
3209 var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
3211 return dx * dx + dy * dy + dz * dz;
3215 distanceToManhattan: function ( v ) {
3217 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
3221 setFromSpherical: function ( s ) {
3223 var sinPhiRadius = Math.sin( s.phi ) * s.radius;
3225 this.x = sinPhiRadius * Math.sin( s.theta );
3226 this.y = Math.cos( s.phi ) * s.radius;
3227 this.z = sinPhiRadius * Math.cos( s.theta );
3233 setFromCylindrical: function ( c ) {
3235 this.x = c.radius * Math.sin( c.theta );
3237 this.z = c.radius * Math.cos( c.theta );
3243 setFromMatrixPosition: function ( m ) {
3255 setFromMatrixScale: function ( m ) {
3257 var sx = this.setFromMatrixColumn( m, 0 ).length();
3258 var sy = this.setFromMatrixColumn( m, 1 ).length();
3259 var sz = this.setFromMatrixColumn( m, 2 ).length();
3269 setFromMatrixColumn: function ( m, index ) {
3271 return this.fromArray( m.elements, index * 4 );
3275 equals: function ( v ) {
3277 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
3281 fromArray: function ( array, offset ) {
3283 if ( offset === undefined ) offset = 0;
3285 this.x = array[ offset ];
3286 this.y = array[ offset + 1 ];
3287 this.z = array[ offset + 2 ];
3293 toArray: function ( array, offset ) {
3295 if ( array === undefined ) array = [];
3296 if ( offset === undefined ) offset = 0;
3298 array[ offset ] = this.x;
3299 array[ offset + 1 ] = this.y;
3300 array[ offset + 2 ] = this.z;
3306 fromBufferAttribute: function ( attribute, index, offset ) {
3308 if ( offset !== undefined ) {
3310 console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
3314 this.x = attribute.getX( index );
3315 this.y = attribute.getY( index );
3316 this.z = attribute.getZ( index );
3325 * @author mrdoob / http://mrdoob.com/
3326 * @author supereggbert / http://www.paulbrunt.co.uk/
3327 * @author philogb / http://blog.thejit.org/
3328 * @author jordi_ros / http://plattsoft.com
3329 * @author D1plo1d / http://github.com/D1plo1d
3330 * @author alteredq / http://alteredqualia.com/
3331 * @author mikael emtinger / http://gomo.se/
3332 * @author timknip / http://www.floorplanner.com/
3333 * @author bhouston / http://clara.io
3334 * @author WestLangley / http://github.com/WestLangley
3337 function Matrix4() {
3348 if ( arguments.length > 0 ) {
3350 console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
3356 Object.assign( Matrix4.prototype, {
3360 set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
3362 var te = this.elements;
3364 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
3365 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
3366 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
3367 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
3373 identity: function () {
3388 clone: function () {
3390 return new Matrix4().fromArray( this.elements );
3394 copy: function ( m ) {
3396 var te = this.elements;
3397 var me = m.elements;
3399 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
3400 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
3401 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
3402 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
3408 copyPosition: function ( m ) {
3410 var te = this.elements, me = m.elements;
3412 te[ 12 ] = me[ 12 ];
3413 te[ 13 ] = me[ 13 ];
3414 te[ 14 ] = me[ 14 ];
3420 extractBasis: function ( xAxis, yAxis, zAxis ) {
3422 xAxis.setFromMatrixColumn( this, 0 );
3423 yAxis.setFromMatrixColumn( this, 1 );
3424 zAxis.setFromMatrixColumn( this, 2 );
3430 makeBasis: function ( xAxis, yAxis, zAxis ) {
3433 xAxis.x, yAxis.x, zAxis.x, 0,
3434 xAxis.y, yAxis.y, zAxis.y, 0,
3435 xAxis.z, yAxis.z, zAxis.z, 0,
3443 extractRotation: function () {
3445 var v1 = new Vector3();
3447 return function extractRotation( m ) {
3449 var te = this.elements;
3450 var me = m.elements;
3452 var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
3453 var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
3454 var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
3456 te[ 0 ] = me[ 0 ] * scaleX;
3457 te[ 1 ] = me[ 1 ] * scaleX;
3458 te[ 2 ] = me[ 2 ] * scaleX;
3460 te[ 4 ] = me[ 4 ] * scaleY;
3461 te[ 5 ] = me[ 5 ] * scaleY;
3462 te[ 6 ] = me[ 6 ] * scaleY;
3464 te[ 8 ] = me[ 8 ] * scaleZ;
3465 te[ 9 ] = me[ 9 ] * scaleZ;
3466 te[ 10 ] = me[ 10 ] * scaleZ;
3474 makeRotationFromEuler: function ( euler ) {
3476 if ( ! ( euler && euler.isEuler ) ) {
3478 console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
3482 var te = this.elements;
3484 var x = euler.x, y = euler.y, z = euler.z;
3485 var a = Math.cos( x ), b = Math.sin( x );
3486 var c = Math.cos( y ), d = Math.sin( y );
3487 var e = Math.cos( z ), f = Math.sin( z );
3489 if ( euler.order === 'XYZ' ) {
3491 var ae = a * e, af = a * f, be = b * e, bf = b * f;
3497 te[ 1 ] = af + be * d;
3498 te[ 5 ] = ae - bf * d;
3501 te[ 2 ] = bf - ae * d;
3502 te[ 6 ] = be + af * d;
3505 } else if ( euler.order === 'YXZ' ) {
3507 var ce = c * e, cf = c * f, de = d * e, df = d * f;
3509 te[ 0 ] = ce + df * b;
3510 te[ 4 ] = de * b - cf;
3517 te[ 2 ] = cf * b - de;
3518 te[ 6 ] = df + ce * b;
3521 } else if ( euler.order === 'ZXY' ) {
3523 var ce = c * e, cf = c * f, de = d * e, df = d * f;
3525 te[ 0 ] = ce - df * b;
3527 te[ 8 ] = de + cf * b;
3529 te[ 1 ] = cf + de * b;
3531 te[ 9 ] = df - ce * b;
3537 } else if ( euler.order === 'ZYX' ) {
3539 var ae = a * e, af = a * f, be = b * e, bf = b * f;
3542 te[ 4 ] = be * d - af;
3543 te[ 8 ] = ae * d + bf;
3546 te[ 5 ] = bf * d + ae;
3547 te[ 9 ] = af * d - be;
3553 } else if ( euler.order === 'YZX' ) {
3555 var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
3558 te[ 4 ] = bd - ac * f;
3559 te[ 8 ] = bc * f + ad;
3566 te[ 6 ] = ad * f + bc;
3567 te[ 10 ] = ac - bd * f;
3569 } else if ( euler.order === 'XZY' ) {
3571 var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
3577 te[ 1 ] = ac * f + bd;
3579 te[ 9 ] = ad * f - bc;
3581 te[ 2 ] = bc * f - ad;
3583 te[ 10 ] = bd * f + ac;
3602 makeRotationFromQuaternion: function ( q ) {
3604 var te = this.elements;
3606 var x = q._x, y = q._y, z = q._z, w = q._w;
3607 var x2 = x + x, y2 = y + y, z2 = z + z;
3608 var xx = x * x2, xy = x * y2, xz = x * z2;
3609 var yy = y * y2, yz = y * z2, zz = z * z2;
3610 var wx = w * x2, wy = w * y2, wz = w * z2;
3612 te[ 0 ] = 1 - ( yy + zz );
3617 te[ 5 ] = 1 - ( xx + zz );
3622 te[ 10 ] = 1 - ( xx + yy );
3639 lookAt: function () {
3641 var x = new Vector3();
3642 var y = new Vector3();
3643 var z = new Vector3();
3645 return function lookAt( eye, target, up ) {
3647 var te = this.elements;
3649 z.subVectors( eye, target );
3651 if ( z.lengthSq() === 0 ) {
3653 // eye and target are in the same position
3660 x.crossVectors( up, z );
3662 if ( x.lengthSq() === 0 ) {
3664 // up and z are parallel
3666 if ( Math.abs( up.z ) === 1 ) {
3677 x.crossVectors( up, z );
3682 y.crossVectors( z, x );
3684 te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
3685 te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
3686 te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
3694 multiply: function ( m, n ) {
3696 if ( n !== undefined ) {
3698 console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
3699 return this.multiplyMatrices( m, n );
3703 return this.multiplyMatrices( this, m );
3707 premultiply: function ( m ) {
3709 return this.multiplyMatrices( m, this );
3713 multiplyMatrices: function ( a, b ) {
3715 var ae = a.elements;
3716 var be = b.elements;
3717 var te = this.elements;
3719 var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
3720 var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
3721 var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
3722 var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
3724 var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
3725 var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
3726 var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
3727 var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
3729 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
3730 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
3731 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
3732 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
3734 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
3735 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
3736 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
3737 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
3739 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
3740 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
3741 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
3742 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
3744 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
3745 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
3746 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
3747 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
3753 multiplyScalar: function ( s ) {
3755 var te = this.elements;
3757 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
3758 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
3759 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
3760 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
3766 applyToBufferAttribute: function () {
3768 var v1 = new Vector3();
3770 return function applyToBufferAttribute( attribute ) {
3772 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
3774 v1.x = attribute.getX( i );
3775 v1.y = attribute.getY( i );
3776 v1.z = attribute.getZ( i );
3778 v1.applyMatrix4( this );
3780 attribute.setXYZ( i, v1.x, v1.y, v1.z );
3790 determinant: function () {
3792 var te = this.elements;
3794 var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
3795 var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
3796 var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
3797 var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
3799 //TODO: make this more efficient
3800 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
3840 transpose: function () {
3842 var te = this.elements;
3845 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
3846 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
3847 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
3849 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
3850 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
3851 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
3857 setPosition: function ( v ) {
3859 var te = this.elements;
3869 getInverse: function ( m, throwOnDegenerate ) {
3871 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
3872 var te = this.elements,
3875 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
3876 n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
3877 n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
3878 n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
3880 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
3881 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
3882 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
3883 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
3885 var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
3889 var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
3891 if ( throwOnDegenerate === true ) {
3893 throw new Error( msg );
3897 console.warn( msg );
3901 return this.identity();
3905 var detInv = 1 / det;
3907 te[ 0 ] = t11 * detInv;
3908 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
3909 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
3910 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
3912 te[ 4 ] = t12 * detInv;
3913 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
3914 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
3915 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
3917 te[ 8 ] = t13 * detInv;
3918 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
3919 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
3920 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
3922 te[ 12 ] = t14 * detInv;
3923 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
3924 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
3925 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
3931 scale: function ( v ) {
3933 var te = this.elements;
3934 var x = v.x, y = v.y, z = v.z;
3936 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
3937 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
3938 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
3939 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
3945 getMaxScaleOnAxis: function () {
3947 var te = this.elements;
3949 var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
3950 var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
3951 var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
3953 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
3957 makeTranslation: function ( x, y, z ) {
3972 makeRotationX: function ( theta ) {
3974 var c = Math.cos( theta ), s = Math.sin( theta );
3989 makeRotationY: function ( theta ) {
3991 var c = Math.cos( theta ), s = Math.sin( theta );
4006 makeRotationZ: function ( theta ) {
4008 var c = Math.cos( theta ), s = Math.sin( theta );
4023 makeRotationAxis: function ( axis, angle ) {
4025 // Based on http://www.gamedev.net/reference/articles/article1199.asp
4027 var c = Math.cos( angle );
4028 var s = Math.sin( angle );
4030 var x = axis.x, y = axis.y, z = axis.z;
4031 var tx = t * x, ty = t * y;
4035 tx * x + c, tx * y - s * z, tx * z + s * y, 0,
4036 tx * y + s * z, ty * y + c, ty * z - s * x, 0,
4037 tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
4046 makeScale: function ( x, y, z ) {
4061 makeShear: function ( x, y, z ) {
4076 compose: function ( position, quaternion, scale ) {
4078 this.makeRotationFromQuaternion( quaternion );
4079 this.scale( scale );
4080 this.setPosition( position );
4086 decompose: function () {
4088 var vector = new Vector3();
4089 var matrix = new Matrix4();
4091 return function decompose( position, quaternion, scale ) {
4093 var te = this.elements;
4095 var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
4096 var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
4097 var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
4099 // if determine is negative, we need to invert one scale
4100 var det = this.determinant();
4101 if ( det < 0 ) sx = - sx;
4103 position.x = te[ 12 ];
4104 position.y = te[ 13 ];
4105 position.z = te[ 14 ];
4107 // scale the rotation part
4108 matrix.copy( this );
4114 matrix.elements[ 0 ] *= invSX;
4115 matrix.elements[ 1 ] *= invSX;
4116 matrix.elements[ 2 ] *= invSX;
4118 matrix.elements[ 4 ] *= invSY;
4119 matrix.elements[ 5 ] *= invSY;
4120 matrix.elements[ 6 ] *= invSY;
4122 matrix.elements[ 8 ] *= invSZ;
4123 matrix.elements[ 9 ] *= invSZ;
4124 matrix.elements[ 10 ] *= invSZ;
4126 quaternion.setFromRotationMatrix( matrix );
4138 makePerspective: function ( left, right, top, bottom, near, far ) {
4140 if ( far === undefined ) {
4142 console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
4146 var te = this.elements;
4147 var x = 2 * near / ( right - left );
4148 var y = 2 * near / ( top - bottom );
4150 var a = ( right + left ) / ( right - left );
4151 var b = ( top + bottom ) / ( top - bottom );
4152 var c = - ( far + near ) / ( far - near );
4153 var d = - 2 * far * near / ( far - near );
4155 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
4156 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
4157 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
4158 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
4164 makeOrthographic: function ( left, right, top, bottom, near, far ) {
4166 var te = this.elements;
4167 var w = 1.0 / ( right - left );
4168 var h = 1.0 / ( top - bottom );
4169 var p = 1.0 / ( far - near );
4171 var x = ( right + left ) * w;
4172 var y = ( top + bottom ) * h;
4173 var z = ( far + near ) * p;
4175 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
4176 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
4177 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
4178 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
4184 equals: function ( matrix ) {
4186 var te = this.elements;
4187 var me = matrix.elements;
4189 for ( var i = 0; i < 16; i ++ ) {
4191 if ( te[ i ] !== me[ i ] ) return false;
4199 fromArray: function ( array, offset ) {
4201 if ( offset === undefined ) offset = 0;
4203 for ( var i = 0; i < 16; i ++ ) {
4205 this.elements[ i ] = array[ i + offset ];
4213 toArray: function ( array, offset ) {
4215 if ( array === undefined ) array = [];
4216 if ( offset === undefined ) offset = 0;
4218 var te = this.elements;
4220 array[ offset ] = te[ 0 ];
4221 array[ offset + 1 ] = te[ 1 ];
4222 array[ offset + 2 ] = te[ 2 ];
4223 array[ offset + 3 ] = te[ 3 ];
4225 array[ offset + 4 ] = te[ 4 ];
4226 array[ offset + 5 ] = te[ 5 ];
4227 array[ offset + 6 ] = te[ 6 ];
4228 array[ offset + 7 ] = te[ 7 ];
4230 array[ offset + 8 ] = te[ 8 ];
4231 array[ offset + 9 ] = te[ 9 ];
4232 array[ offset + 10 ] = te[ 10 ];
4233 array[ offset + 11 ] = te[ 11 ];
4235 array[ offset + 12 ] = te[ 12 ];
4236 array[ offset + 13 ] = te[ 13 ];
4237 array[ offset + 14 ] = te[ 14 ];
4238 array[ offset + 15 ] = te[ 15 ];
4247 * @author alteredq / http://alteredqualia.com/
4250 function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
4252 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
4254 this.image = { data: data, width: width, height: height };
4256 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
4257 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
4259 this.generateMipmaps = false;
4261 this.unpackAlignment = 1;
4265 DataTexture.prototype = Object.create( Texture.prototype );
4266 DataTexture.prototype.constructor = DataTexture;
4268 DataTexture.prototype.isDataTexture = true;
4271 * @author mrdoob / http://mrdoob.com/
4274 function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
4276 images = images !== undefined ? images : [];
4277 mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
4279 Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
4285 CubeTexture.prototype = Object.create( Texture.prototype );
4286 CubeTexture.prototype.constructor = CubeTexture;
4288 CubeTexture.prototype.isCubeTexture = true;
4290 Object.defineProperty( CubeTexture.prototype, 'images', {
4298 set: function ( value ) {
4309 * Uniforms of a program.
4310 * Those form a tree structure with a special top-level container for the root,
4311 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
4314 * Properties of inner nodes including the top-level container:
4316 * .seq - array of nested uniforms
4317 * .map - nested uniforms by name
4320 * Methods of all nodes except the top-level container:
4322 * .setValue( gl, value, [renderer] )
4324 * uploads a uniform value(s)
4325 * the 'renderer' parameter is needed for sampler uniforms
4328 * Static methods of the top-level container (renderer factorizations):
4330 * .upload( gl, seq, values, renderer )
4332 * sets uniforms in 'seq' to 'values[id].value'
4334 * .seqWithValue( seq, values ) : filteredSeq
4336 * filters 'seq' entries with corresponding entry in values
4339 * Methods of the top-level container (renderer factorizations):
4341 * .setValue( gl, name, value )
4343 * sets uniform with name 'name' to 'value'
4345 * .set( gl, obj, prop )
4347 * sets uniform from object and property with same name than uniform
4349 * .setOptional( gl, obj, prop )
4351 * like .set for an optional property of the object
4355 var emptyTexture = new Texture();
4356 var emptyCubeTexture = new CubeTexture();
4358 // --- Base for inner nodes (including the root) ---
4360 function UniformContainer() {
4367 // --- Utilities ---
4369 // Array Caches (provide typed arrays for temporary by size)
4371 var arrayCacheF32 = [];
4372 var arrayCacheI32 = [];
4374 // Float32Array caches used for uploading Matrix uniforms
4376 var mat4array = new Float32Array( 16 );
4377 var mat3array = new Float32Array( 9 );
4379 // Flattening for arrays of vectors and matrices
4381 function flatten( array, nBlocks, blockSize ) {
4383 var firstElem = array[ 0 ];
4385 if ( firstElem <= 0 || firstElem > 0 ) return array;
4386 // unoptimized: ! isNaN( firstElem )
4387 // see http://jacksondunstan.com/articles/983
4389 var n = nBlocks * blockSize,
4390 r = arrayCacheF32[ n ];
4392 if ( r === undefined ) {
4394 r = new Float32Array( n );
4395 arrayCacheF32[ n ] = r;
4399 if ( nBlocks !== 0 ) {
4401 firstElem.toArray( r, 0 );
4403 for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
4405 offset += blockSize;
4406 array[ i ].toArray( r, offset );
4416 // Texture unit allocation
4418 function allocTexUnits( renderer, n ) {
4420 var r = arrayCacheI32[ n ];
4422 if ( r === undefined ) {
4424 r = new Int32Array( n );
4425 arrayCacheI32[ n ] = r;
4429 for ( var i = 0; i !== n; ++ i )
4430 r[ i ] = renderer.allocTextureUnit();
4438 // Note: Defining these methods externally, because they come in a bunch
4439 // and this way their names minify.
4443 function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }
4444 function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }
4446 // Single float vector (from flat array or THREE.VectorN)
4448 function setValue2fv( gl, v ) {
4450 if ( v.x === undefined ) gl.uniform2fv( this.addr, v );
4451 else gl.uniform2f( this.addr, v.x, v.y );
4455 function setValue3fv( gl, v ) {
4457 if ( v.x !== undefined )
4458 gl.uniform3f( this.addr, v.x, v.y, v.z );
4459 else if ( v.r !== undefined )
4460 gl.uniform3f( this.addr, v.r, v.g, v.b );
4462 gl.uniform3fv( this.addr, v );
4466 function setValue4fv( gl, v ) {
4468 if ( v.x === undefined ) gl.uniform4fv( this.addr, v );
4469 else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
4473 // Single matrix (from flat array or MatrixN)
4475 function setValue2fm( gl, v ) {
4477 gl.uniformMatrix2fv( this.addr, false, v.elements || v );
4481 function setValue3fm( gl, v ) {
4483 if ( v.elements === undefined ) {
4485 gl.uniformMatrix3fv( this.addr, false, v );
4489 mat3array.set( v.elements );
4490 gl.uniformMatrix3fv( this.addr, false, mat3array );
4496 function setValue4fm( gl, v ) {
4498 if ( v.elements === undefined ) {
4500 gl.uniformMatrix4fv( this.addr, false, v );
4504 mat4array.set( v.elements );
4505 gl.uniformMatrix4fv( this.addr, false, mat4array );
4511 // Single texture (2D / Cube)
4513 function setValueT1( gl, v, renderer ) {
4515 var unit = renderer.allocTextureUnit();
4516 gl.uniform1i( this.addr, unit );
4517 renderer.setTexture2D( v || emptyTexture, unit );
4521 function setValueT6( gl, v, renderer ) {
4523 var unit = renderer.allocTextureUnit();
4524 gl.uniform1i( this.addr, unit );
4525 renderer.setTextureCube( v || emptyCubeTexture, unit );
4529 // Integer / Boolean vectors or arrays thereof (always flat arrays)
4531 function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }
4532 function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }
4533 function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }
4535 // Helper to pick the right setter for the singular case
4537 function getSingularSetter( type ) {
4541 case 0x1406: return setValue1f; // FLOAT
4542 case 0x8b50: return setValue2fv; // _VEC2
4543 case 0x8b51: return setValue3fv; // _VEC3
4544 case 0x8b52: return setValue4fv; // _VEC4
4546 case 0x8b5a: return setValue2fm; // _MAT2
4547 case 0x8b5b: return setValue3fm; // _MAT3
4548 case 0x8b5c: return setValue4fm; // _MAT4
4550 case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
4551 case 0x8b60: return setValueT6; // SAMPLER_CUBE
4553 case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
4554 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
4555 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
4556 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
4564 function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }
4565 function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }
4567 // Array of vectors (flat or from THREE classes)
4569 function setValueV2a( gl, v ) {
4571 gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );
4575 function setValueV3a( gl, v ) {
4577 gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );
4581 function setValueV4a( gl, v ) {
4583 gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );
4587 // Array of matrices (flat or from THREE clases)
4589 function setValueM2a( gl, v ) {
4591 gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );
4595 function setValueM3a( gl, v ) {
4597 gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );
4601 function setValueM4a( gl, v ) {
4603 gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );
4607 // Array of textures (2D / Cube)
4609 function setValueT1a( gl, v, renderer ) {
4612 units = allocTexUnits( renderer, n );
4614 gl.uniform1iv( this.addr, units );
4616 for ( var i = 0; i !== n; ++ i ) {
4618 renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
4624 function setValueT6a( gl, v, renderer ) {
4627 units = allocTexUnits( renderer, n );
4629 gl.uniform1iv( this.addr, units );
4631 for ( var i = 0; i !== n; ++ i ) {
4633 renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
4639 // Helper to pick the right setter for a pure (bottom-level) array
4641 function getPureArraySetter( type ) {
4645 case 0x1406: return setValue1fv; // FLOAT
4646 case 0x8b50: return setValueV2a; // _VEC2
4647 case 0x8b51: return setValueV3a; // _VEC3
4648 case 0x8b52: return setValueV4a; // _VEC4
4650 case 0x8b5a: return setValueM2a; // _MAT2
4651 case 0x8b5b: return setValueM3a; // _MAT3
4652 case 0x8b5c: return setValueM4a; // _MAT4
4654 case 0x8b5e: return setValueT1a; // SAMPLER_2D
4655 case 0x8b60: return setValueT6a; // SAMPLER_CUBE
4657 case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
4658 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
4659 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
4660 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
4666 // --- Uniform Classes ---
4668 function SingleUniform( id, activeInfo, addr ) {
4672 this.setValue = getSingularSetter( activeInfo.type );
4674 // this.path = activeInfo.name; // DEBUG
4678 function PureArrayUniform( id, activeInfo, addr ) {
4682 this.size = activeInfo.size;
4683 this.setValue = getPureArraySetter( activeInfo.type );
4685 // this.path = activeInfo.name; // DEBUG
4689 function StructuredUniform( id ) {
4693 UniformContainer.call( this ); // mix-in
4697 StructuredUniform.prototype.setValue = function ( gl, value ) {
4699 // Note: Don't need an extra 'renderer' parameter, since samplers
4700 // are not allowed in structured uniforms.
4704 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
4707 u.setValue( gl, value[ u.id ] );
4713 // --- Top-level ---
4715 // Parser - builds up the property tree from the path strings
4717 var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
4720 // - the identifier (member name or array index)
4721 // - followed by an optional right bracket (found when array index)
4722 // - followed by an optional left bracket or dot (type of subscript)
4724 // Note: These portions can be read in a non-overlapping fashion and
4725 // allow straightforward parsing of the hierarchy that WebGL encodes
4726 // in the uniform names.
4728 function addUniform( container, uniformObject ) {
4730 container.seq.push( uniformObject );
4731 container.map[ uniformObject.id ] = uniformObject;
4735 function parseUniform( activeInfo, addr, container ) {
4737 var path = activeInfo.name,
4738 pathLength = path.length;
4740 // reset RegExp object, because of the early exit of a previous run
4741 RePathPart.lastIndex = 0;
4745 var match = RePathPart.exec( path ),
4746 matchEnd = RePathPart.lastIndex,
4749 idIsIndex = match[ 2 ] === ']',
4750 subscript = match[ 3 ];
4752 if ( idIsIndex ) id = id | 0; // convert to integer
4754 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
4756 // bare name or "pure" bottom-level array "[0]" suffix
4758 addUniform( container, subscript === undefined ?
4759 new SingleUniform( id, activeInfo, addr ) :
4760 new PureArrayUniform( id, activeInfo, addr ) );
4766 // step into inner node / create it in case it doesn't exist
4768 var map = container.map, next = map[ id ];
4770 if ( next === undefined ) {
4772 next = new StructuredUniform( id );
4773 addUniform( container, next );
4787 function WebGLUniforms( gl, program, renderer ) {
4789 UniformContainer.call( this );
4791 this.renderer = renderer;
4793 var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
4795 for ( var i = 0; i < n; ++ i ) {
4797 var info = gl.getActiveUniform( program, i ),
4799 addr = gl.getUniformLocation( program, path );
4801 parseUniform( info, addr, this );
4807 WebGLUniforms.prototype.setValue = function ( gl, name, value ) {
4809 var u = this.map[ name ];
4811 if ( u !== undefined ) u.setValue( gl, value, this.renderer );
4815 WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
4817 var v = object[ name ];
4819 if ( v !== undefined ) this.setValue( gl, name, v );
4826 WebGLUniforms.upload = function ( gl, seq, values, renderer ) {
4828 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
4833 if ( v.needsUpdate !== false ) {
4835 // note: always updating when .needsUpdate is undefined
4836 u.setValue( gl, v.value, renderer );
4844 WebGLUniforms.seqWithValue = function ( seq, values ) {
4848 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
4851 if ( u.id in values ) r.push( u );
4860 * @author mrdoob / http://mrdoob.com/
4863 var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
4864 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
4865 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
4866 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
4867 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
4868 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
4869 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
4870 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
4871 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
4872 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
4873 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
4874 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
4875 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
4876 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
4877 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
4878 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
4879 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
4880 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
4881 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
4882 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
4883 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
4884 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
4885 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
4886 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
4888 function Color( r, g, b ) {
4890 if ( g === undefined && b === undefined ) {
4892 // r is THREE.Color, hex or string
4893 return this.set( r );
4897 return this.setRGB( r, g, b );
4901 Object.assign( Color.prototype, {
4907 set: function ( value ) {
4909 if ( value && value.isColor ) {
4913 } else if ( typeof value === 'number' ) {
4915 this.setHex( value );
4917 } else if ( typeof value === 'string' ) {
4919 this.setStyle( value );
4927 setScalar: function ( scalar ) {
4937 setHex: function ( hex ) {
4939 hex = Math.floor( hex );
4941 this.r = ( hex >> 16 & 255 ) / 255;
4942 this.g = ( hex >> 8 & 255 ) / 255;
4943 this.b = ( hex & 255 ) / 255;
4949 setRGB: function ( r, g, b ) {
4959 setHSL: function () {
4961 function hue2rgb( p, q, t ) {
4963 if ( t < 0 ) t += 1;
4964 if ( t > 1 ) t -= 1;
4965 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
4966 if ( t < 1 / 2 ) return q;
4967 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
4972 return function setHSL( h, s, l ) {
4974 // h,s,l ranges are in 0.0 - 1.0
4975 h = _Math.euclideanModulo( h, 1 );
4976 s = _Math.clamp( s, 0, 1 );
4977 l = _Math.clamp( l, 0, 1 );
4981 this.r = this.g = this.b = l;
4985 var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
4986 var q = ( 2 * l ) - p;
4988 this.r = hue2rgb( q, p, h + 1 / 3 );
4989 this.g = hue2rgb( q, p, h );
4990 this.b = hue2rgb( q, p, h - 1 / 3 );
5000 setStyle: function ( style ) {
5002 function handleAlpha( string ) {
5004 if ( string === undefined ) return;
5006 if ( parseFloat( string ) < 1 ) {
5008 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
5017 if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
5023 var components = m[ 2 ];
5030 if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
5032 // rgb(255,0,0) rgba(255,0,0,0.5)
5033 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
5034 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
5035 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
5037 handleAlpha( color[ 5 ] );
5043 if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
5045 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
5046 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
5047 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
5048 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
5050 handleAlpha( color[ 5 ] );
5061 if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
5063 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
5064 var h = parseFloat( color[ 1 ] ) / 360;
5065 var s = parseInt( color[ 2 ], 10 ) / 100;
5066 var l = parseInt( color[ 3 ], 10 ) / 100;
5068 handleAlpha( color[ 5 ] );
5070 return this.setHSL( h, s, l );
5078 } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
5083 var size = hex.length;
5088 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
5089 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
5090 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
5094 } else if ( size === 6 ) {
5097 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
5098 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
5099 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
5107 if ( style && style.length > 0 ) {
5110 var hex = ColorKeywords[ style ];
5112 if ( hex !== undefined ) {
5120 console.warn( 'THREE.Color: Unknown color ' + style );
5130 clone: function () {
5132 return new this.constructor( this.r, this.g, this.b );
5136 copy: function ( color ) {
5146 copyGammaToLinear: function ( color, gammaFactor ) {
5148 if ( gammaFactor === undefined ) gammaFactor = 2.0;
5150 this.r = Math.pow( color.r, gammaFactor );
5151 this.g = Math.pow( color.g, gammaFactor );
5152 this.b = Math.pow( color.b, gammaFactor );
5158 copyLinearToGamma: function ( color, gammaFactor ) {
5160 if ( gammaFactor === undefined ) gammaFactor = 2.0;
5162 var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
5164 this.r = Math.pow( color.r, safeInverse );
5165 this.g = Math.pow( color.g, safeInverse );
5166 this.b = Math.pow( color.b, safeInverse );
5172 convertGammaToLinear: function () {
5174 var r = this.r, g = this.g, b = this.b;
5184 convertLinearToGamma: function () {
5186 this.r = Math.sqrt( this.r );
5187 this.g = Math.sqrt( this.g );
5188 this.b = Math.sqrt( this.b );
5194 getHex: function () {
5196 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
5200 getHexString: function () {
5202 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
5206 getHSL: function ( optionalTarget ) {
5208 // h,s,l ranges are in 0.0 - 1.0
5210 var hsl = optionalTarget || { h: 0, s: 0, l: 0 };
5212 var r = this.r, g = this.g, b = this.b;
5214 var max = Math.max( r, g, b );
5215 var min = Math.min( r, g, b );
5217 var hue, saturation;
5218 var lightness = ( min + max ) / 2.0;
5220 if ( min === max ) {
5227 var delta = max - min;
5229 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
5233 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
5234 case g: hue = ( b - r ) / delta + 2; break;
5235 case b: hue = ( r - g ) / delta + 4; break;
5251 getStyle: function () {
5253 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
5257 offsetHSL: function ( h, s, l ) {
5259 var hsl = this.getHSL();
5261 hsl.h += h; hsl.s += s; hsl.l += l;
5263 this.setHSL( hsl.h, hsl.s, hsl.l );
5269 add: function ( color ) {
5279 addColors: function ( color1, color2 ) {
5281 this.r = color1.r + color2.r;
5282 this.g = color1.g + color2.g;
5283 this.b = color1.b + color2.b;
5289 addScalar: function ( s ) {
5299 sub: function( color ) {
5301 this.r = Math.max( 0, this.r - color.r );
5302 this.g = Math.max( 0, this.g - color.g );
5303 this.b = Math.max( 0, this.b - color.b );
5309 multiply: function ( color ) {
5319 multiplyScalar: function ( s ) {
5329 lerp: function ( color, alpha ) {
5331 this.r += ( color.r - this.r ) * alpha;
5332 this.g += ( color.g - this.g ) * alpha;
5333 this.b += ( color.b - this.b ) * alpha;
5339 equals: function ( c ) {
5341 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
5345 fromArray: function ( array, offset ) {
5347 if ( offset === undefined ) offset = 0;
5349 this.r = array[ offset ];
5350 this.g = array[ offset + 1 ];
5351 this.b = array[ offset + 2 ];
5357 toArray: function ( array, offset ) {
5359 if ( array === undefined ) array = [];
5360 if ( offset === undefined ) offset = 0;
5362 array[ offset ] = this.r;
5363 array[ offset + 1 ] = this.g;
5364 array[ offset + 2 ] = this.b;
5370 toJSON: function () {
5372 return this.getHex();
5379 * Uniforms library for shared webgl shaders
5386 diffuse: { value: new Color( 0xeeeeee ) },
5387 opacity: { value: 1.0 },
5389 map: { value: null },
5390 offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },
5392 alphaMap: { value: null },
5398 specularMap: { value: null },
5404 envMap: { value: null },
5405 flipEnvMap: { value: - 1 },
5406 reflectivity: { value: 1.0 },
5407 refractionRatio: { value: 0.98 }
5413 aoMap: { value: null },
5414 aoMapIntensity: { value: 1 }
5420 lightMap: { value: null },
5421 lightMapIntensity: { value: 1 }
5427 emissiveMap: { value: null }
5433 bumpMap: { value: null },
5434 bumpScale: { value: 1 }
5440 normalMap: { value: null },
5441 normalScale: { value: new Vector2( 1, 1 ) }
5447 displacementMap: { value: null },
5448 displacementScale: { value: 1 },
5449 displacementBias: { value: 0 }
5455 roughnessMap: { value: null }
5461 metalnessMap: { value: null }
5467 gradientMap: { value: null }
5473 fogDensity: { value: 0.00025 },
5474 fogNear: { value: 1 },
5475 fogFar: { value: 2000 },
5476 fogColor: { value: new Color( 0xffffff ) }
5482 ambientLightColor: { value: [] },
5484 directionalLights: { value: [], properties: {
5494 directionalShadowMap: { value: [] },
5495 directionalShadowMatrix: { value: [] },
5497 spotLights: { value: [], properties: {
5512 spotShadowMap: { value: [] },
5513 spotShadowMatrix: { value: [] },
5515 pointLights: { value: [], properties: {
5525 shadowCameraNear: {},
5529 pointShadowMap: { value: [] },
5530 pointShadowMatrix: { value: [] },
5532 hemisphereLights: { value: [], properties: {
5538 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
5539 rectAreaLights: { value: [], properties: {
5550 diffuse: { value: new Color( 0xeeeeee ) },
5551 opacity: { value: 1.0 },
5552 size: { value: 1.0 },
5553 scale: { value: 1.0 },
5554 map: { value: null },
5555 offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }
5565 var UniformsUtils = {
5567 merge: function ( uniforms ) {
5571 for ( var u = 0; u < uniforms.length; u ++ ) {
5573 var tmp = this.clone( uniforms[ u ] );
5575 for ( var p in tmp ) {
5577 merged[ p ] = tmp[ p ];
5587 clone: function ( uniforms_src ) {
5589 var uniforms_dst = {};
5591 for ( var u in uniforms_src ) {
5593 uniforms_dst[ u ] = {};
5595 for ( var p in uniforms_src[ u ] ) {
5597 var parameter_src = uniforms_src[ u ][ p ];
5599 if ( parameter_src && ( parameter_src.isColor ||
5600 parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
5601 parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
5602 parameter_src.isTexture ) ) {
5604 uniforms_dst[ u ][ p ] = parameter_src.clone();
5606 } else if ( Array.isArray( parameter_src ) ) {
5608 uniforms_dst[ u ][ p ] = parameter_src.slice();
5612 uniforms_dst[ u ][ p ] = parameter_src;
5620 return uniforms_dst;
5626 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
5628 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
5630 var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
5632 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( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
5634 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
5636 var begin_vertex = "\nvec3 transformed = vec3( position );\n";
5638 var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
5640 var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\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}\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 GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, 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_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 theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\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.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\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";
5642 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\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
5644 var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";
5646 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
5648 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
5650 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
5652 var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
5654 var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
5656 var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
5658 var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
5660 var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(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}\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};\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 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n";
5662 var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
5664 var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n";
5666 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
5668 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
5670 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
5672 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
5674 var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
5676 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.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\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.w );\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.w );\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.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, 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.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.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 = value.rgb * cLogLuvM;\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 = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";
5678 var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, 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_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\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\n";
5680 var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
5682 var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
5684 var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\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\n";
5686 var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
5688 var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n";
5690 var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\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\n";
5692 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\n";
5694 var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
5696 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
5698 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
5700 var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\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#endif\n#if NUM_SPOT_LIGHTS > 0\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#endif\n#if NUM_DIR_LIGHTS > 0\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#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
5702 var lights_pars = "uniform vec3 ambientLightColor;\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\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\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\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\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\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\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 ltcMat;\tuniform sampler2D ltcMag;\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\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\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\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 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 blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, 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\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
5704 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
5706 var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\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)\n";
5708 var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
5710 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#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\tfloat norm = texture2D( ltcMag, uv ).a;\n\t\tvec4 t = texture2D( ltcMat, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( 1, 0, t.y ),\n\t\t\tvec3( 0, t.z, 0 ),\n\t\t\tvec3( t.w, 0, t.x )\n\t\t);\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), 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#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\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 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\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\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\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}\n";
5712 var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\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#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * 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 ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
5714 var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif";
5716 var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
5718 var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
5720 var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n";
5722 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
5724 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
5726 var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
5728 var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n";
5730 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";
5732 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
5734 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
5736 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
5738 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
5740 var normal_fragment = "#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#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
5742 var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\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\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
5744 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 1.0 - 2.0 * rgb.xyz;\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}\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}\n";
5746 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
5748 var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n";
5750 var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";
5752 var dithering_pars_fragment = "#if defined( 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\n";
5754 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";
5756 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
5758 var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\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\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( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, 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( 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 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\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\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\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 )\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\n";
5760 var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";
5762 var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";
5764 var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
5766 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";
5768 var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform 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\n";
5770 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\n";
5772 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#endif\n";
5774 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";
5776 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
5778 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
5780 var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\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}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\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}\n";
5782 var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";
5784 var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n";
5786 var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif";
5788 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
5790 var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
5792 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
5794 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n";
5796 var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
5798 var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
5800 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>\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\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
5802 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>\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}\n";
5804 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}\n";
5806 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}\n";
5808 var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
5810 var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
5812 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 <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
5814 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 <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";
5816 var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\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_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <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\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * 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 <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
5818 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}\n";
5820 var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\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_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\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\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\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}\n";
5822 var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\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>\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}\n";
5824 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_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\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>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_template>\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}\n";
5826 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}\n";
5828 var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\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_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + 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}\n";
5830 var meshphysical_vert = "#define PHYSICAL\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}\n";
5832 var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\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>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";
5834 var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\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>\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#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#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";
5836 var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <shadowmap_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 <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
5838 var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <shadowmap_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 <project_vertex>\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
5840 var shadow_frag = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <bsdfs>\n#include <lights_pars>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n}\n";
5842 var shadow_vert = "#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n}\n";
5845 alphamap_fragment: alphamap_fragment,
5846 alphamap_pars_fragment: alphamap_pars_fragment,
5847 alphatest_fragment: alphatest_fragment,
5848 aomap_fragment: aomap_fragment,
5849 aomap_pars_fragment: aomap_pars_fragment,
5850 begin_vertex: begin_vertex,
5851 beginnormal_vertex: beginnormal_vertex,
5853 bumpmap_pars_fragment: bumpmap_pars_fragment,
5854 clipping_planes_fragment: clipping_planes_fragment,
5855 clipping_planes_pars_fragment: clipping_planes_pars_fragment,
5856 clipping_planes_pars_vertex: clipping_planes_pars_vertex,
5857 clipping_planes_vertex: clipping_planes_vertex,
5858 color_fragment: color_fragment,
5859 color_pars_fragment: color_pars_fragment,
5860 color_pars_vertex: color_pars_vertex,
5861 color_vertex: color_vertex,
5863 cube_uv_reflection_fragment: cube_uv_reflection_fragment,
5864 defaultnormal_vertex: defaultnormal_vertex,
5865 displacementmap_pars_vertex: displacementmap_pars_vertex,
5866 displacementmap_vertex: displacementmap_vertex,
5867 emissivemap_fragment: emissivemap_fragment,
5868 emissivemap_pars_fragment: emissivemap_pars_fragment,
5869 encodings_fragment: encodings_fragment,
5870 encodings_pars_fragment: encodings_pars_fragment,
5871 envmap_fragment: envmap_fragment,
5872 envmap_pars_fragment: envmap_pars_fragment,
5873 envmap_pars_vertex: envmap_pars_vertex,
5874 envmap_vertex: envmap_vertex,
5875 fog_vertex: fog_vertex,
5876 fog_pars_vertex: fog_pars_vertex,
5877 fog_fragment: fog_fragment,
5878 fog_pars_fragment: fog_pars_fragment,
5879 gradientmap_pars_fragment: gradientmap_pars_fragment,
5880 lightmap_fragment: lightmap_fragment,
5881 lightmap_pars_fragment: lightmap_pars_fragment,
5882 lights_lambert_vertex: lights_lambert_vertex,
5883 lights_pars: lights_pars,
5884 lights_phong_fragment: lights_phong_fragment,
5885 lights_phong_pars_fragment: lights_phong_pars_fragment,
5886 lights_physical_fragment: lights_physical_fragment,
5887 lights_physical_pars_fragment: lights_physical_pars_fragment,
5888 lights_template: lights_template,
5889 logdepthbuf_fragment: logdepthbuf_fragment,
5890 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
5891 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
5892 logdepthbuf_vertex: logdepthbuf_vertex,
5893 map_fragment: map_fragment,
5894 map_pars_fragment: map_pars_fragment,
5895 map_particle_fragment: map_particle_fragment,
5896 map_particle_pars_fragment: map_particle_pars_fragment,
5897 metalnessmap_fragment: metalnessmap_fragment,
5898 metalnessmap_pars_fragment: metalnessmap_pars_fragment,
5899 morphnormal_vertex: morphnormal_vertex,
5900 morphtarget_pars_vertex: morphtarget_pars_vertex,
5901 morphtarget_vertex: morphtarget_vertex,
5902 normal_fragment: normal_fragment,
5903 normalmap_pars_fragment: normalmap_pars_fragment,
5905 premultiplied_alpha_fragment: premultiplied_alpha_fragment,
5906 project_vertex: project_vertex,
5907 dithering_fragment: dithering_fragment,
5908 dithering_pars_fragment: dithering_pars_fragment,
5909 roughnessmap_fragment: roughnessmap_fragment,
5910 roughnessmap_pars_fragment: roughnessmap_pars_fragment,
5911 shadowmap_pars_fragment: shadowmap_pars_fragment,
5912 shadowmap_pars_vertex: shadowmap_pars_vertex,
5913 shadowmap_vertex: shadowmap_vertex,
5914 shadowmask_pars_fragment: shadowmask_pars_fragment,
5915 skinbase_vertex: skinbase_vertex,
5916 skinning_pars_vertex: skinning_pars_vertex,
5917 skinning_vertex: skinning_vertex,
5918 skinnormal_vertex: skinnormal_vertex,
5919 specularmap_fragment: specularmap_fragment,
5920 specularmap_pars_fragment: specularmap_pars_fragment,
5921 tonemapping_fragment: tonemapping_fragment,
5922 tonemapping_pars_fragment: tonemapping_pars_fragment,
5923 uv_pars_fragment: uv_pars_fragment,
5924 uv_pars_vertex: uv_pars_vertex,
5925 uv_vertex: uv_vertex,
5926 uv2_pars_fragment: uv2_pars_fragment,
5927 uv2_pars_vertex: uv2_pars_vertex,
5928 uv2_vertex: uv2_vertex,
5929 worldpos_vertex: worldpos_vertex,
5931 cube_frag: cube_frag,
5932 cube_vert: cube_vert,
5933 depth_frag: depth_frag,
5934 depth_vert: depth_vert,
5935 distanceRGBA_frag: distanceRGBA_frag,
5936 distanceRGBA_vert: distanceRGBA_vert,
5937 equirect_frag: equirect_frag,
5938 equirect_vert: equirect_vert,
5939 linedashed_frag: linedashed_frag,
5940 linedashed_vert: linedashed_vert,
5941 meshbasic_frag: meshbasic_frag,
5942 meshbasic_vert: meshbasic_vert,
5943 meshlambert_frag: meshlambert_frag,
5944 meshlambert_vert: meshlambert_vert,
5945 meshphong_frag: meshphong_frag,
5946 meshphong_vert: meshphong_vert,
5947 meshphysical_frag: meshphysical_frag,
5948 meshphysical_vert: meshphysical_vert,
5949 normal_frag: normal_frag,
5950 normal_vert: normal_vert,
5951 points_frag: points_frag,
5952 points_vert: points_vert,
5953 shadow_frag: shadow_frag,
5954 shadow_vert: shadow_vert
5958 * @author alteredq / http://alteredqualia.com/
5959 * @author mrdoob / http://mrdoob.com/
5960 * @author mikael emtinger / http://gomo.se/
5967 uniforms: UniformsUtils.merge( [
5969 UniformsLib.specularmap,
5972 UniformsLib.lightmap,
5976 vertexShader: ShaderChunk.meshbasic_vert,
5977 fragmentShader: ShaderChunk.meshbasic_frag
5983 uniforms: UniformsUtils.merge( [
5985 UniformsLib.specularmap,
5988 UniformsLib.lightmap,
5989 UniformsLib.emissivemap,
5993 emissive: { value: new Color( 0x000000 ) }
5997 vertexShader: ShaderChunk.meshlambert_vert,
5998 fragmentShader: ShaderChunk.meshlambert_frag
6004 uniforms: UniformsUtils.merge( [
6006 UniformsLib.specularmap,
6009 UniformsLib.lightmap,
6010 UniformsLib.emissivemap,
6011 UniformsLib.bumpmap,
6012 UniformsLib.normalmap,
6013 UniformsLib.displacementmap,
6014 UniformsLib.gradientmap,
6018 emissive: { value: new Color( 0x000000 ) },
6019 specular: { value: new Color( 0x111111 ) },
6020 shininess: { value: 30 }
6024 vertexShader: ShaderChunk.meshphong_vert,
6025 fragmentShader: ShaderChunk.meshphong_frag
6031 uniforms: UniformsUtils.merge( [
6035 UniformsLib.lightmap,
6036 UniformsLib.emissivemap,
6037 UniformsLib.bumpmap,
6038 UniformsLib.normalmap,
6039 UniformsLib.displacementmap,
6040 UniformsLib.roughnessmap,
6041 UniformsLib.metalnessmap,
6045 emissive: { value: new Color( 0x000000 ) },
6046 roughness: { value: 0.5 },
6047 metalness: { value: 0.5 },
6048 envMapIntensity: { value: 1 } // temporary
6052 vertexShader: ShaderChunk.meshphysical_vert,
6053 fragmentShader: ShaderChunk.meshphysical_frag
6059 uniforms: UniformsUtils.merge( [
6064 vertexShader: ShaderChunk.points_vert,
6065 fragmentShader: ShaderChunk.points_frag
6071 uniforms: UniformsUtils.merge( [
6075 scale: { value: 1 },
6076 dashSize: { value: 1 },
6077 totalSize: { value: 2 }
6081 vertexShader: ShaderChunk.linedashed_vert,
6082 fragmentShader: ShaderChunk.linedashed_frag
6088 uniforms: UniformsUtils.merge( [
6090 UniformsLib.displacementmap
6093 vertexShader: ShaderChunk.depth_vert,
6094 fragmentShader: ShaderChunk.depth_frag
6100 uniforms: UniformsUtils.merge( [
6102 UniformsLib.bumpmap,
6103 UniformsLib.normalmap,
6104 UniformsLib.displacementmap,
6106 opacity: { value: 1.0 }
6110 vertexShader: ShaderChunk.normal_vert,
6111 fragmentShader: ShaderChunk.normal_frag
6115 /* -------------------------------------------------------------------------
6117 ------------------------------------------------------------------------- */
6122 tCube: { value: null },
6123 tFlip: { value: - 1 },
6124 opacity: { value: 1.0 }
6127 vertexShader: ShaderChunk.cube_vert,
6128 fragmentShader: ShaderChunk.cube_frag
6135 tEquirect: { value: null },
6138 vertexShader: ShaderChunk.equirect_vert,
6139 fragmentShader: ShaderChunk.equirect_frag
6145 uniforms: UniformsUtils.merge( [
6147 UniformsLib.displacementmap,
6149 referencePosition: { value: new Vector3() },
6150 nearDistance: { value: 1 },
6151 farDistance: { value: 1000 }
6155 vertexShader: ShaderChunk.distanceRGBA_vert,
6156 fragmentShader: ShaderChunk.distanceRGBA_frag
6162 uniforms: UniformsUtils.merge( [
6165 color: { value: new Color( 0x00000 ) },
6166 opacity: { value: 1.0 }
6170 vertexShader: ShaderChunk.shadow_vert,
6171 fragmentShader: ShaderChunk.shadow_frag
6177 ShaderLib.physical = {
6179 uniforms: UniformsUtils.merge( [
6180 ShaderLib.standard.uniforms,
6182 clearCoat: { value: 0 },
6183 clearCoatRoughness: { value: 0 }
6187 vertexShader: ShaderChunk.meshphysical_vert,
6188 fragmentShader: ShaderChunk.meshphysical_frag
6193 * @author bhouston / http://clara.io
6196 function Box2( min, max ) {
6198 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
6199 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
6203 Object.assign( Box2.prototype, {
6205 set: function ( min, max ) {
6207 this.min.copy( min );
6208 this.max.copy( max );
6214 setFromPoints: function ( points ) {
6218 for ( var i = 0, il = points.length; i < il; i ++ ) {
6220 this.expandByPoint( points[ i ] );
6228 setFromCenterAndSize: function () {
6230 var v1 = new Vector2();
6232 return function setFromCenterAndSize( center, size ) {
6234 var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
6235 this.min.copy( center ).sub( halfSize );
6236 this.max.copy( center ).add( halfSize );
6244 clone: function () {
6246 return new this.constructor().copy( this );
6250 copy: function ( box ) {
6252 this.min.copy( box.min );
6253 this.max.copy( box.max );
6259 makeEmpty: function () {
6261 this.min.x = this.min.y = + Infinity;
6262 this.max.x = this.max.y = - Infinity;
6268 isEmpty: function () {
6270 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
6272 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
6276 getCenter: function ( optionalTarget ) {
6278 var result = optionalTarget || new Vector2();
6279 return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
6283 getSize: function ( optionalTarget ) {
6285 var result = optionalTarget || new Vector2();
6286 return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min );
6290 expandByPoint: function ( point ) {
6292 this.min.min( point );
6293 this.max.max( point );
6299 expandByVector: function ( vector ) {
6301 this.min.sub( vector );
6302 this.max.add( vector );
6308 expandByScalar: function ( scalar ) {
6310 this.min.addScalar( - scalar );
6311 this.max.addScalar( scalar );
6317 containsPoint: function ( point ) {
6319 return point.x < this.min.x || point.x > this.max.x ||
6320 point.y < this.min.y || point.y > this.max.y ? false : true;
6324 containsBox: function ( box ) {
6326 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
6327 this.min.y <= box.min.y && box.max.y <= this.max.y;
6331 getParameter: function ( point, optionalTarget ) {
6333 // This can potentially have a divide by zero if the box
6334 // has a size dimension of 0.
6336 var result = optionalTarget || new Vector2();
6339 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
6340 ( point.y - this.min.y ) / ( this.max.y - this.min.y )
6345 intersectsBox: function ( box ) {
6347 // using 4 splitting planes to rule out intersections
6349 return box.max.x < this.min.x || box.min.x > this.max.x ||
6350 box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
6354 clampPoint: function ( point, optionalTarget ) {
6356 var result = optionalTarget || new Vector2();
6357 return result.copy( point ).clamp( this.min, this.max );
6361 distanceToPoint: function () {
6363 var v1 = new Vector2();
6365 return function distanceToPoint( point ) {
6367 var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
6368 return clampedPoint.sub( point ).length();
6374 intersect: function ( box ) {
6376 this.min.max( box.min );
6377 this.max.min( box.max );
6383 union: function ( box ) {
6385 this.min.min( box.min );
6386 this.max.max( box.max );
6392 translate: function ( offset ) {
6394 this.min.add( offset );
6395 this.max.add( offset );
6401 equals: function ( box ) {
6403 return box.min.equals( this.min ) && box.max.equals( this.max );
6410 * @author mikael emtinger / http://gomo.se/
6411 * @author alteredq / http://alteredqualia.com/
6414 function WebGLFlareRenderer( renderer, gl, state, textures, capabilities ) {
6416 var vertexBuffer, elementBuffer;
6417 var shader, program, attributes, uniforms;
6419 var tempTexture, occlusionTexture;
6423 var vertices = new Float32Array( [
6430 var faces = new Uint16Array( [
6437 vertexBuffer = gl.createBuffer();
6438 elementBuffer = gl.createBuffer();
6440 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
6441 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
6443 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
6444 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
6448 tempTexture = gl.createTexture();
6449 occlusionTexture = gl.createTexture();
6451 state.bindTexture( gl.TEXTURE_2D, tempTexture );
6452 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );
6453 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
6454 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
6455 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
6456 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
6458 state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
6459 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
6460 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
6461 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
6462 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
6463 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
6469 "uniform lowp int renderType;",
6471 "uniform vec3 screenPosition;",
6472 "uniform vec2 scale;",
6473 "uniform float rotation;",
6475 "uniform sampler2D occlusionMap;",
6477 "attribute vec2 position;",
6478 "attribute vec2 uv;",
6480 "varying vec2 vUV;",
6481 "varying float vVisibility;",
6487 "vec2 pos = position;",
6489 "if ( renderType == 2 ) {",
6491 "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );",
6492 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );",
6493 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );",
6494 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );",
6495 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );",
6496 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );",
6497 "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );",
6498 "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );",
6499 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",
6501 "vVisibility = visibility.r / 9.0;",
6502 "vVisibility *= 1.0 - visibility.g / 9.0;",
6503 "vVisibility *= visibility.b / 9.0;",
6504 "vVisibility *= 1.0 - visibility.a / 9.0;",
6506 "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
6507 "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
6511 "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
6519 "uniform lowp int renderType;",
6521 "uniform sampler2D map;",
6522 "uniform float opacity;",
6523 "uniform vec3 color;",
6525 "varying vec2 vUV;",
6526 "varying float vVisibility;",
6532 "if ( renderType == 0 ) {",
6534 "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",
6538 "} else if ( renderType == 1 ) {",
6540 "gl_FragColor = texture2D( map, vUV );",
6546 "vec4 texture = texture2D( map, vUV );",
6547 "texture.a *= opacity * vVisibility;",
6548 "gl_FragColor = texture;",
6549 "gl_FragColor.rgb *= color;",
6559 program = createProgram( shader );
6562 vertex: gl.getAttribLocation ( program, "position" ),
6563 uv: gl.getAttribLocation ( program, "uv" )
6567 renderType: gl.getUniformLocation( program, "renderType" ),
6568 map: gl.getUniformLocation( program, "map" ),
6569 occlusionMap: gl.getUniformLocation( program, "occlusionMap" ),
6570 opacity: gl.getUniformLocation( program, "opacity" ),
6571 color: gl.getUniformLocation( program, "color" ),
6572 scale: gl.getUniformLocation( program, "scale" ),
6573 rotation: gl.getUniformLocation( program, "rotation" ),
6574 screenPosition: gl.getUniformLocation( program, "screenPosition" )
6580 * Render lens flares
6581 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
6582 * reads these back and calculates occlusion.
6585 this.render = function ( flares, scene, camera, viewport ) {
6587 if ( flares.length === 0 ) return;
6589 var tempPosition = new Vector3();
6591 var invAspect = viewport.w / viewport.z,
6592 halfViewportWidth = viewport.z * 0.5,
6593 halfViewportHeight = viewport.w * 0.5;
6595 var size = 16 / viewport.w,
6596 scale = new Vector2( size * invAspect, size );
6598 var screenPosition = new Vector3( 1, 1, 0 ),
6599 screenPositionPixels = new Vector2( 1, 1 );
6601 var validArea = new Box2();
6603 validArea.min.set( viewport.x, viewport.y );
6604 validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );
6606 if ( program === undefined ) {
6612 state.useProgram( program );
6614 state.initAttributes();
6615 state.enableAttribute( attributes.vertex );
6616 state.enableAttribute( attributes.uv );
6617 state.disableUnusedAttributes();
6619 // loop through all lens flares to update their occlusion and positions
6620 // setup gl and common used attribs/uniforms
6622 gl.uniform1i( uniforms.occlusionMap, 0 );
6623 gl.uniform1i( uniforms.map, 1 );
6625 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
6626 gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );
6627 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
6629 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
6631 state.disable( gl.CULL_FACE );
6632 state.buffers.depth.setMask( false );
6634 for ( var i = 0, l = flares.length; i < l; i ++ ) {
6636 size = 16 / viewport.w;
6637 scale.set( size * invAspect, size );
6639 // calc object screen position
6641 var flare = flares[ i ];
6643 tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] );
6645 tempPosition.applyMatrix4( camera.matrixWorldInverse );
6646 tempPosition.applyMatrix4( camera.projectionMatrix );
6648 // setup arrays for gl programs
6650 screenPosition.copy( tempPosition );
6652 // horizontal and vertical coordinate of the lower left corner of the pixels to copy
6654 screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;
6655 screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;
6659 if ( validArea.containsPoint( screenPositionPixels ) === true ) {
6661 // save current RGB to temp texture
6663 state.activeTexture( gl.TEXTURE0 );
6664 state.bindTexture( gl.TEXTURE_2D, null );
6665 state.activeTexture( gl.TEXTURE1 );
6666 state.bindTexture( gl.TEXTURE_2D, tempTexture );
6667 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
6672 gl.uniform1i( uniforms.renderType, 0 );
6673 gl.uniform2f( uniforms.scale, scale.x, scale.y );
6674 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
6676 state.disable( gl.BLEND );
6677 state.enable( gl.DEPTH_TEST );
6679 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
6682 // copy result to occlusionMap
6684 state.activeTexture( gl.TEXTURE0 );
6685 state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
6686 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
6691 gl.uniform1i( uniforms.renderType, 1 );
6692 state.disable( gl.DEPTH_TEST );
6694 state.activeTexture( gl.TEXTURE1 );
6695 state.bindTexture( gl.TEXTURE_2D, tempTexture );
6696 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
6699 // update object positions
6701 flare.positionScreen.copy( screenPosition );
6703 if ( flare.customUpdateCallback ) {
6705 flare.customUpdateCallback( flare );
6709 flare.updateLensFlares();
6715 gl.uniform1i( uniforms.renderType, 2 );
6716 state.enable( gl.BLEND );
6718 for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
6720 var sprite = flare.lensFlares[ j ];
6722 if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
6724 screenPosition.x = sprite.x;
6725 screenPosition.y = sprite.y;
6726 screenPosition.z = sprite.z;
6728 size = sprite.size * sprite.scale / viewport.w;
6730 scale.x = size * invAspect;
6733 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
6734 gl.uniform2f( uniforms.scale, scale.x, scale.y );
6735 gl.uniform1f( uniforms.rotation, sprite.rotation );
6737 gl.uniform1f( uniforms.opacity, sprite.opacity );
6738 gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
6740 state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
6742 textures.setTexture2D( sprite.texture, 1 );
6744 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
6756 state.enable( gl.CULL_FACE );
6757 state.enable( gl.DEPTH_TEST );
6758 state.buffers.depth.setMask( true );
6764 function createProgram( shader ) {
6766 var program = gl.createProgram();
6768 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
6769 var vertexShader = gl.createShader( gl.VERTEX_SHADER );
6771 var prefix = "precision " + capabilities.precision + " float;\n";
6773 gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
6774 gl.shaderSource( vertexShader, prefix + shader.vertexShader );
6776 gl.compileShader( fragmentShader );
6777 gl.compileShader( vertexShader );
6779 gl.attachShader( program, fragmentShader );
6780 gl.attachShader( program, vertexShader );
6782 gl.linkProgram( program );
6791 * @author mrdoob / http://mrdoob.com/
6794 function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
6796 Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
6798 this.needsUpdate = true;
6802 CanvasTexture.prototype = Object.create( Texture.prototype );
6803 CanvasTexture.prototype.constructor = CanvasTexture;
6806 * @author mikael emtinger / http://gomo.se/
6807 * @author alteredq / http://alteredqualia.com/
6810 function WebGLSpriteRenderer( renderer, gl, state, textures, capabilities ) {
6812 var vertexBuffer, elementBuffer;
6813 var program, attributes, uniforms;
6817 // decompose matrixWorld
6819 var spritePosition = new Vector3();
6820 var spriteRotation = new Quaternion();
6821 var spriteScale = new Vector3();
6825 var vertices = new Float32Array( [
6832 var faces = new Uint16Array( [
6837 vertexBuffer = gl.createBuffer();
6838 elementBuffer = gl.createBuffer();
6840 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
6841 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
6843 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
6844 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
6846 program = createProgram();
6849 position: gl.getAttribLocation ( program, 'position' ),
6850 uv: gl.getAttribLocation ( program, 'uv' )
6854 uvOffset: gl.getUniformLocation( program, 'uvOffset' ),
6855 uvScale: gl.getUniformLocation( program, 'uvScale' ),
6857 rotation: gl.getUniformLocation( program, 'rotation' ),
6858 scale: gl.getUniformLocation( program, 'scale' ),
6860 color: gl.getUniformLocation( program, 'color' ),
6861 map: gl.getUniformLocation( program, 'map' ),
6862 opacity: gl.getUniformLocation( program, 'opacity' ),
6864 modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ),
6865 projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ),
6867 fogType: gl.getUniformLocation( program, 'fogType' ),
6868 fogDensity: gl.getUniformLocation( program, 'fogDensity' ),
6869 fogNear: gl.getUniformLocation( program, 'fogNear' ),
6870 fogFar: gl.getUniformLocation( program, 'fogFar' ),
6871 fogColor: gl.getUniformLocation( program, 'fogColor' ),
6873 alphaTest: gl.getUniformLocation( program, 'alphaTest' )
6876 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
6880 var context = canvas.getContext( '2d' );
6881 context.fillStyle = 'white';
6882 context.fillRect( 0, 0, 8, 8 );
6884 texture = new CanvasTexture( canvas );
6888 this.render = function ( sprites, scene, camera ) {
6890 if ( sprites.length === 0 ) return;
6894 if ( program === undefined ) {
6900 state.useProgram( program );
6902 state.initAttributes();
6903 state.enableAttribute( attributes.position );
6904 state.enableAttribute( attributes.uv );
6905 state.disableUnusedAttributes();
6907 state.disable( gl.CULL_FACE );
6908 state.enable( gl.BLEND );
6910 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
6911 gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
6912 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
6914 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
6916 gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
6918 state.activeTexture( gl.TEXTURE0 );
6919 gl.uniform1i( uniforms.map, 0 );
6922 var sceneFogType = 0;
6923 var fog = scene.fog;
6927 gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
6931 gl.uniform1f( uniforms.fogNear, fog.near );
6932 gl.uniform1f( uniforms.fogFar, fog.far );
6934 gl.uniform1i( uniforms.fogType, 1 );
6938 } else if ( fog.isFogExp2 ) {
6940 gl.uniform1f( uniforms.fogDensity, fog.density );
6942 gl.uniform1i( uniforms.fogType, 2 );
6950 gl.uniform1i( uniforms.fogType, 0 );
6957 // update positions and sort
6959 for ( var i = 0, l = sprites.length; i < l; i ++ ) {
6961 var sprite = sprites[ i ];
6963 sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
6964 sprite.z = - sprite.modelViewMatrix.elements[ 14 ];
6968 sprites.sort( painterSortStable );
6970 // render all sprites
6974 for ( var i = 0, l = sprites.length; i < l; i ++ ) {
6976 var sprite = sprites[ i ];
6977 var material = sprite.material;
6979 if ( material.visible === false ) continue;
6981 sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );
6983 gl.uniform1f( uniforms.alphaTest, material.alphaTest );
6984 gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );
6986 sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );
6988 scale[ 0 ] = spriteScale.x;
6989 scale[ 1 ] = spriteScale.y;
6993 if ( scene.fog && material.fog ) {
6995 fogType = sceneFogType;
6999 if ( oldFogType !== fogType ) {
7001 gl.uniform1i( uniforms.fogType, fogType );
7002 oldFogType = fogType;
7006 if ( material.map !== null ) {
7008 gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
7009 gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
7013 gl.uniform2f( uniforms.uvOffset, 0, 0 );
7014 gl.uniform2f( uniforms.uvScale, 1, 1 );
7018 gl.uniform1f( uniforms.opacity, material.opacity );
7019 gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
7021 gl.uniform1f( uniforms.rotation, material.rotation );
7022 gl.uniform2fv( uniforms.scale, scale );
7024 state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
7025 state.buffers.depth.setTest( material.depthTest );
7026 state.buffers.depth.setMask( material.depthWrite );
7028 textures.setTexture2D( material.map || texture, 0 );
7030 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
7032 sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );
7038 state.enable( gl.CULL_FACE );
7044 function createProgram() {
7046 var program = gl.createProgram();
7048 var vertexShader = gl.createShader( gl.VERTEX_SHADER );
7049 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
7051 gl.shaderSource( vertexShader, [
7053 'precision ' + capabilities.precision + ' float;',
7055 '#define SHADER_NAME ' + 'SpriteMaterial',
7057 'uniform mat4 modelViewMatrix;',
7058 'uniform mat4 projectionMatrix;',
7059 'uniform float rotation;',
7060 'uniform vec2 scale;',
7061 'uniform vec2 uvOffset;',
7062 'uniform vec2 uvScale;',
7064 'attribute vec2 position;',
7065 'attribute vec2 uv;',
7067 'varying vec2 vUV;',
7071 'vUV = uvOffset + uv * uvScale;',
7073 'vec2 alignedPosition = position * scale;',
7075 'vec2 rotatedPosition;',
7076 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
7077 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
7079 'vec4 finalPosition;',
7081 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
7082 'finalPosition.xy += rotatedPosition;',
7083 'finalPosition = projectionMatrix * finalPosition;',
7085 'gl_Position = finalPosition;',
7091 gl.shaderSource( fragmentShader, [
7093 'precision ' + capabilities.precision + ' float;',
7095 '#define SHADER_NAME ' + 'SpriteMaterial',
7097 'uniform vec3 color;',
7098 'uniform sampler2D map;',
7099 'uniform float opacity;',
7101 'uniform int fogType;',
7102 'uniform vec3 fogColor;',
7103 'uniform float fogDensity;',
7104 'uniform float fogNear;',
7105 'uniform float fogFar;',
7106 'uniform float alphaTest;',
7108 'varying vec2 vUV;',
7112 'vec4 texture = texture2D( map, vUV );',
7114 'if ( texture.a < alphaTest ) discard;',
7116 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
7118 'if ( fogType > 0 ) {',
7120 'float depth = gl_FragCoord.z / gl_FragCoord.w;',
7121 'float fogFactor = 0.0;',
7123 'if ( fogType == 1 ) {',
7125 'fogFactor = smoothstep( fogNear, fogFar, depth );',
7129 'const float LOG2 = 1.442695;',
7130 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
7131 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
7135 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',
7143 gl.compileShader( vertexShader );
7144 gl.compileShader( fragmentShader );
7146 gl.attachShader( program, vertexShader );
7147 gl.attachShader( program, fragmentShader );
7149 gl.linkProgram( program );
7155 function painterSortStable( a, b ) {
7157 if ( a.renderOrder !== b.renderOrder ) {
7159 return a.renderOrder - b.renderOrder;
7161 } else if ( a.z !== b.z ) {
7176 * @author mrdoob / http://mrdoob.com/
7177 * @author alteredq / http://alteredqualia.com/
7182 function Material() {
7184 Object.defineProperty( this, 'id', { value: materialId ++ } );
7186 this.uuid = _Math.generateUUID();
7189 this.type = 'Material';
7194 this.blending = NormalBlending;
7195 this.side = FrontSide;
7196 this.flatShading = false;
7197 this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors
7200 this.transparent = false;
7202 this.blendSrc = SrcAlphaFactor;
7203 this.blendDst = OneMinusSrcAlphaFactor;
7204 this.blendEquation = AddEquation;
7205 this.blendSrcAlpha = null;
7206 this.blendDstAlpha = null;
7207 this.blendEquationAlpha = null;
7209 this.depthFunc = LessEqualDepth;
7210 this.depthTest = true;
7211 this.depthWrite = true;
7213 this.clippingPlanes = null;
7214 this.clipIntersection = false;
7215 this.clipShadows = false;
7217 this.colorWrite = true;
7219 this.precision = null; // override the renderer's default precision for this material
7221 this.polygonOffset = false;
7222 this.polygonOffsetFactor = 0;
7223 this.polygonOffsetUnits = 0;
7225 this.dithering = false;
7228 this.premultipliedAlpha = false;
7230 this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
7232 this.visible = true;
7236 this.needsUpdate = true;
7240 Object.assign( Material.prototype, EventDispatcher.prototype, {
7244 onBeforeCompile: function () {},
7246 setValues: function ( values ) {
7248 if ( values === undefined ) return;
7250 for ( var key in values ) {
7252 var newValue = values[ key ];
7254 if ( newValue === undefined ) {
7256 console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
7261 // for backward compatability if shading is set in the constructor
7262 if ( key === 'shading' ) {
7264 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
7265 this.flatShading = ( newValue === FlatShading ) ? true : false;
7270 var currentValue = this[ key ];
7272 if ( currentValue === undefined ) {
7274 console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
7279 if ( currentValue && currentValue.isColor ) {
7281 currentValue.set( newValue );
7283 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
7285 currentValue.copy( newValue );
7287 } else if ( key === 'overdraw' ) {
7289 // ensure overdraw is backwards-compatible with legacy boolean type
7290 this[ key ] = Number( newValue );
7294 this[ key ] = newValue;
7302 toJSON: function ( meta ) {
7304 var isRoot = meta === undefined;
7319 generator: 'Material.toJSON'
7323 // standard Material serialization
7324 data.uuid = this.uuid;
7325 data.type = this.type;
7327 if ( this.name !== '' ) data.name = this.name;
7329 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
7331 if ( this.roughness !== undefined ) data.roughness = this.roughness;
7332 if ( this.metalness !== undefined ) data.metalness = this.metalness;
7334 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
7335 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
7336 if ( this.shininess !== undefined ) data.shininess = this.shininess;
7337 if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
7338 if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;
7340 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
7341 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
7342 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
7343 if ( this.bumpMap && this.bumpMap.isTexture ) {
7345 data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
7346 data.bumpScale = this.bumpScale;
7349 if ( this.normalMap && this.normalMap.isTexture ) {
7351 data.normalMap = this.normalMap.toJSON( meta ).uuid;
7352 data.normalScale = this.normalScale.toArray();
7355 if ( this.displacementMap && this.displacementMap.isTexture ) {
7357 data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
7358 data.displacementScale = this.displacementScale;
7359 data.displacementBias = this.displacementBias;
7362 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
7363 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
7365 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
7366 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
7368 if ( this.envMap && this.envMap.isTexture ) {
7370 data.envMap = this.envMap.toJSON( meta ).uuid;
7371 data.reflectivity = this.reflectivity; // Scale behind envMap
7375 if ( this.gradientMap && this.gradientMap.isTexture ) {
7377 data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
7381 if ( this.size !== undefined ) data.size = this.size;
7382 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
7384 if ( this.blending !== NormalBlending ) data.blending = this.blending;
7385 if ( this.flatShading === true ) data.flatShading = this.flatShading;
7386 if ( this.side !== FrontSide ) data.side = this.side;
7387 if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;
7389 if ( this.opacity < 1 ) data.opacity = this.opacity;
7390 if ( this.transparent === true ) data.transparent = this.transparent;
7392 data.depthFunc = this.depthFunc;
7393 data.depthTest = this.depthTest;
7394 data.depthWrite = this.depthWrite;
7396 if ( this.dithering === true ) data.dithering = true;
7398 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
7399 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
7401 if ( this.wireframe === true ) data.wireframe = this.wireframe;
7402 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
7403 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
7404 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
7406 if ( this.morphTargets === true ) data.morphTargets = true;
7407 if ( this.skinning === true ) data.skinning = true;
7409 if ( this.visible === false ) data.visible = false;
7410 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
7412 // TODO: Copied from Object3D.toJSON
7414 function extractFromCache( cache ) {
7418 for ( var key in cache ) {
7420 var data = cache[ key ];
7421 delete data.metadata;
7422 values.push( data );
7432 var textures = extractFromCache( meta.textures );
7433 var images = extractFromCache( meta.images );
7435 if ( textures.length > 0 ) data.textures = textures;
7436 if ( images.length > 0 ) data.images = images;
7444 clone: function () {
7446 return new this.constructor().copy( this );
7450 copy: function ( source ) {
7452 this.name = source.name;
7454 this.fog = source.fog;
7455 this.lights = source.lights;
7457 this.blending = source.blending;
7458 this.side = source.side;
7459 this.flatShading = source.flatShading;
7460 this.vertexColors = source.vertexColors;
7462 this.opacity = source.opacity;
7463 this.transparent = source.transparent;
7465 this.blendSrc = source.blendSrc;
7466 this.blendDst = source.blendDst;
7467 this.blendEquation = source.blendEquation;
7468 this.blendSrcAlpha = source.blendSrcAlpha;
7469 this.blendDstAlpha = source.blendDstAlpha;
7470 this.blendEquationAlpha = source.blendEquationAlpha;
7472 this.depthFunc = source.depthFunc;
7473 this.depthTest = source.depthTest;
7474 this.depthWrite = source.depthWrite;
7476 this.colorWrite = source.colorWrite;
7478 this.precision = source.precision;
7480 this.polygonOffset = source.polygonOffset;
7481 this.polygonOffsetFactor = source.polygonOffsetFactor;
7482 this.polygonOffsetUnits = source.polygonOffsetUnits;
7484 this.dithering = source.dithering;
7486 this.alphaTest = source.alphaTest;
7487 this.premultipliedAlpha = source.premultipliedAlpha;
7489 this.overdraw = source.overdraw;
7491 this.visible = source.visible;
7492 this.userData = JSON.parse( JSON.stringify( source.userData ) );
7494 this.clipShadows = source.clipShadows;
7495 this.clipIntersection = source.clipIntersection;
7497 var srcPlanes = source.clippingPlanes,
7500 if ( srcPlanes !== null ) {
7502 var n = srcPlanes.length;
7503 dstPlanes = new Array( n );
7505 for ( var i = 0; i !== n; ++ i )
7506 dstPlanes[ i ] = srcPlanes[ i ].clone();
7510 this.clippingPlanes = dstPlanes;
7516 dispose: function () {
7518 this.dispatchEvent( { type: 'dispose' } );
7525 * @author alteredq / http://alteredqualia.com/
7528 * defines: { "label" : "value" },
7529 * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
7531 * fragmentShader: <string>,
7532 * vertexShader: <string>,
7534 * wireframe: <boolean>,
7535 * wireframeLinewidth: <float>,
7540 * morphTargets: <bool>,
7541 * morphNormals: <bool>
7545 function ShaderMaterial( parameters ) {
7547 Material.call( this );
7549 this.type = 'ShaderMaterial';
7554 this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
7555 this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
7559 this.wireframe = false;
7560 this.wireframeLinewidth = 1;
7562 this.fog = false; // set to use scene fog
7563 this.lights = false; // set to use scene lights
7564 this.clipping = false; // set to use user-defined clipping planes
7566 this.skinning = false; // set to use skinning attribute streams
7567 this.morphTargets = false; // set to use morph targets
7568 this.morphNormals = false; // set to use morph normals
7571 derivatives: false, // set to use derivatives
7572 fragDepth: false, // set to use fragment depth values
7573 drawBuffers: false, // set to use draw buffers
7574 shaderTextureLOD: false // set to use shader texture LOD
7577 // When rendered geometry doesn't include these attributes but the material does,
7578 // use these default values in WebGL. This avoids errors when buffer data is missing.
7579 this.defaultAttributeValues = {
7580 'color': [ 1, 1, 1 ],
7585 this.index0AttributeName = undefined;
7587 if ( parameters !== undefined ) {
7589 if ( parameters.attributes !== undefined ) {
7591 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
7595 this.setValues( parameters );
7601 ShaderMaterial.prototype = Object.create( Material.prototype );
7602 ShaderMaterial.prototype.constructor = ShaderMaterial;
7604 ShaderMaterial.prototype.isShaderMaterial = true;
7606 ShaderMaterial.prototype.copy = function ( source ) {
7608 Material.prototype.copy.call( this, source );
7610 this.fragmentShader = source.fragmentShader;
7611 this.vertexShader = source.vertexShader;
7613 this.uniforms = UniformsUtils.clone( source.uniforms );
7615 this.defines = source.defines;
7617 this.wireframe = source.wireframe;
7618 this.wireframeLinewidth = source.wireframeLinewidth;
7620 this.lights = source.lights;
7621 this.clipping = source.clipping;
7623 this.skinning = source.skinning;
7625 this.morphTargets = source.morphTargets;
7626 this.morphNormals = source.morphNormals;
7628 this.extensions = source.extensions;
7634 ShaderMaterial.prototype.toJSON = function ( meta ) {
7636 var data = Material.prototype.toJSON.call( this, meta );
7638 data.uniforms = this.uniforms;
7639 data.vertexShader = this.vertexShader;
7640 data.fragmentShader = this.fragmentShader;
7647 * @author mrdoob / http://mrdoob.com/
7648 * @author alteredq / http://alteredqualia.com/
7649 * @author bhouston / https://clara.io
7650 * @author WestLangley / http://github.com/WestLangley
7656 * map: new THREE.Texture( <Image> ),
7658 * alphaMap: new THREE.Texture( <Image> ),
7660 * displacementMap: new THREE.Texture( <Image> ),
7661 * displacementScale: <float>,
7662 * displacementBias: <float>,
7664 * wireframe: <boolean>,
7665 * wireframeLinewidth: <float>
7669 function MeshDepthMaterial( parameters ) {
7671 Material.call( this );
7673 this.type = 'MeshDepthMaterial';
7675 this.depthPacking = BasicDepthPacking;
7677 this.skinning = false;
7678 this.morphTargets = false;
7682 this.alphaMap = null;
7684 this.displacementMap = null;
7685 this.displacementScale = 1;
7686 this.displacementBias = 0;
7688 this.wireframe = false;
7689 this.wireframeLinewidth = 1;
7692 this.lights = false;
7694 this.setValues( parameters );
7698 MeshDepthMaterial.prototype = Object.create( Material.prototype );
7699 MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
7701 MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
7703 MeshDepthMaterial.prototype.copy = function ( source ) {
7705 Material.prototype.copy.call( this, source );
7707 this.depthPacking = source.depthPacking;
7709 this.skinning = source.skinning;
7710 this.morphTargets = source.morphTargets;
7712 this.map = source.map;
7714 this.alphaMap = source.alphaMap;
7716 this.displacementMap = source.displacementMap;
7717 this.displacementScale = source.displacementScale;
7718 this.displacementBias = source.displacementBias;
7720 this.wireframe = source.wireframe;
7721 this.wireframeLinewidth = source.wireframeLinewidth;
7728 * @author WestLangley / http://github.com/WestLangley
7732 * referencePosition: <float>,
7733 * nearDistance: <float>,
7734 * farDistance: <float>,
7737 * morphTargets: <bool>,
7739 * map: new THREE.Texture( <Image> ),
7741 * alphaMap: new THREE.Texture( <Image> ),
7743 * displacementMap: new THREE.Texture( <Image> ),
7744 * displacementScale: <float>,
7745 * displacementBias: <float>
7750 function MeshDistanceMaterial( parameters ) {
7752 Material.call( this );
7754 this.type = 'MeshDistanceMaterial';
7756 this.referencePosition = new Vector3();
7757 this.nearDistance = 1;
7758 this.farDistance = 1000;
7760 this.skinning = false;
7761 this.morphTargets = false;
7765 this.alphaMap = null;
7767 this.displacementMap = null;
7768 this.displacementScale = 1;
7769 this.displacementBias = 0;
7772 this.lights = false;
7774 this.setValues( parameters );
7778 MeshDistanceMaterial.prototype = Object.create( Material.prototype );
7779 MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
7781 MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
7783 MeshDistanceMaterial.prototype.copy = function ( source ) {
7785 Material.prototype.copy.call( this, source );
7787 this.referencePosition.copy( source.referencePosition );
7788 this.nearDistance = source.nearDistance;
7789 this.farDistance = source.farDistance;
7791 this.skinning = source.skinning;
7792 this.morphTargets = source.morphTargets;
7794 this.map = source.map;
7796 this.alphaMap = source.alphaMap;
7798 this.displacementMap = source.displacementMap;
7799 this.displacementScale = source.displacementScale;
7800 this.displacementBias = source.displacementBias;
7807 * @author bhouston / http://clara.io
7808 * @author WestLangley / http://github.com/WestLangley
7811 function Box3( min, max ) {
7813 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
7814 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
7818 Object.assign( Box3.prototype, {
7822 set: function ( min, max ) {
7824 this.min.copy( min );
7825 this.max.copy( max );
7831 setFromArray: function ( array ) {
7833 var minX = + Infinity;
7834 var minY = + Infinity;
7835 var minZ = + Infinity;
7837 var maxX = - Infinity;
7838 var maxY = - Infinity;
7839 var maxZ = - Infinity;
7841 for ( var i = 0, l = array.length; i < l; i += 3 ) {
7844 var y = array[ i + 1 ];
7845 var z = array[ i + 2 ];
7847 if ( x < minX ) minX = x;
7848 if ( y < minY ) minY = y;
7849 if ( z < minZ ) minZ = z;
7851 if ( x > maxX ) maxX = x;
7852 if ( y > maxY ) maxY = y;
7853 if ( z > maxZ ) maxZ = z;
7857 this.min.set( minX, minY, minZ );
7858 this.max.set( maxX, maxY, maxZ );
7864 setFromBufferAttribute: function ( attribute ) {
7866 var minX = + Infinity;
7867 var minY = + Infinity;
7868 var minZ = + Infinity;
7870 var maxX = - Infinity;
7871 var maxY = - Infinity;
7872 var maxZ = - Infinity;
7874 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
7876 var x = attribute.getX( i );
7877 var y = attribute.getY( i );
7878 var z = attribute.getZ( i );
7880 if ( x < minX ) minX = x;
7881 if ( y < minY ) minY = y;
7882 if ( z < minZ ) minZ = z;
7884 if ( x > maxX ) maxX = x;
7885 if ( y > maxY ) maxY = y;
7886 if ( z > maxZ ) maxZ = z;
7890 this.min.set( minX, minY, minZ );
7891 this.max.set( maxX, maxY, maxZ );
7897 setFromPoints: function ( points ) {
7901 for ( var i = 0, il = points.length; i < il; i ++ ) {
7903 this.expandByPoint( points[ i ] );
7911 setFromCenterAndSize: function () {
7913 var v1 = new Vector3();
7915 return function setFromCenterAndSize( center, size ) {
7917 var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
7919 this.min.copy( center ).sub( halfSize );
7920 this.max.copy( center ).add( halfSize );
7928 setFromObject: function ( object ) {
7932 return this.expandByObject( object );
7936 clone: function () {
7938 return new this.constructor().copy( this );
7942 copy: function ( box ) {
7944 this.min.copy( box.min );
7945 this.max.copy( box.max );
7951 makeEmpty: function () {
7953 this.min.x = this.min.y = this.min.z = + Infinity;
7954 this.max.x = this.max.y = this.max.z = - Infinity;
7960 isEmpty: function () {
7962 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
7964 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
7968 getCenter: function ( optionalTarget ) {
7970 var result = optionalTarget || new Vector3();
7971 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
7975 getSize: function ( optionalTarget ) {
7977 var result = optionalTarget || new Vector3();
7978 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min );
7982 expandByPoint: function ( point ) {
7984 this.min.min( point );
7985 this.max.max( point );
7991 expandByVector: function ( vector ) {
7993 this.min.sub( vector );
7994 this.max.add( vector );
8000 expandByScalar: function ( scalar ) {
8002 this.min.addScalar( - scalar );
8003 this.max.addScalar( scalar );
8009 expandByObject: function () {
8011 // Computes the world-axis-aligned bounding box of an object (including its children),
8012 // accounting for both the object's, and children's, world transforms
8014 var v1 = new Vector3();
8016 return function expandByObject( object ) {
8020 object.updateMatrixWorld( true );
8022 object.traverse( function ( node ) {
8026 var geometry = node.geometry;
8028 if ( geometry !== undefined ) {
8030 if ( geometry.isGeometry ) {
8032 var vertices = geometry.vertices;
8034 for ( i = 0, l = vertices.length; i < l; i ++ ) {
8036 v1.copy( vertices[ i ] );
8037 v1.applyMatrix4( node.matrixWorld );
8039 scope.expandByPoint( v1 );
8043 } else if ( geometry.isBufferGeometry ) {
8045 var attribute = geometry.attributes.position;
8047 if ( attribute !== undefined ) {
8049 for ( i = 0, l = attribute.count; i < l; i ++ ) {
8051 v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
8053 scope.expandByPoint( v1 );
8071 containsPoint: function ( point ) {
8073 return point.x < this.min.x || point.x > this.max.x ||
8074 point.y < this.min.y || point.y > this.max.y ||
8075 point.z < this.min.z || point.z > this.max.z ? false : true;
8079 containsBox: function ( box ) {
8081 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
8082 this.min.y <= box.min.y && box.max.y <= this.max.y &&
8083 this.min.z <= box.min.z && box.max.z <= this.max.z;
8087 getParameter: function ( point, optionalTarget ) {
8089 // This can potentially have a divide by zero if the box
8090 // has a size dimension of 0.
8092 var result = optionalTarget || new Vector3();
8095 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
8096 ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
8097 ( point.z - this.min.z ) / ( this.max.z - this.min.z )
8102 intersectsBox: function ( box ) {
8104 // using 6 splitting planes to rule out intersections.
8105 return box.max.x < this.min.x || box.min.x > this.max.x ||
8106 box.max.y < this.min.y || box.min.y > this.max.y ||
8107 box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
8111 intersectsSphere: ( function () {
8113 var closestPoint = new Vector3();
8115 return function intersectsSphere( sphere ) {
8117 // Find the point on the AABB closest to the sphere center.
8118 this.clampPoint( sphere.center, closestPoint );
8120 // If that point is inside the sphere, the AABB and sphere intersect.
8121 return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
8127 intersectsPlane: function ( plane ) {
8129 // We compute the minimum and maximum dot product values. If those values
8130 // are on the same side (back or front) of the plane, then there is no intersection.
8134 if ( plane.normal.x > 0 ) {
8136 min = plane.normal.x * this.min.x;
8137 max = plane.normal.x * this.max.x;
8141 min = plane.normal.x * this.max.x;
8142 max = plane.normal.x * this.min.x;
8146 if ( plane.normal.y > 0 ) {
8148 min += plane.normal.y * this.min.y;
8149 max += plane.normal.y * this.max.y;
8153 min += plane.normal.y * this.max.y;
8154 max += plane.normal.y * this.min.y;
8158 if ( plane.normal.z > 0 ) {
8160 min += plane.normal.z * this.min.z;
8161 max += plane.normal.z * this.max.z;
8165 min += plane.normal.z * this.max.z;
8166 max += plane.normal.z * this.min.z;
8170 return ( min <= plane.constant && max >= plane.constant );
8174 clampPoint: function ( point, optionalTarget ) {
8176 var result = optionalTarget || new Vector3();
8177 return result.copy( point ).clamp( this.min, this.max );
8181 distanceToPoint: function () {
8183 var v1 = new Vector3();
8185 return function distanceToPoint( point ) {
8187 var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
8188 return clampedPoint.sub( point ).length();
8194 getBoundingSphere: function () {
8196 var v1 = new Vector3();
8198 return function getBoundingSphere( optionalTarget ) {
8200 var result = optionalTarget || new Sphere();
8202 this.getCenter( result.center );
8204 result.radius = this.getSize( v1 ).length() * 0.5;
8212 intersect: function ( box ) {
8214 this.min.max( box.min );
8215 this.max.min( box.max );
8217 // 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.
8218 if( this.isEmpty() ) this.makeEmpty();
8224 union: function ( box ) {
8226 this.min.min( box.min );
8227 this.max.max( box.max );
8233 applyMatrix4: function () {
8246 return function applyMatrix4( matrix ) {
8248 // transform of empty box is an empty box.
8249 if( this.isEmpty() ) return this;
8251 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
8252 points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
8253 points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
8254 points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
8255 points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
8256 points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
8257 points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
8258 points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
8259 points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
8261 this.setFromPoints( points );
8269 translate: function ( offset ) {
8271 this.min.add( offset );
8272 this.max.add( offset );
8278 equals: function ( box ) {
8280 return box.min.equals( this.min ) && box.max.equals( this.max );
8287 * @author bhouston / http://clara.io
8288 * @author mrdoob / http://mrdoob.com/
8291 function Sphere( center, radius ) {
8293 this.center = ( center !== undefined ) ? center : new Vector3();
8294 this.radius = ( radius !== undefined ) ? radius : 0;
8298 Object.assign( Sphere.prototype, {
8300 set: function ( center, radius ) {
8302 this.center.copy( center );
8303 this.radius = radius;
8309 setFromPoints: function () {
8311 var box = new Box3();
8313 return function setFromPoints( points, optionalCenter ) {
8315 var center = this.center;
8317 if ( optionalCenter !== undefined ) {
8319 center.copy( optionalCenter );
8323 box.setFromPoints( points ).getCenter( center );
8327 var maxRadiusSq = 0;
8329 for ( var i = 0, il = points.length; i < il; i ++ ) {
8331 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
8335 this.radius = Math.sqrt( maxRadiusSq );
8343 clone: function () {
8345 return new this.constructor().copy( this );
8349 copy: function ( sphere ) {
8351 this.center.copy( sphere.center );
8352 this.radius = sphere.radius;
8358 empty: function () {
8360 return ( this.radius <= 0 );
8364 containsPoint: function ( point ) {
8366 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
8370 distanceToPoint: function ( point ) {
8372 return ( point.distanceTo( this.center ) - this.radius );
8376 intersectsSphere: function ( sphere ) {
8378 var radiusSum = this.radius + sphere.radius;
8380 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
8384 intersectsBox: function ( box ) {
8386 return box.intersectsSphere( this );
8390 intersectsPlane: function ( plane ) {
8392 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
8396 clampPoint: function ( point, optionalTarget ) {
8398 var deltaLengthSq = this.center.distanceToSquared( point );
8400 var result = optionalTarget || new Vector3();
8402 result.copy( point );
8404 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
8406 result.sub( this.center ).normalize();
8407 result.multiplyScalar( this.radius ).add( this.center );
8415 getBoundingBox: function ( optionalTarget ) {
8417 var box = optionalTarget || new Box3();
8419 box.set( this.center, this.center );
8420 box.expandByScalar( this.radius );
8426 applyMatrix4: function ( matrix ) {
8428 this.center.applyMatrix4( matrix );
8429 this.radius = this.radius * matrix.getMaxScaleOnAxis();
8435 translate: function ( offset ) {
8437 this.center.add( offset );
8443 equals: function ( sphere ) {
8445 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
8452 * @author alteredq / http://alteredqualia.com/
8453 * @author WestLangley / http://github.com/WestLangley
8454 * @author bhouston / http://clara.io
8458 function Matrix3() {
8468 if ( arguments.length > 0 ) {
8470 console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
8476 Object.assign( Matrix3.prototype, {
8480 set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
8482 var te = this.elements;
8484 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
8485 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
8486 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
8492 identity: function () {
8506 clone: function () {
8508 return new this.constructor().fromArray( this.elements );
8512 copy: function ( m ) {
8514 var te = this.elements;
8515 var me = m.elements;
8517 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
8518 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
8519 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
8525 setFromMatrix4: function ( m ) {
8527 var me = m.elements;
8531 me[ 0 ], me[ 4 ], me[ 8 ],
8532 me[ 1 ], me[ 5 ], me[ 9 ],
8533 me[ 2 ], me[ 6 ], me[ 10 ]
8541 applyToBufferAttribute: function () {
8543 var v1 = new Vector3();
8545 return function applyToBufferAttribute( attribute ) {
8547 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
8549 v1.x = attribute.getX( i );
8550 v1.y = attribute.getY( i );
8551 v1.z = attribute.getZ( i );
8553 v1.applyMatrix3( this );
8555 attribute.setXYZ( i, v1.x, v1.y, v1.z );
8565 multiply: function ( m ) {
8567 return this.multiplyMatrices( this, m );
8571 premultiply: function ( m ) {
8573 return this.multiplyMatrices( m, this );
8577 multiplyMatrices: function ( a, b ) {
8579 var ae = a.elements;
8580 var be = b.elements;
8581 var te = this.elements;
8583 var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
8584 var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
8585 var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
8587 var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
8588 var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
8589 var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
8591 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
8592 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
8593 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
8595 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
8596 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
8597 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
8599 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
8600 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
8601 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
8607 multiplyScalar: function ( s ) {
8609 var te = this.elements;
8611 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
8612 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
8613 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
8619 determinant: function () {
8621 var te = this.elements;
8623 var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
8624 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
8625 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
8627 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
8631 getInverse: function ( matrix, throwOnDegenerate ) {
8633 if ( matrix && matrix.isMatrix4 ) {
8635 console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );
8639 var me = matrix.elements,
8642 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
8643 n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
8644 n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],
8646 t11 = n33 * n22 - n32 * n23,
8647 t12 = n32 * n13 - n33 * n12,
8648 t13 = n23 * n12 - n22 * n13,
8650 det = n11 * t11 + n21 * t12 + n31 * t13;
8654 var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
8656 if ( throwOnDegenerate === true ) {
8658 throw new Error( msg );
8662 console.warn( msg );
8666 return this.identity();
8670 var detInv = 1 / det;
8672 te[ 0 ] = t11 * detInv;
8673 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
8674 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
8676 te[ 3 ] = t12 * detInv;
8677 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
8678 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
8680 te[ 6 ] = t13 * detInv;
8681 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
8682 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
8688 transpose: function () {
8690 var tmp, m = this.elements;
8692 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
8693 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
8694 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
8700 getNormalMatrix: function ( matrix4 ) {
8702 return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();
8706 transposeIntoArray: function ( r ) {
8708 var m = this.elements;
8724 equals: function ( matrix ) {
8726 var te = this.elements;
8727 var me = matrix.elements;
8729 for ( var i = 0; i < 9; i ++ ) {
8731 if ( te[ i ] !== me[ i ] ) return false;
8739 fromArray: function ( array, offset ) {
8741 if ( offset === undefined ) offset = 0;
8743 for ( var i = 0; i < 9; i ++ ) {
8745 this.elements[ i ] = array[ i + offset ];
8753 toArray: function ( array, offset ) {
8755 if ( array === undefined ) array = [];
8756 if ( offset === undefined ) offset = 0;
8758 var te = this.elements;
8760 array[ offset ] = te[ 0 ];
8761 array[ offset + 1 ] = te[ 1 ];
8762 array[ offset + 2 ] = te[ 2 ];
8764 array[ offset + 3 ] = te[ 3 ];
8765 array[ offset + 4 ] = te[ 4 ];
8766 array[ offset + 5 ] = te[ 5 ];
8768 array[ offset + 6 ] = te[ 6 ];
8769 array[ offset + 7 ] = te[ 7 ];
8770 array[ offset + 8 ] = te[ 8 ];
8779 * @author bhouston / http://clara.io
8782 function Plane( normal, constant ) {
8784 // normal is assumed to be normalized
8786 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
8787 this.constant = ( constant !== undefined ) ? constant : 0;
8791 Object.assign( Plane.prototype, {
8793 set: function ( normal, constant ) {
8795 this.normal.copy( normal );
8796 this.constant = constant;
8802 setComponents: function ( x, y, z, w ) {
8804 this.normal.set( x, y, z );
8811 setFromNormalAndCoplanarPoint: function ( normal, point ) {
8813 this.normal.copy( normal );
8814 this.constant = - point.dot( this.normal );
8820 setFromCoplanarPoints: function () {
8822 var v1 = new Vector3();
8823 var v2 = new Vector3();
8825 return function setFromCoplanarPoints( a, b, c ) {
8827 var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
8829 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
8831 this.setFromNormalAndCoplanarPoint( normal, a );
8839 clone: function () {
8841 return new this.constructor().copy( this );
8845 copy: function ( plane ) {
8847 this.normal.copy( plane.normal );
8848 this.constant = plane.constant;
8854 normalize: function () {
8856 // Note: will lead to a divide by zero if the plane is invalid.
8858 var inverseNormalLength = 1.0 / this.normal.length();
8859 this.normal.multiplyScalar( inverseNormalLength );
8860 this.constant *= inverseNormalLength;
8866 negate: function () {
8868 this.constant *= - 1;
8869 this.normal.negate();
8875 distanceToPoint: function ( point ) {
8877 return this.normal.dot( point ) + this.constant;
8881 distanceToSphere: function ( sphere ) {
8883 return this.distanceToPoint( sphere.center ) - sphere.radius;
8887 projectPoint: function ( point, optionalTarget ) {
8889 var result = optionalTarget || new Vector3();
8891 return result.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
8895 intersectLine: function () {
8897 var v1 = new Vector3();
8899 return function intersectLine( line, optionalTarget ) {
8901 var result = optionalTarget || new Vector3();
8903 var direction = line.delta( v1 );
8905 var denominator = this.normal.dot( direction );
8907 if ( denominator === 0 ) {
8909 // line is coplanar, return origin
8910 if ( this.distanceToPoint( line.start ) === 0 ) {
8912 return result.copy( line.start );
8916 // Unsure if this is the correct method to handle this case.
8921 var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
8923 if ( t < 0 || t > 1 ) {
8929 return result.copy( direction ).multiplyScalar( t ).add( line.start );
8935 intersectsLine: function ( line ) {
8937 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
8939 var startSign = this.distanceToPoint( line.start );
8940 var endSign = this.distanceToPoint( line.end );
8942 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
8946 intersectsBox: function ( box ) {
8948 return box.intersectsPlane( this );
8952 intersectsSphere: function ( sphere ) {
8954 return sphere.intersectsPlane( this );
8958 coplanarPoint: function ( optionalTarget ) {
8960 var result = optionalTarget || new Vector3();
8962 return result.copy( this.normal ).multiplyScalar( - this.constant );
8966 applyMatrix4: function () {
8968 var v1 = new Vector3();
8969 var m1 = new Matrix3();
8971 return function applyMatrix4( matrix, optionalNormalMatrix ) {
8973 var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
8975 var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
8977 var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
8979 this.constant = - referencePoint.dot( normal );
8987 translate: function ( offset ) {
8989 this.constant -= offset.dot( this.normal );
8995 equals: function ( plane ) {
8997 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
9004 * @author mrdoob / http://mrdoob.com/
9005 * @author alteredq / http://alteredqualia.com/
9006 * @author bhouston / http://clara.io
9009 function Frustum( p0, p1, p2, p3, p4, p5 ) {
9013 ( p0 !== undefined ) ? p0 : new Plane(),
9014 ( p1 !== undefined ) ? p1 : new Plane(),
9015 ( p2 !== undefined ) ? p2 : new Plane(),
9016 ( p3 !== undefined ) ? p3 : new Plane(),
9017 ( p4 !== undefined ) ? p4 : new Plane(),
9018 ( p5 !== undefined ) ? p5 : new Plane()
9024 Object.assign( Frustum.prototype, {
9026 set: function ( p0, p1, p2, p3, p4, p5 ) {
9028 var planes = this.planes;
9030 planes[ 0 ].copy( p0 );
9031 planes[ 1 ].copy( p1 );
9032 planes[ 2 ].copy( p2 );
9033 planes[ 3 ].copy( p3 );
9034 planes[ 4 ].copy( p4 );
9035 planes[ 5 ].copy( p5 );
9041 clone: function () {
9043 return new this.constructor().copy( this );
9047 copy: function ( frustum ) {
9049 var planes = this.planes;
9051 for ( var i = 0; i < 6; i ++ ) {
9053 planes[ i ].copy( frustum.planes[ i ] );
9061 setFromMatrix: function ( m ) {
9063 var planes = this.planes;
9064 var me = m.elements;
9065 var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
9066 var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
9067 var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
9068 var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
9070 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
9071 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
9072 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
9073 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
9074 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
9075 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
9081 intersectsObject: function () {
9083 var sphere = new Sphere();
9085 return function intersectsObject( object ) {
9087 var geometry = object.geometry;
9089 if ( geometry.boundingSphere === null )
9090 geometry.computeBoundingSphere();
9092 sphere.copy( geometry.boundingSphere )
9093 .applyMatrix4( object.matrixWorld );
9095 return this.intersectsSphere( sphere );
9101 intersectsSprite: function () {
9103 var sphere = new Sphere();
9105 return function intersectsSprite( sprite ) {
9107 sphere.center.set( 0, 0, 0 );
9108 sphere.radius = 0.7071067811865476;
9109 sphere.applyMatrix4( sprite.matrixWorld );
9111 return this.intersectsSphere( sphere );
9117 intersectsSphere: function ( sphere ) {
9119 var planes = this.planes;
9120 var center = sphere.center;
9121 var negRadius = - sphere.radius;
9123 for ( var i = 0; i < 6; i ++ ) {
9125 var distance = planes[ i ].distanceToPoint( center );
9127 if ( distance < negRadius ) {
9139 intersectsBox: function () {
9141 var p1 = new Vector3(),
9144 return function intersectsBox( box ) {
9146 var planes = this.planes;
9148 for ( var i = 0; i < 6; i ++ ) {
9150 var plane = planes[ i ];
9152 p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
9153 p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
9154 p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
9155 p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
9156 p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
9157 p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
9159 var d1 = plane.distanceToPoint( p1 );
9160 var d2 = plane.distanceToPoint( p2 );
9162 // if both outside plane, no intersection
9164 if ( d1 < 0 && d2 < 0 ) {
9178 containsPoint: function ( point ) {
9180 var planes = this.planes;
9182 for ( var i = 0; i < 6; i ++ ) {
9184 if ( planes[ i ].distanceToPoint( point ) < 0 ) {
9199 * @author alteredq / http://alteredqualia.com/
9200 * @author mrdoob / http://mrdoob.com/
9203 function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
9205 var _frustum = new Frustum(),
9206 _projScreenMatrix = new Matrix4(),
9208 _shadowMapSize = new Vector2(),
9209 _maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),
9211 _lookTarget = new Vector3(),
9212 _lightPositionWorld = new Vector3(),
9217 _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
9219 _depthMaterials = new Array( _NumberOfMaterialVariants ),
9220 _distanceMaterials = new Array( _NumberOfMaterialVariants ),
9222 _materialCache = {};
9224 var cubeDirections = [
9225 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
9226 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
9230 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
9231 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
9234 var cube2DViewPorts = [
9235 new Vector4(), new Vector4(), new Vector4(),
9236 new Vector4(), new Vector4(), new Vector4()
9241 for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {
9243 var useMorphing = ( i & _MorphingFlag ) !== 0;
9244 var useSkinning = ( i & _SkinningFlag ) !== 0;
9246 var depthMaterial = new MeshDepthMaterial( {
9248 depthPacking: RGBADepthPacking,
9250 morphTargets: useMorphing,
9251 skinning: useSkinning
9255 _depthMaterials[ i ] = depthMaterial;
9259 var distanceMaterial = new MeshDistanceMaterial( {
9261 morphTargets: useMorphing,
9262 skinning: useSkinning
9266 _distanceMaterials[ i ] = distanceMaterial;
9274 this.enabled = false;
9276 this.autoUpdate = true;
9277 this.needsUpdate = false;
9279 this.type = PCFShadowMap;
9281 this.renderReverseSided = true;
9282 this.renderSingleSided = true;
9284 this.render = function ( lights, scene, camera ) {
9286 if ( scope.enabled === false ) return;
9287 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
9289 if ( lights.length === 0 ) return;
9291 // TODO Clean up (needed in case of contextlost)
9292 var _gl = _renderer.context;
9293 var _state = _renderer.state;
9295 // Set GL state for depth map.
9296 _state.disable( _gl.BLEND );
9297 _state.buffers.color.setClear( 1, 1, 1, 1 );
9298 _state.buffers.depth.setTest( true );
9299 _state.setScissorTest( false );
9305 for ( var i = 0, il = lights.length; i < il; i ++ ) {
9307 var light = lights[ i ];
9308 var shadow = light.shadow;
9309 var isPointLight = light && light.isPointLight;
9311 if ( shadow === undefined ) {
9313 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
9318 var shadowCamera = shadow.camera;
9320 _shadowMapSize.copy( shadow.mapSize );
9321 _shadowMapSize.min( _maxShadowMapSize );
9323 if ( isPointLight ) {
9325 var vpWidth = _shadowMapSize.x;
9326 var vpHeight = _shadowMapSize.y;
9328 // These viewports map a cube-map onto a 2D texture with the
9329 // following orientation:
9334 // X - Positive x direction
9335 // x - Negative x direction
9336 // Y - Positive y direction
9337 // y - Negative y direction
9338 // Z - Positive z direction
9339 // z - Negative z direction
9342 cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
9344 cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
9346 cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
9348 cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
9350 cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
9352 cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
9354 _shadowMapSize.x *= 4.0;
9355 _shadowMapSize.y *= 2.0;
9359 if ( shadow.map === null ) {
9361 var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
9363 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
9364 shadow.map.texture.name = light.name + ".shadowMap";
9366 shadowCamera.updateProjectionMatrix();
9370 if ( shadow.isSpotLightShadow ) {
9372 shadow.update( light );
9376 var shadowMap = shadow.map;
9377 var shadowMatrix = shadow.matrix;
9379 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
9380 shadowCamera.position.copy( _lightPositionWorld );
9382 if ( isPointLight ) {
9386 // for point lights we set the shadow matrix to be a translation-only matrix
9387 // equal to inverse of the light's position
9389 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
9395 _lookTarget.setFromMatrixPosition( light.target.matrixWorld );
9396 shadowCamera.lookAt( _lookTarget );
9397 shadowCamera.updateMatrixWorld();
9399 // compute shadow matrix
9408 shadowMatrix.multiply( shadowCamera.projectionMatrix );
9409 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
9413 _renderer.setRenderTarget( shadowMap );
9416 // render shadow map for each cube face (if omni-directional) or
9417 // run a single pass if not
9419 for ( var face = 0; face < faceCount; face ++ ) {
9421 if ( isPointLight ) {
9423 _lookTarget.copy( shadowCamera.position );
9424 _lookTarget.add( cubeDirections[ face ] );
9425 shadowCamera.up.copy( cubeUps[ face ] );
9426 shadowCamera.lookAt( _lookTarget );
9427 shadowCamera.updateMatrixWorld();
9429 var vpDimensions = cube2DViewPorts[ face ];
9430 _state.viewport( vpDimensions );
9434 // update camera matrices and frustum
9436 _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
9437 _frustum.setFromMatrix( _projScreenMatrix );
9439 // set object matrices & frustum culling
9441 renderObject( scene, camera, shadowCamera, isPointLight );
9447 scope.needsUpdate = false;
9451 function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {
9453 var geometry = object.geometry;
9457 var materialVariants = _depthMaterials;
9458 var customMaterial = object.customDepthMaterial;
9460 if ( isPointLight ) {
9462 materialVariants = _distanceMaterials;
9463 customMaterial = object.customDistanceMaterial;
9467 if ( ! customMaterial ) {
9469 var useMorphing = false;
9471 if ( material.morphTargets ) {
9473 if ( geometry && geometry.isBufferGeometry ) {
9475 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
9477 } else if ( geometry && geometry.isGeometry ) {
9479 useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
9485 if ( object.isSkinnedMesh && material.skinning === false ) {
9487 console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
9491 var useSkinning = object.isSkinnedMesh && material.skinning;
9493 var variantIndex = 0;
9495 if ( useMorphing ) variantIndex |= _MorphingFlag;
9496 if ( useSkinning ) variantIndex |= _SkinningFlag;
9498 result = materialVariants[ variantIndex ];
9502 result = customMaterial;
9506 if ( _renderer.localClippingEnabled &&
9507 material.clipShadows === true &&
9508 material.clippingPlanes.length !== 0 ) {
9510 // in this case we need a unique material instance reflecting the
9511 // appropriate state
9513 var keyA = result.uuid, keyB = material.uuid;
9515 var materialsForVariant = _materialCache[ keyA ];
9517 if ( materialsForVariant === undefined ) {
9519 materialsForVariant = {};
9520 _materialCache[ keyA ] = materialsForVariant;
9524 var cachedMaterial = materialsForVariant[ keyB ];
9526 if ( cachedMaterial === undefined ) {
9528 cachedMaterial = result.clone();
9529 materialsForVariant[ keyB ] = cachedMaterial;
9533 result = cachedMaterial;
9537 result.visible = material.visible;
9538 result.wireframe = material.wireframe;
9540 var side = material.side;
9542 if ( scope.renderSingleSided && side == DoubleSide ) {
9548 if ( scope.renderReverseSided ) {
9550 if ( side === FrontSide ) side = BackSide;
9551 else if ( side === BackSide ) side = FrontSide;
9557 result.clipShadows = material.clipShadows;
9558 result.clippingPlanes = material.clippingPlanes;
9559 result.clipIntersection = material.clipIntersection;
9561 result.wireframeLinewidth = material.wireframeLinewidth;
9562 result.linewidth = material.linewidth;
9564 if ( isPointLight && result.isMeshDistanceMaterial ) {
9566 result.referencePosition.copy( lightPositionWorld );
9567 result.nearDistance = shadowCameraNear;
9568 result.farDistance = shadowCameraFar;
9576 function renderObject( object, camera, shadowCamera, isPointLight ) {
9578 if ( object.visible === false ) return;
9580 var visible = object.layers.test( camera.layers );
9582 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
9584 if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
9586 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
9588 var geometry = _objects.update( object );
9589 var material = object.material;
9591 if ( Array.isArray( material ) ) {
9593 var groups = geometry.groups;
9595 for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
9597 var group = groups[ k ];
9598 var groupMaterial = material[ group.materialIndex ];
9600 if ( groupMaterial && groupMaterial.visible ) {
9602 var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
9603 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
9609 } else if ( material.visible ) {
9611 var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
9612 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
9620 var children = object.children;
9622 for ( var i = 0, l = children.length; i < l; i ++ ) {
9624 renderObject( children[ i ], camera, shadowCamera, isPointLight );
9633 * @author mrdoob / http://mrdoob.com/
9636 function WebGLAttributes( gl ) {
9640 function createBuffer( attribute, bufferType ) {
9642 var array = attribute.array;
9643 var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
9645 var buffer = gl.createBuffer();
9647 gl.bindBuffer( bufferType, buffer );
9648 gl.bufferData( bufferType, array, usage );
9650 attribute.onUploadCallback();
9652 var type = gl.FLOAT;
9654 if ( array instanceof Float32Array ) {
9658 } else if ( array instanceof Float64Array ) {
9660 console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
9662 } else if ( array instanceof Uint16Array ) {
9664 type = gl.UNSIGNED_SHORT;
9666 } else if ( array instanceof Int16Array ) {
9670 } else if ( array instanceof Uint32Array ) {
9672 type = gl.UNSIGNED_INT;
9674 } else if ( array instanceof Int32Array ) {
9678 } else if ( array instanceof Int8Array ) {
9682 } else if ( array instanceof Uint8Array ) {
9684 type = gl.UNSIGNED_BYTE;
9691 bytesPerElement: array.BYTES_PER_ELEMENT,
9692 version: attribute.version
9697 function updateBuffer( buffer, attribute, bufferType ) {
9699 var array = attribute.array;
9700 var updateRange = attribute.updateRange;
9702 gl.bindBuffer( bufferType, buffer );
9704 if ( attribute.dynamic === false ) {
9706 gl.bufferData( bufferType, array, gl.STATIC_DRAW );
9708 } else if ( updateRange.count === - 1 ) {
9710 // Not using update ranges
9712 gl.bufferSubData( bufferType, 0, array );
9714 } else if ( updateRange.count === 0 ) {
9716 console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
9720 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
9721 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
9723 updateRange.count = -1; // reset range
9731 function get( attribute ) {
9733 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
9735 return buffers[ attribute.uuid ];
9739 function remove( attribute ) {
9741 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
9743 var data = buffers[ attribute.uuid ];
9747 gl.deleteBuffer( data.buffer );
9749 delete buffers[ attribute.uuid ];
9755 function update( attribute, bufferType ) {
9757 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
9759 var data = buffers[ attribute.uuid ];
9761 if ( data === undefined ) {
9763 buffers[ attribute.uuid ] = createBuffer( attribute, bufferType );
9765 } else if ( data.version < attribute.version ) {
9767 updateBuffer( data.buffer, attribute, bufferType );
9769 data.version = attribute.version;
9786 * @author mrdoob / http://mrdoob.com/
9787 * @author WestLangley / http://github.com/WestLangley
9788 * @author bhouston / http://clara.io
9791 function Euler( x, y, z, order ) {
9796 this._order = order || Euler.DefaultOrder;
9800 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
9802 Euler.DefaultOrder = 'XYZ';
9804 Object.defineProperties( Euler.prototype, {
9814 set: function ( value ) {
9817 this.onChangeCallback();
9831 set: function ( value ) {
9834 this.onChangeCallback();
9848 set: function ( value ) {
9851 this.onChangeCallback();
9865 set: function ( value ) {
9867 this._order = value;
9868 this.onChangeCallback();
9876 Object.assign( Euler.prototype, {
9880 set: function ( x, y, z, order ) {
9885 this._order = order || this._order;
9887 this.onChangeCallback();
9893 clone: function () {
9895 return new this.constructor( this._x, this._y, this._z, this._order );
9899 copy: function ( euler ) {
9904 this._order = euler._order;
9906 this.onChangeCallback();
9912 setFromRotationMatrix: function ( m, order, update ) {
9914 var clamp = _Math.clamp;
9916 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
9918 var te = m.elements;
9919 var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
9920 var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
9921 var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
9923 order = order || this._order;
9925 if ( order === 'XYZ' ) {
9927 this._y = Math.asin( clamp( m13, - 1, 1 ) );
9929 if ( Math.abs( m13 ) < 0.99999 ) {
9931 this._x = Math.atan2( - m23, m33 );
9932 this._z = Math.atan2( - m12, m11 );
9936 this._x = Math.atan2( m32, m22 );
9941 } else if ( order === 'YXZ' ) {
9943 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
9945 if ( Math.abs( m23 ) < 0.99999 ) {
9947 this._y = Math.atan2( m13, m33 );
9948 this._z = Math.atan2( m21, m22 );
9952 this._y = Math.atan2( - m31, m11 );
9957 } else if ( order === 'ZXY' ) {
9959 this._x = Math.asin( clamp( m32, - 1, 1 ) );
9961 if ( Math.abs( m32 ) < 0.99999 ) {
9963 this._y = Math.atan2( - m31, m33 );
9964 this._z = Math.atan2( - m12, m22 );
9969 this._z = Math.atan2( m21, m11 );
9973 } else if ( order === 'ZYX' ) {
9975 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
9977 if ( Math.abs( m31 ) < 0.99999 ) {
9979 this._x = Math.atan2( m32, m33 );
9980 this._z = Math.atan2( m21, m11 );
9985 this._z = Math.atan2( - m12, m22 );
9989 } else if ( order === 'YZX' ) {
9991 this._z = Math.asin( clamp( m21, - 1, 1 ) );
9993 if ( Math.abs( m21 ) < 0.99999 ) {
9995 this._x = Math.atan2( - m23, m22 );
9996 this._y = Math.atan2( - m31, m11 );
10001 this._y = Math.atan2( m13, m33 );
10005 } else if ( order === 'XZY' ) {
10007 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
10009 if ( Math.abs( m12 ) < 0.99999 ) {
10011 this._x = Math.atan2( m32, m22 );
10012 this._y = Math.atan2( m13, m11 );
10016 this._x = Math.atan2( - m23, m33 );
10023 console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );
10027 this._order = order;
10029 if ( update !== false ) this.onChangeCallback();
10035 setFromQuaternion: function () {
10037 var matrix = new Matrix4();
10039 return function setFromQuaternion( q, order, update ) {
10041 matrix.makeRotationFromQuaternion( q );
10043 return this.setFromRotationMatrix( matrix, order, update );
10049 setFromVector3: function ( v, order ) {
10051 return this.set( v.x, v.y, v.z, order || this._order );
10055 reorder: function () {
10057 // WARNING: this discards revolution information -bhouston
10059 var q = new Quaternion();
10061 return function reorder( newOrder ) {
10063 q.setFromEuler( this );
10065 return this.setFromQuaternion( q, newOrder );
10071 equals: function ( euler ) {
10073 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
10077 fromArray: function ( array ) {
10079 this._x = array[ 0 ];
10080 this._y = array[ 1 ];
10081 this._z = array[ 2 ];
10082 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
10084 this.onChangeCallback();
10090 toArray: function ( array, offset ) {
10092 if ( array === undefined ) array = [];
10093 if ( offset === undefined ) offset = 0;
10095 array[ offset ] = this._x;
10096 array[ offset + 1 ] = this._y;
10097 array[ offset + 2 ] = this._z;
10098 array[ offset + 3 ] = this._order;
10104 toVector3: function ( optionalResult ) {
10106 if ( optionalResult ) {
10108 return optionalResult.set( this._x, this._y, this._z );
10112 return new Vector3( this._x, this._y, this._z );
10118 onChange: function ( callback ) {
10120 this.onChangeCallback = callback;
10126 onChangeCallback: function () {}
10131 * @author mrdoob / http://mrdoob.com/
10134 function Layers() {
10140 Object.assign( Layers.prototype, {
10142 set: function ( channel ) {
10144 this.mask = 1 << channel | 0;
10148 enable: function ( channel ) {
10150 this.mask |= 1 << channel | 0;
10154 toggle: function ( channel ) {
10156 this.mask ^= 1 << channel | 0;
10160 disable: function ( channel ) {
10162 this.mask &= ~ ( 1 << channel | 0 );
10166 test: function ( layers ) {
10168 return ( this.mask & layers.mask ) !== 0;
10175 * @author mrdoob / http://mrdoob.com/
10176 * @author mikael emtinger / http://gomo.se/
10177 * @author alteredq / http://alteredqualia.com/
10178 * @author WestLangley / http://github.com/WestLangley
10179 * @author elephantatwork / www.elephantatwork.ch
10182 var object3DId = 0;
10184 function Object3D() {
10186 Object.defineProperty( this, 'id', { value: object3DId ++ } );
10188 this.uuid = _Math.generateUUID();
10191 this.type = 'Object3D';
10193 this.parent = null;
10194 this.children = [];
10196 this.up = Object3D.DefaultUp.clone();
10198 var position = new Vector3();
10199 var rotation = new Euler();
10200 var quaternion = new Quaternion();
10201 var scale = new Vector3( 1, 1, 1 );
10203 function onRotationChange() {
10205 quaternion.setFromEuler( rotation, false );
10209 function onQuaternionChange() {
10211 rotation.setFromQuaternion( quaternion, undefined, false );
10215 rotation.onChange( onRotationChange );
10216 quaternion.onChange( onQuaternionChange );
10218 Object.defineProperties( this, {
10236 value: new Matrix4()
10239 value: new Matrix3()
10243 this.matrix = new Matrix4();
10244 this.matrixWorld = new Matrix4();
10246 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
10247 this.matrixWorldNeedsUpdate = false;
10249 this.layers = new Layers();
10250 this.visible = true;
10252 this.castShadow = false;
10253 this.receiveShadow = false;
10255 this.frustumCulled = true;
10256 this.renderOrder = 0;
10258 this.userData = {};
10261 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
10262 Object3D.DefaultMatrixAutoUpdate = true;
10264 Object.assign( Object3D.prototype, EventDispatcher.prototype, {
10268 onBeforeRender: function () {},
10269 onAfterRender: function () {},
10271 applyMatrix: function ( matrix ) {
10273 this.matrix.multiplyMatrices( matrix, this.matrix );
10275 this.matrix.decompose( this.position, this.quaternion, this.scale );
10279 applyQuaternion: function ( q ) {
10281 this.quaternion.premultiply( q );
10287 setRotationFromAxisAngle: function ( axis, angle ) {
10289 // assumes axis is normalized
10291 this.quaternion.setFromAxisAngle( axis, angle );
10295 setRotationFromEuler: function ( euler ) {
10297 this.quaternion.setFromEuler( euler, true );
10301 setRotationFromMatrix: function ( m ) {
10303 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
10305 this.quaternion.setFromRotationMatrix( m );
10309 setRotationFromQuaternion: function ( q ) {
10311 // assumes q is normalized
10313 this.quaternion.copy( q );
10317 rotateOnAxis: function () {
10319 // rotate object on axis in object space
10320 // axis is assumed to be normalized
10322 var q1 = new Quaternion();
10324 return function rotateOnAxis( axis, angle ) {
10326 q1.setFromAxisAngle( axis, angle );
10328 this.quaternion.multiply( q1 );
10336 rotateX: function () {
10338 var v1 = new Vector3( 1, 0, 0 );
10340 return function rotateX( angle ) {
10342 return this.rotateOnAxis( v1, angle );
10348 rotateY: function () {
10350 var v1 = new Vector3( 0, 1, 0 );
10352 return function rotateY( angle ) {
10354 return this.rotateOnAxis( v1, angle );
10360 rotateZ: function () {
10362 var v1 = new Vector3( 0, 0, 1 );
10364 return function rotateZ( angle ) {
10366 return this.rotateOnAxis( v1, angle );
10372 translateOnAxis: function () {
10374 // translate object by distance along axis in object space
10375 // axis is assumed to be normalized
10377 var v1 = new Vector3();
10379 return function translateOnAxis( axis, distance ) {
10381 v1.copy( axis ).applyQuaternion( this.quaternion );
10383 this.position.add( v1.multiplyScalar( distance ) );
10391 translateX: function () {
10393 var v1 = new Vector3( 1, 0, 0 );
10395 return function translateX( distance ) {
10397 return this.translateOnAxis( v1, distance );
10403 translateY: function () {
10405 var v1 = new Vector3( 0, 1, 0 );
10407 return function translateY( distance ) {
10409 return this.translateOnAxis( v1, distance );
10415 translateZ: function () {
10417 var v1 = new Vector3( 0, 0, 1 );
10419 return function translateZ( distance ) {
10421 return this.translateOnAxis( v1, distance );
10427 localToWorld: function ( vector ) {
10429 return vector.applyMatrix4( this.matrixWorld );
10433 worldToLocal: function () {
10435 var m1 = new Matrix4();
10437 return function worldToLocal( vector ) {
10439 return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
10445 lookAt: function () {
10447 // This method does not support objects with rotated and/or translated parent(s)
10449 var m1 = new Matrix4();
10451 return function lookAt( vector ) {
10453 if ( this.isCamera ) {
10455 m1.lookAt( this.position, vector, this.up );
10459 m1.lookAt( vector, this.position, this.up );
10463 this.quaternion.setFromRotationMatrix( m1 );
10469 add: function ( object ) {
10471 if ( arguments.length > 1 ) {
10473 for ( var i = 0; i < arguments.length; i ++ ) {
10475 this.add( arguments[ i ] );
10483 if ( object === this ) {
10485 console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
10490 if ( ( object && object.isObject3D ) ) {
10492 if ( object.parent !== null ) {
10494 object.parent.remove( object );
10498 object.parent = this;
10499 object.dispatchEvent( { type: 'added' } );
10501 this.children.push( object );
10505 console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
10513 remove: function ( object ) {
10515 if ( arguments.length > 1 ) {
10517 for ( var i = 0; i < arguments.length; i ++ ) {
10519 this.remove( arguments[ i ] );
10527 var index = this.children.indexOf( object );
10529 if ( index !== - 1 ) {
10531 object.parent = null;
10533 object.dispatchEvent( { type: 'removed' } );
10535 this.children.splice( index, 1 );
10543 getObjectById: function ( id ) {
10545 return this.getObjectByProperty( 'id', id );
10549 getObjectByName: function ( name ) {
10551 return this.getObjectByProperty( 'name', name );
10555 getObjectByProperty: function ( name, value ) {
10557 if ( this[ name ] === value ) return this;
10559 for ( var i = 0, l = this.children.length; i < l; i ++ ) {
10561 var child = this.children[ i ];
10562 var object = child.getObjectByProperty( name, value );
10564 if ( object !== undefined ) {
10576 getWorldPosition: function ( optionalTarget ) {
10578 var result = optionalTarget || new Vector3();
10580 this.updateMatrixWorld( true );
10582 return result.setFromMatrixPosition( this.matrixWorld );
10586 getWorldQuaternion: function () {
10588 var position = new Vector3();
10589 var scale = new Vector3();
10591 return function getWorldQuaternion( optionalTarget ) {
10593 var result = optionalTarget || new Quaternion();
10595 this.updateMatrixWorld( true );
10597 this.matrixWorld.decompose( position, result, scale );
10605 getWorldRotation: function () {
10607 var quaternion = new Quaternion();
10609 return function getWorldRotation( optionalTarget ) {
10611 var result = optionalTarget || new Euler();
10613 this.getWorldQuaternion( quaternion );
10615 return result.setFromQuaternion( quaternion, this.rotation.order, false );
10621 getWorldScale: function () {
10623 var position = new Vector3();
10624 var quaternion = new Quaternion();
10626 return function getWorldScale( optionalTarget ) {
10628 var result = optionalTarget || new Vector3();
10630 this.updateMatrixWorld( true );
10632 this.matrixWorld.decompose( position, quaternion, result );
10640 getWorldDirection: function () {
10642 var quaternion = new Quaternion();
10644 return function getWorldDirection( optionalTarget ) {
10646 var result = optionalTarget || new Vector3();
10648 this.getWorldQuaternion( quaternion );
10650 return result.set( 0, 0, 1 ).applyQuaternion( quaternion );
10656 raycast: function () {},
10658 traverse: function ( callback ) {
10662 var children = this.children;
10664 for ( var i = 0, l = children.length; i < l; i ++ ) {
10666 children[ i ].traverse( callback );
10672 traverseVisible: function ( callback ) {
10674 if ( this.visible === false ) return;
10678 var children = this.children;
10680 for ( var i = 0, l = children.length; i < l; i ++ ) {
10682 children[ i ].traverseVisible( callback );
10688 traverseAncestors: function ( callback ) {
10690 var parent = this.parent;
10692 if ( parent !== null ) {
10694 callback( parent );
10696 parent.traverseAncestors( callback );
10702 updateMatrix: function () {
10704 this.matrix.compose( this.position, this.quaternion, this.scale );
10706 this.matrixWorldNeedsUpdate = true;
10710 updateMatrixWorld: function ( force ) {
10712 if ( this.matrixAutoUpdate ) this.updateMatrix();
10714 if ( this.matrixWorldNeedsUpdate || force ) {
10716 if ( this.parent === null ) {
10718 this.matrixWorld.copy( this.matrix );
10722 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
10726 this.matrixWorldNeedsUpdate = false;
10734 var children = this.children;
10736 for ( var i = 0, l = children.length; i < l; i ++ ) {
10738 children[ i ].updateMatrixWorld( force );
10744 toJSON: function ( meta ) {
10746 // meta is '' when called from JSON.stringify
10747 var isRootObject = ( meta === undefined || meta === '' );
10751 // meta is a hash used to collect geometries, materials.
10752 // not providing it implies that this is the root object
10753 // being serialized.
10754 if ( isRootObject ) {
10756 // initialize meta obj
10764 output.metadata = {
10767 generator: 'Object3D.toJSON'
10772 // standard Object3D serialization
10776 object.uuid = this.uuid;
10777 object.type = this.type;
10779 if ( this.name !== '' ) object.name = this.name;
10780 if ( this.castShadow === true ) object.castShadow = true;
10781 if ( this.receiveShadow === true ) object.receiveShadow = true;
10782 if ( this.visible === false ) object.visible = false;
10783 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
10785 object.matrix = this.matrix.toArray();
10789 function serialize( library, element ) {
10791 if ( library[ element.uuid ] === undefined ) {
10793 library[ element.uuid ] = element.toJSON( meta );
10797 return element.uuid;
10801 if ( this.geometry !== undefined ) {
10803 object.geometry = serialize( meta.geometries, this.geometry );
10807 if ( this.material !== undefined ) {
10809 if ( Array.isArray( this.material ) ) {
10813 for ( var i = 0, l = this.material.length; i < l; i ++ ) {
10815 uuids.push( serialize( meta.materials, this.material[ i ] ) );
10819 object.material = uuids;
10823 object.material = serialize( meta.materials, this.material );
10831 if ( this.children.length > 0 ) {
10833 object.children = [];
10835 for ( var i = 0; i < this.children.length; i ++ ) {
10837 object.children.push( this.children[ i ].toJSON( meta ).object );
10843 if ( isRootObject ) {
10845 var geometries = extractFromCache( meta.geometries );
10846 var materials = extractFromCache( meta.materials );
10847 var textures = extractFromCache( meta.textures );
10848 var images = extractFromCache( meta.images );
10850 if ( geometries.length > 0 ) output.geometries = geometries;
10851 if ( materials.length > 0 ) output.materials = materials;
10852 if ( textures.length > 0 ) output.textures = textures;
10853 if ( images.length > 0 ) output.images = images;
10857 output.object = object;
10861 // extract data from the cache hash
10862 // remove metadata on each item
10863 // and return as array
10864 function extractFromCache( cache ) {
10867 for ( var key in cache ) {
10869 var data = cache[ key ];
10870 delete data.metadata;
10871 values.push( data );
10880 clone: function ( recursive ) {
10882 return new this.constructor().copy( this, recursive );
10886 copy: function ( source, recursive ) {
10888 if ( recursive === undefined ) recursive = true;
10890 this.name = source.name;
10892 this.up.copy( source.up );
10894 this.position.copy( source.position );
10895 this.quaternion.copy( source.quaternion );
10896 this.scale.copy( source.scale );
10898 this.matrix.copy( source.matrix );
10899 this.matrixWorld.copy( source.matrixWorld );
10901 this.matrixAutoUpdate = source.matrixAutoUpdate;
10902 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
10904 this.layers.mask = source.layers.mask;
10905 this.visible = source.visible;
10907 this.castShadow = source.castShadow;
10908 this.receiveShadow = source.receiveShadow;
10910 this.frustumCulled = source.frustumCulled;
10911 this.renderOrder = source.renderOrder;
10913 this.userData = JSON.parse( JSON.stringify( source.userData ) );
10915 if ( recursive === true ) {
10917 for ( var i = 0; i < source.children.length; i ++ ) {
10919 var child = source.children[ i ];
10920 this.add( child.clone() );
10933 * @author mrdoob / http://mrdoob.com/
10934 * @author mikael emtinger / http://gomo.se/
10935 * @author WestLangley / http://github.com/WestLangley
10938 function Camera() {
10940 Object3D.call( this );
10942 this.type = 'Camera';
10944 this.matrixWorldInverse = new Matrix4();
10945 this.projectionMatrix = new Matrix4();
10949 Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
10951 constructor: Camera,
10955 copy: function ( source, recursive ) {
10957 Object3D.prototype.copy.call( this, source, recursive );
10959 this.matrixWorldInverse.copy( source.matrixWorldInverse );
10960 this.projectionMatrix.copy( source.projectionMatrix );
10966 getWorldDirection: function () {
10968 var quaternion = new Quaternion();
10970 return function getWorldDirection( optionalTarget ) {
10972 var result = optionalTarget || new Vector3();
10974 this.getWorldQuaternion( quaternion );
10976 return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );
10982 updateMatrixWorld: function ( force ) {
10984 Object3D.prototype.updateMatrixWorld.call( this, force );
10986 this.matrixWorldInverse.getInverse( this.matrixWorld );
10990 clone: function () {
10992 return new this.constructor().copy( this );
10999 * @author alteredq / http://alteredqualia.com/
11000 * @author arose / http://github.com/arose
11003 function OrthographicCamera( left, right, top, bottom, near, far ) {
11005 Camera.call( this );
11007 this.type = 'OrthographicCamera';
11013 this.right = right;
11015 this.bottom = bottom;
11017 this.near = ( near !== undefined ) ? near : 0.1;
11018 this.far = ( far !== undefined ) ? far : 2000;
11020 this.updateProjectionMatrix();
11024 OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
11026 constructor: OrthographicCamera,
11028 isOrthographicCamera: true,
11030 copy: function ( source, recursive ) {
11032 Camera.prototype.copy.call( this, source, recursive );
11034 this.left = source.left;
11035 this.right = source.right;
11036 this.top = source.top;
11037 this.bottom = source.bottom;
11038 this.near = source.near;
11039 this.far = source.far;
11041 this.zoom = source.zoom;
11042 this.view = source.view === null ? null : Object.assign( {}, source.view );
11048 setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {
11051 fullWidth: fullWidth,
11052 fullHeight: fullHeight,
11059 this.updateProjectionMatrix();
11063 clearViewOffset: function() {
11066 this.updateProjectionMatrix();
11070 updateProjectionMatrix: function () {
11072 var dx = ( this.right - this.left ) / ( 2 * this.zoom );
11073 var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
11074 var cx = ( this.right + this.left ) / 2;
11075 var cy = ( this.top + this.bottom ) / 2;
11077 var left = cx - dx;
11078 var right = cx + dx;
11080 var bottom = cy - dy;
11082 if ( this.view !== null ) {
11084 var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
11085 var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
11086 var scaleW = ( this.right - this.left ) / this.view.width;
11087 var scaleH = ( this.top - this.bottom ) / this.view.height;
11089 left += scaleW * ( this.view.offsetX / zoomW );
11090 right = left + scaleW * ( this.view.width / zoomW );
11091 top -= scaleH * ( this.view.offsetY / zoomH );
11092 bottom = top - scaleH * ( this.view.height / zoomH );
11096 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
11100 toJSON: function ( meta ) {
11102 var data = Object3D.prototype.toJSON.call( this, meta );
11104 data.object.zoom = this.zoom;
11105 data.object.left = this.left;
11106 data.object.right = this.right;
11107 data.object.top = this.top;
11108 data.object.bottom = this.bottom;
11109 data.object.near = this.near;
11110 data.object.far = this.far;
11112 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
11121 * @author mrdoob / http://mrdoob.com/
11122 * @author greggman / http://games.greggman.com/
11123 * @author zz85 / http://www.lab4games.net/zz85/blog
11127 function PerspectiveCamera( fov, aspect, near, far ) {
11129 Camera.call( this );
11131 this.type = 'PerspectiveCamera';
11133 this.fov = fov !== undefined ? fov : 50;
11136 this.near = near !== undefined ? near : 0.1;
11137 this.far = far !== undefined ? far : 2000;
11140 this.aspect = aspect !== undefined ? aspect : 1;
11143 this.filmGauge = 35; // width of the film (default in millimeters)
11144 this.filmOffset = 0; // horizontal film offset (same unit as gauge)
11146 this.updateProjectionMatrix();
11150 PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
11152 constructor: PerspectiveCamera,
11154 isPerspectiveCamera: true,
11156 copy: function ( source, recursive ) {
11158 Camera.prototype.copy.call( this, source, recursive );
11160 this.fov = source.fov;
11161 this.zoom = source.zoom;
11163 this.near = source.near;
11164 this.far = source.far;
11165 this.focus = source.focus;
11167 this.aspect = source.aspect;
11168 this.view = source.view === null ? null : Object.assign( {}, source.view );
11170 this.filmGauge = source.filmGauge;
11171 this.filmOffset = source.filmOffset;
11178 * Sets the FOV by focal length in respect to the current .filmGauge.
11180 * The default film gauge is 35, so that the focal length can be specified for
11181 * a 35mm (full frame) camera.
11183 * Values for focal length and film gauge must have the same unit.
11185 setFocalLength: function ( focalLength ) {
11187 // see http://www.bobatkins.com/photography/technical/field_of_view.html
11188 var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
11190 this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
11191 this.updateProjectionMatrix();
11196 * Calculates the focal length from the current .fov and .filmGauge.
11198 getFocalLength: function () {
11200 var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );
11202 return 0.5 * this.getFilmHeight() / vExtentSlope;
11206 getEffectiveFOV: function () {
11208 return _Math.RAD2DEG * 2 * Math.atan(
11209 Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );
11213 getFilmWidth: function () {
11215 // film not completely covered in portrait format (aspect < 1)
11216 return this.filmGauge * Math.min( this.aspect, 1 );
11220 getFilmHeight: function () {
11222 // film not completely covered in landscape format (aspect > 1)
11223 return this.filmGauge / Math.max( this.aspect, 1 );
11228 * Sets an offset in a larger frustum. This is useful for multi-window or
11229 * multi-monitor/multi-machine setups.
11231 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
11232 * the monitors are in grid like this
11240 * then for each monitor you would call it like this
11244 * var fullWidth = w * 3;
11245 * var fullHeight = h * 2;
11248 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
11250 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
11252 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
11254 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
11256 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
11258 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
11260 * Note there is no reason monitors have to be the same size or in a grid.
11262 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
11264 this.aspect = fullWidth / fullHeight;
11267 fullWidth: fullWidth,
11268 fullHeight: fullHeight,
11275 this.updateProjectionMatrix();
11279 clearViewOffset: function () {
11282 this.updateProjectionMatrix();
11286 updateProjectionMatrix: function () {
11288 var near = this.near,
11289 top = near * Math.tan(
11290 _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
11292 width = this.aspect * height,
11293 left = - 0.5 * width,
11296 if ( view !== null ) {
11298 var fullWidth = view.fullWidth,
11299 fullHeight = view.fullHeight;
11301 left += view.offsetX * width / fullWidth;
11302 top -= view.offsetY * height / fullHeight;
11303 width *= view.width / fullWidth;
11304 height *= view.height / fullHeight;
11308 var skew = this.filmOffset;
11309 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
11311 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
11315 toJSON: function ( meta ) {
11317 var data = Object3D.prototype.toJSON.call( this, meta );
11319 data.object.fov = this.fov;
11320 data.object.zoom = this.zoom;
11322 data.object.near = this.near;
11323 data.object.far = this.far;
11324 data.object.focus = this.focus;
11326 data.object.aspect = this.aspect;
11328 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
11330 data.object.filmGauge = this.filmGauge;
11331 data.object.filmOffset = this.filmOffset;
11340 * @author mrdoob / http://mrdoob.com/
11341 * @author alteredq / http://alteredqualia.com/
11344 function Face3( a, b, c, normal, color, materialIndex ) {
11350 this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
11351 this.vertexNormals = Array.isArray( normal ) ? normal : [];
11353 this.color = ( color && color.isColor ) ? color : new Color();
11354 this.vertexColors = Array.isArray( color ) ? color : [];
11356 this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
11360 Object.assign( Face3.prototype, {
11362 clone: function () {
11364 return new this.constructor().copy( this );
11368 copy: function ( source ) {
11374 this.normal.copy( source.normal );
11375 this.color.copy( source.color );
11377 this.materialIndex = source.materialIndex;
11379 for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
11381 this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
11385 for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {
11387 this.vertexColors[ i ] = source.vertexColors[ i ].clone();
11398 * @author mrdoob / http://mrdoob.com/
11399 * @author kile / http://kile.stravaganza.org/
11400 * @author alteredq / http://alteredqualia.com/
11401 * @author mikael emtinger / http://gomo.se/
11402 * @author zz85 / http://www.lab4games.net/zz85/blog
11403 * @author bhouston / http://clara.io
11407 function GeometryIdCount() { return count++; }
11409 function Geometry() {
11411 Object.defineProperty( this, 'id', { value: GeometryIdCount() } );
11413 this.uuid = _Math.generateUUID();
11416 this.type = 'Geometry';
11418 this.vertices = [];
11421 this.faceVertexUvs = [[]];
11423 this.morphTargets = [];
11424 this.morphNormals = [];
11426 this.skinWeights = [];
11427 this.skinIndices = [];
11429 this.lineDistances = [];
11431 this.boundingBox = null;
11432 this.boundingSphere = null;
11436 this.elementsNeedUpdate = false;
11437 this.verticesNeedUpdate = false;
11438 this.uvsNeedUpdate = false;
11439 this.normalsNeedUpdate = false;
11440 this.colorsNeedUpdate = false;
11441 this.lineDistancesNeedUpdate = false;
11442 this.groupsNeedUpdate = false;
11446 Object.assign( Geometry.prototype, EventDispatcher.prototype, {
11450 applyMatrix: function ( matrix ) {
11452 var normalMatrix = new Matrix3().getNormalMatrix( matrix );
11454 for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
11456 var vertex = this.vertices[ i ];
11457 vertex.applyMatrix4( matrix );
11461 for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
11463 var face = this.faces[ i ];
11464 face.normal.applyMatrix3( normalMatrix ).normalize();
11466 for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
11468 face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
11474 if ( this.boundingBox !== null ) {
11476 this.computeBoundingBox();
11480 if ( this.boundingSphere !== null ) {
11482 this.computeBoundingSphere();
11486 this.verticesNeedUpdate = true;
11487 this.normalsNeedUpdate = true;
11493 rotateX: function () {
11495 // rotate geometry around world x-axis
11497 var m1 = new Matrix4();
11499 return function rotateX( angle ) {
11501 m1.makeRotationX( angle );
11503 this.applyMatrix( m1 );
11511 rotateY: function () {
11513 // rotate geometry around world y-axis
11515 var m1 = new Matrix4();
11517 return function rotateY( angle ) {
11519 m1.makeRotationY( angle );
11521 this.applyMatrix( m1 );
11529 rotateZ: function () {
11531 // rotate geometry around world z-axis
11533 var m1 = new Matrix4();
11535 return function rotateZ( angle ) {
11537 m1.makeRotationZ( angle );
11539 this.applyMatrix( m1 );
11547 translate: function () {
11549 // translate geometry
11551 var m1 = new Matrix4();
11553 return function translate( x, y, z ) {
11555 m1.makeTranslation( x, y, z );
11557 this.applyMatrix( m1 );
11565 scale: function () {
11569 var m1 = new Matrix4();
11571 return function scale( x, y, z ) {
11573 m1.makeScale( x, y, z );
11575 this.applyMatrix( m1 );
11583 lookAt: function () {
11585 var obj = new Object3D();
11587 return function lookAt( vector ) {
11589 obj.lookAt( vector );
11591 obj.updateMatrix();
11593 this.applyMatrix( obj.matrix );
11599 fromBufferGeometry: function ( geometry ) {
11603 var indices = geometry.index !== null ? geometry.index.array : undefined;
11604 var attributes = geometry.attributes;
11606 var positions = attributes.position.array;
11607 var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
11608 var colors = attributes.color !== undefined ? attributes.color.array : undefined;
11609 var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
11610 var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
11612 if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
11614 var tempNormals = [];
11618 for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
11620 scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );
11622 if ( normals !== undefined ) {
11624 tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );
11628 if ( colors !== undefined ) {
11630 scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
11634 if ( uvs !== undefined ) {
11636 tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );
11640 if ( uvs2 !== undefined ) {
11642 tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );
11648 function addFace( a, b, c, materialIndex ) {
11650 var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];
11651 var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];
11653 var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
11655 scope.faces.push( face );
11657 if ( uvs !== undefined ) {
11659 scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );
11663 if ( uvs2 !== undefined ) {
11665 scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );
11671 var groups = geometry.groups;
11673 if ( groups.length > 0 ) {
11675 for ( var i = 0; i < groups.length; i ++ ) {
11677 var group = groups[ i ];
11679 var start = group.start;
11680 var count = group.count;
11682 for ( var j = start, jl = start + count; j < jl; j += 3 ) {
11684 if ( indices !== undefined ) {
11686 addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );
11690 addFace( j, j + 1, j + 2, group.materialIndex );
11700 if ( indices !== undefined ) {
11702 for ( var i = 0; i < indices.length; i += 3 ) {
11704 addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
11710 for ( var i = 0; i < positions.length / 3; i += 3 ) {
11712 addFace( i, i + 1, i + 2 );
11720 this.computeFaceNormals();
11722 if ( geometry.boundingBox !== null ) {
11724 this.boundingBox = geometry.boundingBox.clone();
11728 if ( geometry.boundingSphere !== null ) {
11730 this.boundingSphere = geometry.boundingSphere.clone();
11738 center: function () {
11740 this.computeBoundingBox();
11742 var offset = this.boundingBox.getCenter().negate();
11744 this.translate( offset.x, offset.y, offset.z );
11750 normalize: function () {
11752 this.computeBoundingSphere();
11754 var center = this.boundingSphere.center;
11755 var radius = this.boundingSphere.radius;
11757 var s = radius === 0 ? 1 : 1.0 / radius;
11759 var matrix = new Matrix4();
11761 s, 0, 0, - s * center.x,
11762 0, s, 0, - s * center.y,
11763 0, 0, s, - s * center.z,
11767 this.applyMatrix( matrix );
11773 computeFaceNormals: function () {
11775 var cb = new Vector3(), ab = new Vector3();
11777 for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
11779 var face = this.faces[ f ];
11781 var vA = this.vertices[ face.a ];
11782 var vB = this.vertices[ face.b ];
11783 var vC = this.vertices[ face.c ];
11785 cb.subVectors( vC, vB );
11786 ab.subVectors( vA, vB );
11791 face.normal.copy( cb );
11797 computeVertexNormals: function ( areaWeighted ) {
11799 if ( areaWeighted === undefined ) areaWeighted = true;
11801 var v, vl, f, fl, face, vertices;
11803 vertices = new Array( this.vertices.length );
11805 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
11807 vertices[ v ] = new Vector3();
11811 if ( areaWeighted ) {
11813 // vertex normals weighted by triangle areas
11814 // http://www.iquilezles.org/www/articles/normals/normals.htm
11817 var cb = new Vector3(), ab = new Vector3();
11819 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11821 face = this.faces[ f ];
11823 vA = this.vertices[ face.a ];
11824 vB = this.vertices[ face.b ];
11825 vC = this.vertices[ face.c ];
11827 cb.subVectors( vC, vB );
11828 ab.subVectors( vA, vB );
11831 vertices[ face.a ].add( cb );
11832 vertices[ face.b ].add( cb );
11833 vertices[ face.c ].add( cb );
11839 this.computeFaceNormals();
11841 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11843 face = this.faces[ f ];
11845 vertices[ face.a ].add( face.normal );
11846 vertices[ face.b ].add( face.normal );
11847 vertices[ face.c ].add( face.normal );
11853 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
11855 vertices[ v ].normalize();
11859 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11861 face = this.faces[ f ];
11863 var vertexNormals = face.vertexNormals;
11865 if ( vertexNormals.length === 3 ) {
11867 vertexNormals[ 0 ].copy( vertices[ face.a ] );
11868 vertexNormals[ 1 ].copy( vertices[ face.b ] );
11869 vertexNormals[ 2 ].copy( vertices[ face.c ] );
11873 vertexNormals[ 0 ] = vertices[ face.a ].clone();
11874 vertexNormals[ 1 ] = vertices[ face.b ].clone();
11875 vertexNormals[ 2 ] = vertices[ face.c ].clone();
11881 if ( this.faces.length > 0 ) {
11883 this.normalsNeedUpdate = true;
11889 computeFlatVertexNormals: function () {
11893 this.computeFaceNormals();
11895 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11897 face = this.faces[ f ];
11899 var vertexNormals = face.vertexNormals;
11901 if ( vertexNormals.length === 3 ) {
11903 vertexNormals[ 0 ].copy( face.normal );
11904 vertexNormals[ 1 ].copy( face.normal );
11905 vertexNormals[ 2 ].copy( face.normal );
11909 vertexNormals[ 0 ] = face.normal.clone();
11910 vertexNormals[ 1 ] = face.normal.clone();
11911 vertexNormals[ 2 ] = face.normal.clone();
11917 if ( this.faces.length > 0 ) {
11919 this.normalsNeedUpdate = true;
11925 computeMorphNormals: function () {
11927 var i, il, f, fl, face;
11929 // save original normals
11930 // - create temp variables on first access
11931 // otherwise just copy (for faster repeated calls)
11933 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11935 face = this.faces[ f ];
11937 if ( ! face.__originalFaceNormal ) {
11939 face.__originalFaceNormal = face.normal.clone();
11943 face.__originalFaceNormal.copy( face.normal );
11947 if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
11949 for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
11951 if ( ! face.__originalVertexNormals[ i ] ) {
11953 face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
11957 face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
11965 // use temp geometry to compute face and vertex normals for each morph
11967 var tmpGeo = new Geometry();
11968 tmpGeo.faces = this.faces;
11970 for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
11972 // create on first access
11974 if ( ! this.morphNormals[ i ] ) {
11976 this.morphNormals[ i ] = {};
11977 this.morphNormals[ i ].faceNormals = [];
11978 this.morphNormals[ i ].vertexNormals = [];
11980 var dstNormalsFace = this.morphNormals[ i ].faceNormals;
11981 var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
11983 var faceNormal, vertexNormals;
11985 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
11987 faceNormal = new Vector3();
11988 vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
11990 dstNormalsFace.push( faceNormal );
11991 dstNormalsVertex.push( vertexNormals );
11997 var morphNormals = this.morphNormals[ i ];
11999 // set vertices to morph target
12001 tmpGeo.vertices = this.morphTargets[ i ].vertices;
12003 // compute morph normals
12005 tmpGeo.computeFaceNormals();
12006 tmpGeo.computeVertexNormals();
12008 // store morph normals
12010 var faceNormal, vertexNormals;
12012 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
12014 face = this.faces[ f ];
12016 faceNormal = morphNormals.faceNormals[ f ];
12017 vertexNormals = morphNormals.vertexNormals[ f ];
12019 faceNormal.copy( face.normal );
12021 vertexNormals.a.copy( face.vertexNormals[ 0 ] );
12022 vertexNormals.b.copy( face.vertexNormals[ 1 ] );
12023 vertexNormals.c.copy( face.vertexNormals[ 2 ] );
12029 // restore original normals
12031 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
12033 face = this.faces[ f ];
12035 face.normal = face.__originalFaceNormal;
12036 face.vertexNormals = face.__originalVertexNormals;
12042 computeLineDistances: function () {
12045 var vertices = this.vertices;
12047 for ( var i = 0, il = vertices.length; i < il; i ++ ) {
12051 d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
12055 this.lineDistances[ i ] = d;
12061 computeBoundingBox: function () {
12063 if ( this.boundingBox === null ) {
12065 this.boundingBox = new Box3();
12069 this.boundingBox.setFromPoints( this.vertices );
12073 computeBoundingSphere: function () {
12075 if ( this.boundingSphere === null ) {
12077 this.boundingSphere = new Sphere();
12081 this.boundingSphere.setFromPoints( this.vertices );
12085 merge: function ( geometry, matrix, materialIndexOffset ) {
12087 if ( ! ( geometry && geometry.isGeometry ) ) {
12089 console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
12095 vertexOffset = this.vertices.length,
12096 vertices1 = this.vertices,
12097 vertices2 = geometry.vertices,
12098 faces1 = this.faces,
12099 faces2 = geometry.faces,
12100 uvs1 = this.faceVertexUvs[ 0 ],
12101 uvs2 = geometry.faceVertexUvs[ 0 ],
12102 colors1 = this.colors,
12103 colors2 = geometry.colors;
12105 if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
12107 if ( matrix !== undefined ) {
12109 normalMatrix = new Matrix3().getNormalMatrix( matrix );
12115 for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
12117 var vertex = vertices2[ i ];
12119 var vertexCopy = vertex.clone();
12121 if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
12123 vertices1.push( vertexCopy );
12129 for ( var i = 0, il = colors2.length; i < il; i ++ ) {
12131 colors1.push( colors2[ i ].clone() );
12137 for ( i = 0, il = faces2.length; i < il; i ++ ) {
12139 var face = faces2[ i ], faceCopy, normal, color,
12140 faceVertexNormals = face.vertexNormals,
12141 faceVertexColors = face.vertexColors;
12143 faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
12144 faceCopy.normal.copy( face.normal );
12146 if ( normalMatrix !== undefined ) {
12148 faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
12152 for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
12154 normal = faceVertexNormals[ j ].clone();
12156 if ( normalMatrix !== undefined ) {
12158 normal.applyMatrix3( normalMatrix ).normalize();
12162 faceCopy.vertexNormals.push( normal );
12166 faceCopy.color.copy( face.color );
12168 for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
12170 color = faceVertexColors[ j ];
12171 faceCopy.vertexColors.push( color.clone() );
12175 faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
12177 faces1.push( faceCopy );
12183 for ( i = 0, il = uvs2.length; i < il; i ++ ) {
12185 var uv = uvs2[ i ], uvCopy = [];
12187 if ( uv === undefined ) {
12193 for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
12195 uvCopy.push( uv[ j ].clone() );
12199 uvs1.push( uvCopy );
12205 mergeMesh: function ( mesh ) {
12207 if ( ! ( mesh && mesh.isMesh ) ) {
12209 console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
12214 mesh.matrixAutoUpdate && mesh.updateMatrix();
12216 this.merge( mesh.geometry, mesh.matrix );
12221 * Checks for duplicate vertices with hashmap.
12222 * Duplicated vertices are removed
12223 * and faces' vertices are updated.
12226 mergeVertices: function () {
12228 var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
12229 var unique = [], changes = [];
12232 var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
12233 var precision = Math.pow( 10, precisionPoints );
12235 var indices, j, jl;
12237 for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
12239 v = this.vertices[ i ];
12240 key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
12242 if ( verticesMap[ key ] === undefined ) {
12244 verticesMap[ key ] = i;
12245 unique.push( this.vertices[ i ] );
12246 changes[ i ] = unique.length - 1;
12250 //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
12251 changes[ i ] = changes[ verticesMap[ key ] ];
12258 // if faces are completely degenerate after merging vertices, we
12259 // have to remove them from the geometry.
12260 var faceIndicesToRemove = [];
12262 for ( i = 0, il = this.faces.length; i < il; i ++ ) {
12264 face = this.faces[ i ];
12266 face.a = changes[ face.a ];
12267 face.b = changes[ face.b ];
12268 face.c = changes[ face.c ];
12270 indices = [ face.a, face.b, face.c ];
12272 // if any duplicate vertices are found in a Face3
12273 // we have to remove the face as nothing can be saved
12274 for ( var n = 0; n < 3; n ++ ) {
12276 if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
12278 faceIndicesToRemove.push( i );
12287 for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
12289 var idx = faceIndicesToRemove[ i ];
12291 this.faces.splice( idx, 1 );
12293 for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
12295 this.faceVertexUvs[ j ].splice( idx, 1 );
12301 // Use unique set of vertices
12303 var diff = this.vertices.length - unique.length;
12304 this.vertices = unique;
12309 sortFacesByMaterialIndex: function () {
12311 var faces = this.faces;
12312 var length = faces.length;
12316 for ( var i = 0; i < length; i ++ ) {
12318 faces[ i ]._id = i;
12324 function materialIndexSort( a, b ) {
12326 return a.materialIndex - b.materialIndex;
12330 faces.sort( materialIndexSort );
12334 var uvs1 = this.faceVertexUvs[ 0 ];
12335 var uvs2 = this.faceVertexUvs[ 1 ];
12337 var newUvs1, newUvs2;
12339 if ( uvs1 && uvs1.length === length ) newUvs1 = [];
12340 if ( uvs2 && uvs2.length === length ) newUvs2 = [];
12342 for ( var i = 0; i < length; i ++ ) {
12344 var id = faces[ i ]._id;
12346 if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
12347 if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
12351 if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
12352 if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
12356 toJSON: function () {
12362 generator: 'Geometry.toJSON'
12366 // standard Geometry serialization
12368 data.uuid = this.uuid;
12369 data.type = this.type;
12370 if ( this.name !== '' ) data.name = this.name;
12372 if ( this.parameters !== undefined ) {
12374 var parameters = this.parameters;
12376 for ( var key in parameters ) {
12378 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
12388 for ( var i = 0; i < this.vertices.length; i ++ ) {
12390 var vertex = this.vertices[ i ];
12391 vertices.push( vertex.x, vertex.y, vertex.z );
12397 var normalsHash = {};
12399 var colorsHash = {};
12403 for ( var i = 0; i < this.faces.length; i ++ ) {
12405 var face = this.faces[ i ];
12407 var hasMaterial = true;
12408 var hasFaceUv = false; // deprecated
12409 var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
12410 var hasFaceNormal = face.normal.length() > 0;
12411 var hasFaceVertexNormal = face.vertexNormals.length > 0;
12412 var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
12413 var hasFaceVertexColor = face.vertexColors.length > 0;
12417 faceType = setBit( faceType, 0, 0 ); // isQuad
12418 faceType = setBit( faceType, 1, hasMaterial );
12419 faceType = setBit( faceType, 2, hasFaceUv );
12420 faceType = setBit( faceType, 3, hasFaceVertexUv );
12421 faceType = setBit( faceType, 4, hasFaceNormal );
12422 faceType = setBit( faceType, 5, hasFaceVertexNormal );
12423 faceType = setBit( faceType, 6, hasFaceColor );
12424 faceType = setBit( faceType, 7, hasFaceVertexColor );
12426 faces.push( faceType );
12427 faces.push( face.a, face.b, face.c );
12428 faces.push( face.materialIndex );
12430 if ( hasFaceVertexUv ) {
12432 var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
12435 getUvIndex( faceVertexUvs[ 0 ] ),
12436 getUvIndex( faceVertexUvs[ 1 ] ),
12437 getUvIndex( faceVertexUvs[ 2 ] )
12442 if ( hasFaceNormal ) {
12444 faces.push( getNormalIndex( face.normal ) );
12448 if ( hasFaceVertexNormal ) {
12450 var vertexNormals = face.vertexNormals;
12453 getNormalIndex( vertexNormals[ 0 ] ),
12454 getNormalIndex( vertexNormals[ 1 ] ),
12455 getNormalIndex( vertexNormals[ 2 ] )
12460 if ( hasFaceColor ) {
12462 faces.push( getColorIndex( face.color ) );
12466 if ( hasFaceVertexColor ) {
12468 var vertexColors = face.vertexColors;
12471 getColorIndex( vertexColors[ 0 ] ),
12472 getColorIndex( vertexColors[ 1 ] ),
12473 getColorIndex( vertexColors[ 2 ] )
12480 function setBit( value, position, enabled ) {
12482 return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
12486 function getNormalIndex( normal ) {
12488 var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
12490 if ( normalsHash[ hash ] !== undefined ) {
12492 return normalsHash[ hash ];
12496 normalsHash[ hash ] = normals.length / 3;
12497 normals.push( normal.x, normal.y, normal.z );
12499 return normalsHash[ hash ];
12503 function getColorIndex( color ) {
12505 var hash = color.r.toString() + color.g.toString() + color.b.toString();
12507 if ( colorsHash[ hash ] !== undefined ) {
12509 return colorsHash[ hash ];
12513 colorsHash[ hash ] = colors.length;
12514 colors.push( color.getHex() );
12516 return colorsHash[ hash ];
12520 function getUvIndex( uv ) {
12522 var hash = uv.x.toString() + uv.y.toString();
12524 if ( uvsHash[ hash ] !== undefined ) {
12526 return uvsHash[ hash ];
12530 uvsHash[ hash ] = uvs.length / 2;
12531 uvs.push( uv.x, uv.y );
12533 return uvsHash[ hash ];
12539 data.data.vertices = vertices;
12540 data.data.normals = normals;
12541 if ( colors.length > 0 ) data.data.colors = colors;
12542 if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
12543 data.data.faces = faces;
12549 clone: function () {
12552 // Handle primitives
12554 var parameters = this.parameters;
12556 if ( parameters !== undefined ) {
12560 for ( var key in parameters ) {
12562 values.push( parameters[ key ] );
12566 var geometry = Object.create( this.constructor.prototype );
12567 this.constructor.apply( geometry, values );
12572 return new this.constructor().copy( this );
12575 return new Geometry().copy( this );
12579 copy: function ( source ) {
12581 var i, il, j, jl, k, kl;
12585 this.vertices = [];
12588 this.faceVertexUvs = [[]];
12589 this.morphTargets = [];
12590 this.morphNormals = [];
12591 this.skinWeights = [];
12592 this.skinIndices = [];
12593 this.lineDistances = [];
12594 this.boundingBox = null;
12595 this.boundingSphere = null;
12599 this.name = source.name;
12603 var vertices = source.vertices;
12605 for ( i = 0, il = vertices.length; i < il; i ++ ) {
12607 this.vertices.push( vertices[ i ].clone() );
12613 var colors = source.colors;
12615 for ( i = 0, il = colors.length; i < il; i ++ ) {
12617 this.colors.push( colors[ i ].clone() );
12623 var faces = source.faces;
12625 for ( i = 0, il = faces.length; i < il; i ++ ) {
12627 this.faces.push( faces[ i ].clone() );
12633 for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
12635 var faceVertexUvs = source.faceVertexUvs[ i ];
12637 if ( this.faceVertexUvs[ i ] === undefined ) {
12639 this.faceVertexUvs[ i ] = [];
12643 for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
12645 var uvs = faceVertexUvs[ j ], uvsCopy = [];
12647 for ( k = 0, kl = uvs.length; k < kl; k ++ ) {
12651 uvsCopy.push( uv.clone() );
12655 this.faceVertexUvs[ i ].push( uvsCopy );
12663 var morphTargets = source.morphTargets;
12665 for ( i = 0, il = morphTargets.length; i < il; i ++ ) {
12667 var morphTarget = {};
12668 morphTarget.name = morphTargets[ i ].name;
12672 if ( morphTargets[ i ].vertices !== undefined ) {
12674 morphTarget.vertices = [];
12676 for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
12678 morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
12686 if ( morphTargets[ i ].normals !== undefined ) {
12688 morphTarget.normals = [];
12690 for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
12692 morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
12698 this.morphTargets.push( morphTarget );
12704 var morphNormals = source.morphNormals;
12706 for ( i = 0, il = morphNormals.length; i < il; i ++ ) {
12708 var morphNormal = {};
12712 if ( morphNormals[ i ].vertexNormals !== undefined ) {
12714 morphNormal.vertexNormals = [];
12716 for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
12718 var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
12719 var destVertexNormal = {};
12721 destVertexNormal.a = srcVertexNormal.a.clone();
12722 destVertexNormal.b = srcVertexNormal.b.clone();
12723 destVertexNormal.c = srcVertexNormal.c.clone();
12725 morphNormal.vertexNormals.push( destVertexNormal );
12733 if ( morphNormals[ i ].faceNormals !== undefined ) {
12735 morphNormal.faceNormals = [];
12737 for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
12739 morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
12745 this.morphNormals.push( morphNormal );
12751 var skinWeights = source.skinWeights;
12753 for ( i = 0, il = skinWeights.length; i < il; i ++ ) {
12755 this.skinWeights.push( skinWeights[ i ].clone() );
12761 var skinIndices = source.skinIndices;
12763 for ( i = 0, il = skinIndices.length; i < il; i ++ ) {
12765 this.skinIndices.push( skinIndices[ i ].clone() );
12771 var lineDistances = source.lineDistances;
12773 for ( i = 0, il = lineDistances.length; i < il; i ++ ) {
12775 this.lineDistances.push( lineDistances[ i ] );
12781 var boundingBox = source.boundingBox;
12783 if ( boundingBox !== null ) {
12785 this.boundingBox = boundingBox.clone();
12791 var boundingSphere = source.boundingSphere;
12793 if ( boundingSphere !== null ) {
12795 this.boundingSphere = boundingSphere.clone();
12801 this.elementsNeedUpdate = source.elementsNeedUpdate;
12802 this.verticesNeedUpdate = source.verticesNeedUpdate;
12803 this.uvsNeedUpdate = source.uvsNeedUpdate;
12804 this.normalsNeedUpdate = source.normalsNeedUpdate;
12805 this.colorsNeedUpdate = source.colorsNeedUpdate;
12806 this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
12807 this.groupsNeedUpdate = source.groupsNeedUpdate;
12813 dispose: function () {
12815 this.dispatchEvent( { type: 'dispose' } );
12822 * @author mrdoob / http://mrdoob.com/
12825 function BufferAttribute( array, itemSize, normalized ) {
12827 if ( Array.isArray( array ) ) {
12829 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
12833 this.uuid = _Math.generateUUID();
12836 this.array = array;
12837 this.itemSize = itemSize;
12838 this.count = array !== undefined ? array.length / itemSize : 0;
12839 this.normalized = normalized === true;
12841 this.dynamic = false;
12842 this.updateRange = { offset: 0, count: - 1 };
12844 this.onUploadCallback = function () {};
12850 Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
12852 set: function ( value ) {
12854 if ( value === true ) this.version ++;
12860 Object.assign( BufferAttribute.prototype, {
12862 isBufferAttribute: true,
12864 setArray: function ( array ) {
12866 if ( Array.isArray( array ) ) {
12868 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
12872 this.count = array !== undefined ? array.length / this.itemSize : 0;
12873 this.array = array;
12877 setDynamic: function ( value ) {
12879 this.dynamic = value;
12885 copy: function ( source ) {
12887 this.array = new source.array.constructor( source.array );
12888 this.itemSize = source.itemSize;
12889 this.count = source.count;
12890 this.normalized = source.normalized;
12892 this.dynamic = source.dynamic;
12898 copyAt: function ( index1, attribute, index2 ) {
12900 index1 *= this.itemSize;
12901 index2 *= attribute.itemSize;
12903 for ( var i = 0, l = this.itemSize; i < l; i ++ ) {
12905 this.array[ index1 + i ] = attribute.array[ index2 + i ];
12913 copyArray: function ( array ) {
12915 this.array.set( array );
12921 copyColorsArray: function ( colors ) {
12923 var array = this.array, offset = 0;
12925 for ( var i = 0, l = colors.length; i < l; i ++ ) {
12927 var color = colors[ i ];
12929 if ( color === undefined ) {
12931 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
12932 color = new Color();
12936 array[ offset ++ ] = color.r;
12937 array[ offset ++ ] = color.g;
12938 array[ offset ++ ] = color.b;
12946 copyIndicesArray: function ( indices ) {
12948 var array = this.array, offset = 0;
12950 for ( var i = 0, l = indices.length; i < l; i ++ ) {
12952 var index = indices[ i ];
12954 array[ offset ++ ] = index.a;
12955 array[ offset ++ ] = index.b;
12956 array[ offset ++ ] = index.c;
12964 copyVector2sArray: function ( vectors ) {
12966 var array = this.array, offset = 0;
12968 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
12970 var vector = vectors[ i ];
12972 if ( vector === undefined ) {
12974 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
12975 vector = new Vector2();
12979 array[ offset ++ ] = vector.x;
12980 array[ offset ++ ] = vector.y;
12988 copyVector3sArray: function ( vectors ) {
12990 var array = this.array, offset = 0;
12992 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
12994 var vector = vectors[ i ];
12996 if ( vector === undefined ) {
12998 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
12999 vector = new Vector3();
13003 array[ offset ++ ] = vector.x;
13004 array[ offset ++ ] = vector.y;
13005 array[ offset ++ ] = vector.z;
13013 copyVector4sArray: function ( vectors ) {
13015 var array = this.array, offset = 0;
13017 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
13019 var vector = vectors[ i ];
13021 if ( vector === undefined ) {
13023 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
13024 vector = new Vector4();
13028 array[ offset ++ ] = vector.x;
13029 array[ offset ++ ] = vector.y;
13030 array[ offset ++ ] = vector.z;
13031 array[ offset ++ ] = vector.w;
13039 set: function ( value, offset ) {
13041 if ( offset === undefined ) offset = 0;
13043 this.array.set( value, offset );
13049 getX: function ( index ) {
13051 return this.array[ index * this.itemSize ];
13055 setX: function ( index, x ) {
13057 this.array[ index * this.itemSize ] = x;
13063 getY: function ( index ) {
13065 return this.array[ index * this.itemSize + 1 ];
13069 setY: function ( index, y ) {
13071 this.array[ index * this.itemSize + 1 ] = y;
13077 getZ: function ( index ) {
13079 return this.array[ index * this.itemSize + 2 ];
13083 setZ: function ( index, z ) {
13085 this.array[ index * this.itemSize + 2 ] = z;
13091 getW: function ( index ) {
13093 return this.array[ index * this.itemSize + 3 ];
13097 setW: function ( index, w ) {
13099 this.array[ index * this.itemSize + 3 ] = w;
13105 setXY: function ( index, x, y ) {
13107 index *= this.itemSize;
13109 this.array[ index + 0 ] = x;
13110 this.array[ index + 1 ] = y;
13116 setXYZ: function ( index, x, y, z ) {
13118 index *= this.itemSize;
13120 this.array[ index + 0 ] = x;
13121 this.array[ index + 1 ] = y;
13122 this.array[ index + 2 ] = z;
13128 setXYZW: function ( index, x, y, z, w ) {
13130 index *= this.itemSize;
13132 this.array[ index + 0 ] = x;
13133 this.array[ index + 1 ] = y;
13134 this.array[ index + 2 ] = z;
13135 this.array[ index + 3 ] = w;
13141 onUpload: function ( callback ) {
13143 this.onUploadCallback = callback;
13149 clone: function () {
13151 return new this.constructor( this.array, this.itemSize ).copy( this );
13159 function Int8BufferAttribute( array, itemSize ) {
13161 BufferAttribute.call( this, new Int8Array( array ), itemSize );
13165 Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13166 Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
13169 function Uint8BufferAttribute( array, itemSize ) {
13171 BufferAttribute.call( this, new Uint8Array( array ), itemSize );
13175 Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13176 Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
13179 function Uint8ClampedBufferAttribute( array, itemSize ) {
13181 BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize );
13185 Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13186 Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
13189 function Int16BufferAttribute( array, itemSize ) {
13191 BufferAttribute.call( this, new Int16Array( array ), itemSize );
13195 Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13196 Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
13199 function Uint16BufferAttribute( array, itemSize ) {
13201 BufferAttribute.call( this, new Uint16Array( array ), itemSize );
13205 Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13206 Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
13209 function Int32BufferAttribute( array, itemSize ) {
13211 BufferAttribute.call( this, new Int32Array( array ), itemSize );
13215 Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13216 Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
13219 function Uint32BufferAttribute( array, itemSize ) {
13221 BufferAttribute.call( this, new Uint32Array( array ), itemSize );
13225 Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13226 Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
13229 function Float32BufferAttribute( array, itemSize ) {
13231 BufferAttribute.call( this, new Float32Array( array ), itemSize );
13235 Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13236 Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
13239 function Float64BufferAttribute( array, itemSize ) {
13241 BufferAttribute.call( this, new Float64Array( array ), itemSize );
13245 Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13246 Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
13249 * @author mrdoob / http://mrdoob.com/
13252 function DirectGeometry() {
13255 this.vertices = [];
13263 this.morphTargets = {};
13265 this.skinWeights = [];
13266 this.skinIndices = [];
13268 // this.lineDistances = [];
13270 this.boundingBox = null;
13271 this.boundingSphere = null;
13275 this.verticesNeedUpdate = false;
13276 this.normalsNeedUpdate = false;
13277 this.colorsNeedUpdate = false;
13278 this.uvsNeedUpdate = false;
13279 this.groupsNeedUpdate = false;
13283 Object.assign( DirectGeometry.prototype, {
13285 computeGroups: function ( geometry ) {
13289 var materialIndex = undefined;
13291 var faces = geometry.faces;
13293 for ( var i = 0; i < faces.length; i ++ ) {
13295 var face = faces[ i ];
13299 if ( face.materialIndex !== materialIndex ) {
13301 materialIndex = face.materialIndex;
13303 if ( group !== undefined ) {
13305 group.count = ( i * 3 ) - group.start;
13306 groups.push( group );
13312 materialIndex: materialIndex
13319 if ( group !== undefined ) {
13321 group.count = ( i * 3 ) - group.start;
13322 groups.push( group );
13326 this.groups = groups;
13330 fromGeometry: function ( geometry ) {
13332 var faces = geometry.faces;
13333 var vertices = geometry.vertices;
13334 var faceVertexUvs = geometry.faceVertexUvs;
13336 var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
13337 var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
13341 var morphTargets = geometry.morphTargets;
13342 var morphTargetsLength = morphTargets.length;
13344 var morphTargetsPosition;
13346 if ( morphTargetsLength > 0 ) {
13348 morphTargetsPosition = [];
13350 for ( var i = 0; i < morphTargetsLength; i ++ ) {
13352 morphTargetsPosition[ i ] = [];
13356 this.morphTargets.position = morphTargetsPosition;
13360 var morphNormals = geometry.morphNormals;
13361 var morphNormalsLength = morphNormals.length;
13363 var morphTargetsNormal;
13365 if ( morphNormalsLength > 0 ) {
13367 morphTargetsNormal = [];
13369 for ( var i = 0; i < morphNormalsLength; i ++ ) {
13371 morphTargetsNormal[ i ] = [];
13375 this.morphTargets.normal = morphTargetsNormal;
13381 var skinIndices = geometry.skinIndices;
13382 var skinWeights = geometry.skinWeights;
13384 var hasSkinIndices = skinIndices.length === vertices.length;
13385 var hasSkinWeights = skinWeights.length === vertices.length;
13389 for ( var i = 0; i < faces.length; i ++ ) {
13391 var face = faces[ i ];
13393 this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
13395 var vertexNormals = face.vertexNormals;
13397 if ( vertexNormals.length === 3 ) {
13399 this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
13403 var normal = face.normal;
13405 this.normals.push( normal, normal, normal );
13409 var vertexColors = face.vertexColors;
13411 if ( vertexColors.length === 3 ) {
13413 this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
13417 var color = face.color;
13419 this.colors.push( color, color, color );
13423 if ( hasFaceVertexUv === true ) {
13425 var vertexUvs = faceVertexUvs[ 0 ][ i ];
13427 if ( vertexUvs !== undefined ) {
13429 this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
13433 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
13435 this.uvs.push( new Vector2(), new Vector2(), new Vector2() );
13441 if ( hasFaceVertexUv2 === true ) {
13443 var vertexUvs = faceVertexUvs[ 1 ][ i ];
13445 if ( vertexUvs !== undefined ) {
13447 this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
13451 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
13453 this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );
13461 for ( var j = 0; j < morphTargetsLength; j ++ ) {
13463 var morphTarget = morphTargets[ j ].vertices;
13465 morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
13469 for ( var j = 0; j < morphNormalsLength; j ++ ) {
13471 var morphNormal = morphNormals[ j ].vertexNormals[ i ];
13473 morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );
13479 if ( hasSkinIndices ) {
13481 this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
13485 if ( hasSkinWeights ) {
13487 this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
13493 this.computeGroups( geometry );
13495 this.verticesNeedUpdate = geometry.verticesNeedUpdate;
13496 this.normalsNeedUpdate = geometry.normalsNeedUpdate;
13497 this.colorsNeedUpdate = geometry.colorsNeedUpdate;
13498 this.uvsNeedUpdate = geometry.uvsNeedUpdate;
13499 this.groupsNeedUpdate = geometry.groupsNeedUpdate;
13508 * @author mrdoob / http://mrdoob.com/
13511 function arrayMax( array ) {
13513 if ( array.length === 0 ) return - Infinity;
13515 var max = array[ 0 ];
13517 for ( var i = 1, l = array.length; i < l; ++ i ) {
13519 if ( array[ i ] > max ) max = array[ i ];
13528 * @author alteredq / http://alteredqualia.com/
13529 * @author mrdoob / http://mrdoob.com/
13532 function BufferGeometry() {
13534 Object.defineProperty( this, 'id', { value: GeometryIdCount() } );
13536 this.uuid = _Math.generateUUID();
13539 this.type = 'BufferGeometry';
13542 this.attributes = {};
13544 this.morphAttributes = {};
13548 this.boundingBox = null;
13549 this.boundingSphere = null;
13551 this.drawRange = { start: 0, count: Infinity };
13555 BufferGeometry.MaxIndex = 65535;
13557 Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, {
13559 isBufferGeometry: true,
13561 getIndex: function () {
13567 setIndex: function ( index ) {
13569 if ( Array.isArray( index ) ) {
13571 this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
13575 this.index = index;
13581 addAttribute: function ( name, attribute ) {
13583 if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
13585 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
13587 this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
13593 if ( name === 'index' ) {
13595 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
13596 this.setIndex( attribute );
13602 this.attributes[ name ] = attribute;
13608 getAttribute: function ( name ) {
13610 return this.attributes[ name ];
13614 removeAttribute: function ( name ) {
13616 delete this.attributes[ name ];
13622 addGroup: function ( start, count, materialIndex ) {
13624 this.groups.push( {
13628 materialIndex: materialIndex !== undefined ? materialIndex : 0
13634 clearGroups: function () {
13640 setDrawRange: function ( start, count ) {
13642 this.drawRange.start = start;
13643 this.drawRange.count = count;
13647 applyMatrix: function ( matrix ) {
13649 var position = this.attributes.position;
13651 if ( position !== undefined ) {
13653 matrix.applyToBufferAttribute( position );
13654 position.needsUpdate = true;
13658 var normal = this.attributes.normal;
13660 if ( normal !== undefined ) {
13662 var normalMatrix = new Matrix3().getNormalMatrix( matrix );
13664 normalMatrix.applyToBufferAttribute( normal );
13665 normal.needsUpdate = true;
13669 if ( this.boundingBox !== null ) {
13671 this.computeBoundingBox();
13675 if ( this.boundingSphere !== null ) {
13677 this.computeBoundingSphere();
13685 rotateX: function () {
13687 // rotate geometry around world x-axis
13689 var m1 = new Matrix4();
13691 return function rotateX( angle ) {
13693 m1.makeRotationX( angle );
13695 this.applyMatrix( m1 );
13703 rotateY: function () {
13705 // rotate geometry around world y-axis
13707 var m1 = new Matrix4();
13709 return function rotateY( angle ) {
13711 m1.makeRotationY( angle );
13713 this.applyMatrix( m1 );
13721 rotateZ: function () {
13723 // rotate geometry around world z-axis
13725 var m1 = new Matrix4();
13727 return function rotateZ( angle ) {
13729 m1.makeRotationZ( angle );
13731 this.applyMatrix( m1 );
13739 translate: function () {
13741 // translate geometry
13743 var m1 = new Matrix4();
13745 return function translate( x, y, z ) {
13747 m1.makeTranslation( x, y, z );
13749 this.applyMatrix( m1 );
13757 scale: function () {
13761 var m1 = new Matrix4();
13763 return function scale( x, y, z ) {
13765 m1.makeScale( x, y, z );
13767 this.applyMatrix( m1 );
13775 lookAt: function () {
13777 var obj = new Object3D();
13779 return function lookAt( vector ) {
13781 obj.lookAt( vector );
13783 obj.updateMatrix();
13785 this.applyMatrix( obj.matrix );
13791 center: function () {
13793 this.computeBoundingBox();
13795 var offset = this.boundingBox.getCenter().negate();
13797 this.translate( offset.x, offset.y, offset.z );
13803 setFromObject: function ( object ) {
13805 // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
13807 var geometry = object.geometry;
13809 if ( object.isPoints || object.isLine ) {
13811 var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
13812 var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
13814 this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
13815 this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
13817 if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
13819 var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
13821 this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
13825 if ( geometry.boundingSphere !== null ) {
13827 this.boundingSphere = geometry.boundingSphere.clone();
13831 if ( geometry.boundingBox !== null ) {
13833 this.boundingBox = geometry.boundingBox.clone();
13837 } else if ( object.isMesh ) {
13839 if ( geometry && geometry.isGeometry ) {
13841 this.fromGeometry( geometry );
13851 updateFromObject: function ( object ) {
13853 var geometry = object.geometry;
13855 if ( object.isMesh ) {
13857 var direct = geometry.__directGeometry;
13859 if ( geometry.elementsNeedUpdate === true ) {
13861 direct = undefined;
13862 geometry.elementsNeedUpdate = false;
13866 if ( direct === undefined ) {
13868 return this.fromGeometry( geometry );
13872 direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
13873 direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
13874 direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
13875 direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
13876 direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
13878 geometry.verticesNeedUpdate = false;
13879 geometry.normalsNeedUpdate = false;
13880 geometry.colorsNeedUpdate = false;
13881 geometry.uvsNeedUpdate = false;
13882 geometry.groupsNeedUpdate = false;
13890 if ( geometry.verticesNeedUpdate === true ) {
13892 attribute = this.attributes.position;
13894 if ( attribute !== undefined ) {
13896 attribute.copyVector3sArray( geometry.vertices );
13897 attribute.needsUpdate = true;
13901 geometry.verticesNeedUpdate = false;
13905 if ( geometry.normalsNeedUpdate === true ) {
13907 attribute = this.attributes.normal;
13909 if ( attribute !== undefined ) {
13911 attribute.copyVector3sArray( geometry.normals );
13912 attribute.needsUpdate = true;
13916 geometry.normalsNeedUpdate = false;
13920 if ( geometry.colorsNeedUpdate === true ) {
13922 attribute = this.attributes.color;
13924 if ( attribute !== undefined ) {
13926 attribute.copyColorsArray( geometry.colors );
13927 attribute.needsUpdate = true;
13931 geometry.colorsNeedUpdate = false;
13935 if ( geometry.uvsNeedUpdate ) {
13937 attribute = this.attributes.uv;
13939 if ( attribute !== undefined ) {
13941 attribute.copyVector2sArray( geometry.uvs );
13942 attribute.needsUpdate = true;
13946 geometry.uvsNeedUpdate = false;
13950 if ( geometry.lineDistancesNeedUpdate ) {
13952 attribute = this.attributes.lineDistance;
13954 if ( attribute !== undefined ) {
13956 attribute.copyArray( geometry.lineDistances );
13957 attribute.needsUpdate = true;
13961 geometry.lineDistancesNeedUpdate = false;
13965 if ( geometry.groupsNeedUpdate ) {
13967 geometry.computeGroups( object.geometry );
13968 this.groups = geometry.groups;
13970 geometry.groupsNeedUpdate = false;
13978 fromGeometry: function ( geometry ) {
13980 geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
13982 return this.fromDirectGeometry( geometry.__directGeometry );
13986 fromDirectGeometry: function ( geometry ) {
13988 var positions = new Float32Array( geometry.vertices.length * 3 );
13989 this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
13991 if ( geometry.normals.length > 0 ) {
13993 var normals = new Float32Array( geometry.normals.length * 3 );
13994 this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
13998 if ( geometry.colors.length > 0 ) {
14000 var colors = new Float32Array( geometry.colors.length * 3 );
14001 this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
14005 if ( geometry.uvs.length > 0 ) {
14007 var uvs = new Float32Array( geometry.uvs.length * 2 );
14008 this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
14012 if ( geometry.uvs2.length > 0 ) {
14014 var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
14015 this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
14019 if ( geometry.indices.length > 0 ) {
14021 var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;
14022 var indices = new TypeArray( geometry.indices.length * 3 );
14023 this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );
14029 this.groups = geometry.groups;
14033 for ( var name in geometry.morphTargets ) {
14036 var morphTargets = geometry.morphTargets[ name ];
14038 for ( var i = 0, l = morphTargets.length; i < l; i ++ ) {
14040 var morphTarget = morphTargets[ i ];
14042 var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );
14044 array.push( attribute.copyVector3sArray( morphTarget ) );
14048 this.morphAttributes[ name ] = array;
14054 if ( geometry.skinIndices.length > 0 ) {
14056 var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
14057 this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
14061 if ( geometry.skinWeights.length > 0 ) {
14063 var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
14064 this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
14070 if ( geometry.boundingSphere !== null ) {
14072 this.boundingSphere = geometry.boundingSphere.clone();
14076 if ( geometry.boundingBox !== null ) {
14078 this.boundingBox = geometry.boundingBox.clone();
14086 computeBoundingBox: function () {
14088 if ( this.boundingBox === null ) {
14090 this.boundingBox = new Box3();
14094 var position = this.attributes.position;
14096 if ( position !== undefined ) {
14098 this.boundingBox.setFromBufferAttribute( position );
14102 this.boundingBox.makeEmpty();
14106 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
14108 console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
14114 computeBoundingSphere: function () {
14116 var box = new Box3();
14117 var vector = new Vector3();
14119 return function computeBoundingSphere() {
14121 if ( this.boundingSphere === null ) {
14123 this.boundingSphere = new Sphere();
14127 var position = this.attributes.position;
14131 var center = this.boundingSphere.center;
14133 box.setFromBufferAttribute( position );
14134 box.getCenter( center );
14136 // hoping to find a boundingSphere with a radius smaller than the
14137 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
14139 var maxRadiusSq = 0;
14141 for ( var i = 0, il = position.count; i < il; i ++ ) {
14143 vector.x = position.getX( i );
14144 vector.y = position.getY( i );
14145 vector.z = position.getZ( i );
14146 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
14150 this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
14152 if ( isNaN( this.boundingSphere.radius ) ) {
14154 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
14164 computeFaceNormals: function () {
14166 // backwards compatibility
14170 computeVertexNormals: function () {
14172 var index = this.index;
14173 var attributes = this.attributes;
14174 var groups = this.groups;
14176 if ( attributes.position ) {
14178 var positions = attributes.position.array;
14180 if ( attributes.normal === undefined ) {
14182 this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );
14186 // reset existing normals to zero
14188 var array = attributes.normal.array;
14190 for ( var i = 0, il = array.length; i < il; i ++ ) {
14198 var normals = attributes.normal.array;
14201 var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
14202 var cb = new Vector3(), ab = new Vector3();
14204 // indexed elements
14208 var indices = index.array;
14210 if ( groups.length === 0 ) {
14212 this.addGroup( 0, indices.length );
14216 for ( var j = 0, jl = groups.length; j < jl; ++ j ) {
14218 var group = groups[ j ];
14220 var start = group.start;
14221 var count = group.count;
14223 for ( var i = start, il = start + count; i < il; i += 3 ) {
14225 vA = indices[ i + 0 ] * 3;
14226 vB = indices[ i + 1 ] * 3;
14227 vC = indices[ i + 2 ] * 3;
14229 pA.fromArray( positions, vA );
14230 pB.fromArray( positions, vB );
14231 pC.fromArray( positions, vC );
14233 cb.subVectors( pC, pB );
14234 ab.subVectors( pA, pB );
14237 normals[ vA ] += cb.x;
14238 normals[ vA + 1 ] += cb.y;
14239 normals[ vA + 2 ] += cb.z;
14241 normals[ vB ] += cb.x;
14242 normals[ vB + 1 ] += cb.y;
14243 normals[ vB + 2 ] += cb.z;
14245 normals[ vC ] += cb.x;
14246 normals[ vC + 1 ] += cb.y;
14247 normals[ vC + 2 ] += cb.z;
14255 // non-indexed elements (unconnected triangle soup)
14257 for ( var i = 0, il = positions.length; i < il; i += 9 ) {
14259 pA.fromArray( positions, i );
14260 pB.fromArray( positions, i + 3 );
14261 pC.fromArray( positions, i + 6 );
14263 cb.subVectors( pC, pB );
14264 ab.subVectors( pA, pB );
14267 normals[ i ] = cb.x;
14268 normals[ i + 1 ] = cb.y;
14269 normals[ i + 2 ] = cb.z;
14271 normals[ i + 3 ] = cb.x;
14272 normals[ i + 4 ] = cb.y;
14273 normals[ i + 5 ] = cb.z;
14275 normals[ i + 6 ] = cb.x;
14276 normals[ i + 7 ] = cb.y;
14277 normals[ i + 8 ] = cb.z;
14283 this.normalizeNormals();
14285 attributes.normal.needsUpdate = true;
14291 merge: function ( geometry, offset ) {
14293 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
14295 console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
14300 if ( offset === undefined ) offset = 0;
14302 var attributes = this.attributes;
14304 for ( var key in attributes ) {
14306 if ( geometry.attributes[ key ] === undefined ) continue;
14308 var attribute1 = attributes[ key ];
14309 var attributeArray1 = attribute1.array;
14311 var attribute2 = geometry.attributes[ key ];
14312 var attributeArray2 = attribute2.array;
14314 var attributeSize = attribute2.itemSize;
14316 for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {
14318 attributeArray1[ j ] = attributeArray2[ i ];
14328 normalizeNormals: function () {
14330 var vector = new Vector3();
14332 return function normalizeNormals() {
14334 var normals = this.attributes.normal;
14336 for ( var i = 0, il = normals.count; i < il; i ++ ) {
14338 vector.x = normals.getX( i );
14339 vector.y = normals.getY( i );
14340 vector.z = normals.getZ( i );
14342 vector.normalize();
14344 normals.setXYZ( i, vector.x, vector.y, vector.z );
14352 toNonIndexed: function () {
14354 if ( this.index === null ) {
14356 console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
14361 var geometry2 = new BufferGeometry();
14363 var indices = this.index.array;
14364 var attributes = this.attributes;
14366 for ( var name in attributes ) {
14368 var attribute = attributes[ name ];
14370 var array = attribute.array;
14371 var itemSize = attribute.itemSize;
14373 var array2 = new array.constructor( indices.length * itemSize );
14375 var index = 0, index2 = 0;
14377 for ( var i = 0, l = indices.length; i < l; i ++ ) {
14379 index = indices[ i ] * itemSize;
14381 for ( var j = 0; j < itemSize; j ++ ) {
14383 array2[ index2 ++ ] = array[ index ++ ];
14389 geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );
14397 toJSON: function () {
14402 type: 'BufferGeometry',
14403 generator: 'BufferGeometry.toJSON'
14407 // standard BufferGeometry serialization
14409 data.uuid = this.uuid;
14410 data.type = this.type;
14411 if ( this.name !== '' ) data.name = this.name;
14413 if ( this.parameters !== undefined ) {
14415 var parameters = this.parameters;
14417 for ( var key in parameters ) {
14419 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
14427 data.data = { attributes: {} };
14429 var index = this.index;
14431 if ( index !== null ) {
14433 var array = Array.prototype.slice.call( index.array );
14435 data.data.index = {
14436 type: index.array.constructor.name,
14442 var attributes = this.attributes;
14444 for ( var key in attributes ) {
14446 var attribute = attributes[ key ];
14448 var array = Array.prototype.slice.call( attribute.array );
14450 data.data.attributes[ key ] = {
14451 itemSize: attribute.itemSize,
14452 type: attribute.array.constructor.name,
14454 normalized: attribute.normalized
14459 var groups = this.groups;
14461 if ( groups.length > 0 ) {
14463 data.data.groups = JSON.parse( JSON.stringify( groups ) );
14467 var boundingSphere = this.boundingSphere;
14469 if ( boundingSphere !== null ) {
14471 data.data.boundingSphere = {
14472 center: boundingSphere.center.toArray(),
14473 radius: boundingSphere.radius
14482 clone: function () {
14485 // Handle primitives
14487 var parameters = this.parameters;
14489 if ( parameters !== undefined ) {
14493 for ( var key in parameters ) {
14495 values.push( parameters[ key ] );
14499 var geometry = Object.create( this.constructor.prototype );
14500 this.constructor.apply( geometry, values );
14505 return new this.constructor().copy( this );
14508 return new BufferGeometry().copy( this );
14512 copy: function ( source ) {
14519 this.attributes = {};
14520 this.morphAttributes = {};
14522 this.boundingBox = null;
14523 this.boundingSphere = null;
14527 this.name = source.name;
14531 var index = source.index;
14533 if ( index !== null ) {
14535 this.setIndex( index.clone() );
14541 var attributes = source.attributes;
14543 for ( name in attributes ) {
14545 var attribute = attributes[ name ];
14546 this.addAttribute( name, attribute.clone() );
14550 // morph attributes
14552 var morphAttributes = source.morphAttributes;
14554 for ( name in morphAttributes ) {
14557 var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
14559 for ( i = 0, l = morphAttribute.length; i < l; i ++ ) {
14561 array.push( morphAttribute[ i ].clone() );
14565 this.morphAttributes[ name ] = array;
14571 var groups = source.groups;
14573 for ( i = 0, l = groups.length; i < l; i ++ ) {
14575 var group = groups[ i ];
14576 this.addGroup( group.start, group.count, group.materialIndex );
14582 var boundingBox = source.boundingBox;
14584 if ( boundingBox !== null ) {
14586 this.boundingBox = boundingBox.clone();
14592 var boundingSphere = source.boundingSphere;
14594 if ( boundingSphere !== null ) {
14596 this.boundingSphere = boundingSphere.clone();
14602 this.drawRange.start = source.drawRange.start;
14603 this.drawRange.count = source.drawRange.count;
14609 dispose: function () {
14611 this.dispatchEvent( { type: 'dispose' } );
14618 * @author mrdoob / http://mrdoob.com/
14619 * @author Mugen87 / https://github.com/Mugen87
14624 function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
14626 Geometry.call( this );
14628 this.type = 'BoxGeometry';
14630 this.parameters = {
14634 widthSegments: widthSegments,
14635 heightSegments: heightSegments,
14636 depthSegments: depthSegments
14639 this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
14640 this.mergeVertices();
14644 BoxGeometry.prototype = Object.create( Geometry.prototype );
14645 BoxGeometry.prototype.constructor = BoxGeometry;
14647 // BoxBufferGeometry
14649 function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
14651 BufferGeometry.call( this );
14653 this.type = 'BoxBufferGeometry';
14655 this.parameters = {
14659 widthSegments: widthSegments,
14660 heightSegments: heightSegments,
14661 depthSegments: depthSegments
14668 widthSegments = Math.floor( widthSegments ) || 1;
14669 heightSegments = Math.floor( heightSegments ) || 1;
14670 depthSegments = Math.floor( depthSegments ) || 1;
14679 // helper variables
14681 var numberOfVertices = 0;
14682 var groupStart = 0;
14684 // build each side of the box geometry
14686 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
14687 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
14688 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
14689 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
14690 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
14691 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
14695 this.setIndex( indices );
14696 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
14697 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
14698 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
14700 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
14702 var segmentWidth = width / gridX;
14703 var segmentHeight = height / gridY;
14705 var widthHalf = width / 2;
14706 var heightHalf = height / 2;
14707 var depthHalf = depth / 2;
14709 var gridX1 = gridX + 1;
14710 var gridY1 = gridY + 1;
14712 var vertexCounter = 0;
14713 var groupCount = 0;
14717 var vector = new Vector3();
14719 // generate vertices, normals and uvs
14721 for ( iy = 0; iy < gridY1; iy ++ ) {
14723 var y = iy * segmentHeight - heightHalf;
14725 for ( ix = 0; ix < gridX1; ix ++ ) {
14727 var x = ix * segmentWidth - widthHalf;
14729 // set values to correct vector component
14731 vector[ u ] = x * udir;
14732 vector[ v ] = y * vdir;
14733 vector[ w ] = depthHalf;
14735 // now apply vector to vertex buffer
14737 vertices.push( vector.x, vector.y, vector.z );
14739 // set values to correct vector component
14743 vector[ w ] = depth > 0 ? 1 : - 1;
14745 // now apply vector to normal buffer
14747 normals.push( vector.x, vector.y, vector.z );
14751 uvs.push( ix / gridX );
14752 uvs.push( 1 - ( iy / gridY ) );
14756 vertexCounter += 1;
14764 // 1. you need three indices to draw a single face
14765 // 2. a single segment consists of two faces
14766 // 3. so we need to generate six (2*3) indices per segment
14768 for ( iy = 0; iy < gridY; iy ++ ) {
14770 for ( ix = 0; ix < gridX; ix ++ ) {
14772 var a = numberOfVertices + ix + gridX1 * iy;
14773 var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
14774 var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
14775 var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
14779 indices.push( a, b, d );
14780 indices.push( b, c, d );
14782 // increase counter
14790 // add a group to the geometry. this will ensure multi material support
14792 scope.addGroup( groupStart, groupCount, materialIndex );
14794 // calculate new start value for groups
14796 groupStart += groupCount;
14798 // update total number of vertices
14800 numberOfVertices += vertexCounter;
14806 BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
14807 BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
14810 * @author mrdoob / http://mrdoob.com/
14811 * @author Mugen87 / https://github.com/Mugen87
14816 function PlaneGeometry( width, height, widthSegments, heightSegments ) {
14818 Geometry.call( this );
14820 this.type = 'PlaneGeometry';
14822 this.parameters = {
14825 widthSegments: widthSegments,
14826 heightSegments: heightSegments
14829 this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
14830 this.mergeVertices();
14834 PlaneGeometry.prototype = Object.create( Geometry.prototype );
14835 PlaneGeometry.prototype.constructor = PlaneGeometry;
14837 // PlaneBufferGeometry
14839 function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
14841 BufferGeometry.call( this );
14843 this.type = 'PlaneBufferGeometry';
14845 this.parameters = {
14848 widthSegments: widthSegments,
14849 heightSegments: heightSegments
14852 var width_half = width / 2;
14853 var height_half = height / 2;
14855 var gridX = Math.floor( widthSegments ) || 1;
14856 var gridY = Math.floor( heightSegments ) || 1;
14858 var gridX1 = gridX + 1;
14859 var gridY1 = gridY + 1;
14861 var segment_width = width / gridX;
14862 var segment_height = height / gridY;
14873 // generate vertices, normals and uvs
14875 for ( iy = 0; iy < gridY1; iy ++ ) {
14877 var y = iy * segment_height - height_half;
14879 for ( ix = 0; ix < gridX1; ix ++ ) {
14881 var x = ix * segment_width - width_half;
14883 vertices.push( x, - y, 0 );
14885 normals.push( 0, 0, 1 );
14887 uvs.push( ix / gridX );
14888 uvs.push( 1 - ( iy / gridY ) );
14896 for ( iy = 0; iy < gridY; iy ++ ) {
14898 for ( ix = 0; ix < gridX; ix ++ ) {
14900 var a = ix + gridX1 * iy;
14901 var b = ix + gridX1 * ( iy + 1 );
14902 var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
14903 var d = ( ix + 1 ) + gridX1 * iy;
14907 indices.push( a, b, d );
14908 indices.push( b, c, d );
14916 this.setIndex( indices );
14917 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
14918 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
14919 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
14923 PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
14924 PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
14927 * @author mrdoob / http://mrdoob.com/
14928 * @author alteredq / http://alteredqualia.com/
14932 * opacity: <float>,
14933 * map: new THREE.Texture( <Image> ),
14935 * lightMap: new THREE.Texture( <Image> ),
14936 * lightMapIntensity: <float>
14938 * aoMap: new THREE.Texture( <Image> ),
14939 * aoMapIntensity: <float>
14941 * specularMap: new THREE.Texture( <Image> ),
14943 * alphaMap: new THREE.Texture( <Image> ),
14945 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
14946 * combine: THREE.Multiply,
14947 * reflectivity: <float>,
14948 * refractionRatio: <float>,
14950 * depthTest: <bool>,
14951 * depthWrite: <bool>,
14953 * wireframe: <boolean>,
14954 * wireframeLinewidth: <float>,
14956 * skinning: <bool>,
14957 * morphTargets: <bool>
14961 function MeshBasicMaterial( parameters ) {
14963 Material.call( this );
14965 this.type = 'MeshBasicMaterial';
14967 this.color = new Color( 0xffffff ); // emissive
14971 this.lightMap = null;
14972 this.lightMapIntensity = 1.0;
14975 this.aoMapIntensity = 1.0;
14977 this.specularMap = null;
14979 this.alphaMap = null;
14981 this.envMap = null;
14982 this.combine = MultiplyOperation;
14983 this.reflectivity = 1;
14984 this.refractionRatio = 0.98;
14986 this.wireframe = false;
14987 this.wireframeLinewidth = 1;
14988 this.wireframeLinecap = 'round';
14989 this.wireframeLinejoin = 'round';
14991 this.skinning = false;
14992 this.morphTargets = false;
14994 this.lights = false;
14996 this.setValues( parameters );
15000 MeshBasicMaterial.prototype = Object.create( Material.prototype );
15001 MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
15003 MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
15005 MeshBasicMaterial.prototype.copy = function ( source ) {
15007 Material.prototype.copy.call( this, source );
15009 this.color.copy( source.color );
15011 this.map = source.map;
15013 this.lightMap = source.lightMap;
15014 this.lightMapIntensity = source.lightMapIntensity;
15016 this.aoMap = source.aoMap;
15017 this.aoMapIntensity = source.aoMapIntensity;
15019 this.specularMap = source.specularMap;
15021 this.alphaMap = source.alphaMap;
15023 this.envMap = source.envMap;
15024 this.combine = source.combine;
15025 this.reflectivity = source.reflectivity;
15026 this.refractionRatio = source.refractionRatio;
15028 this.wireframe = source.wireframe;
15029 this.wireframeLinewidth = source.wireframeLinewidth;
15030 this.wireframeLinecap = source.wireframeLinecap;
15031 this.wireframeLinejoin = source.wireframeLinejoin;
15033 this.skinning = source.skinning;
15034 this.morphTargets = source.morphTargets;
15041 * @author bhouston / http://clara.io
15044 function Ray( origin, direction ) {
15046 this.origin = ( origin !== undefined ) ? origin : new Vector3();
15047 this.direction = ( direction !== undefined ) ? direction : new Vector3();
15051 Object.assign( Ray.prototype, {
15053 set: function ( origin, direction ) {
15055 this.origin.copy( origin );
15056 this.direction.copy( direction );
15062 clone: function () {
15064 return new this.constructor().copy( this );
15068 copy: function ( ray ) {
15070 this.origin.copy( ray.origin );
15071 this.direction.copy( ray.direction );
15077 at: function ( t, optionalTarget ) {
15079 var result = optionalTarget || new Vector3();
15081 return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
15085 lookAt: function ( v ) {
15087 this.direction.copy( v ).sub( this.origin ).normalize();
15093 recast: function () {
15095 var v1 = new Vector3();
15097 return function recast( t ) {
15099 this.origin.copy( this.at( t, v1 ) );
15107 closestPointToPoint: function ( point, optionalTarget ) {
15109 var result = optionalTarget || new Vector3();
15110 result.subVectors( point, this.origin );
15111 var directionDistance = result.dot( this.direction );
15113 if ( directionDistance < 0 ) {
15115 return result.copy( this.origin );
15119 return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
15123 distanceToPoint: function ( point ) {
15125 return Math.sqrt( this.distanceSqToPoint( point ) );
15129 distanceSqToPoint: function () {
15131 var v1 = new Vector3();
15133 return function distanceSqToPoint( point ) {
15135 var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
15137 // point behind the ray
15139 if ( directionDistance < 0 ) {
15141 return this.origin.distanceToSquared( point );
15145 v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
15147 return v1.distanceToSquared( point );
15153 distanceSqToSegment: function () {
15155 var segCenter = new Vector3();
15156 var segDir = new Vector3();
15157 var diff = new Vector3();
15159 return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
15161 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
15162 // It returns the min distance between the ray and the segment
15163 // defined by v0 and v1
15164 // It can also set two optional targets :
15165 // - The closest point on the ray
15166 // - The closest point on the segment
15168 segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
15169 segDir.copy( v1 ).sub( v0 ).normalize();
15170 diff.copy( this.origin ).sub( segCenter );
15172 var segExtent = v0.distanceTo( v1 ) * 0.5;
15173 var a01 = - this.direction.dot( segDir );
15174 var b0 = diff.dot( this.direction );
15175 var b1 = - diff.dot( segDir );
15176 var c = diff.lengthSq();
15177 var det = Math.abs( 1 - a01 * a01 );
15178 var s0, s1, sqrDist, extDet;
15182 // The ray and segment are not parallel.
15184 s0 = a01 * b1 - b0;
15185 s1 = a01 * b0 - b1;
15186 extDet = segExtent * det;
15190 if ( s1 >= - extDet ) {
15192 if ( s1 <= extDet ) {
15195 // Minimum at interior points of ray and segment.
15197 var invDet = 1 / det;
15200 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
15207 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
15208 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
15217 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
15218 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
15224 if ( s1 <= - extDet ) {
15228 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
15229 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
15230 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
15232 } else if ( s1 <= extDet ) {
15237 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
15238 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
15244 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
15245 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
15246 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
15254 // Ray and segment are parallel.
15256 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
15257 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
15258 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
15262 if ( optionalPointOnRay ) {
15264 optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
15268 if ( optionalPointOnSegment ) {
15270 optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
15280 intersectSphere: function () {
15282 var v1 = new Vector3();
15284 return function intersectSphere( sphere, optionalTarget ) {
15286 v1.subVectors( sphere.center, this.origin );
15287 var tca = v1.dot( this.direction );
15288 var d2 = v1.dot( v1 ) - tca * tca;
15289 var radius2 = sphere.radius * sphere.radius;
15291 if ( d2 > radius2 ) return null;
15293 var thc = Math.sqrt( radius2 - d2 );
15295 // t0 = first intersect point - entrance on front of sphere
15296 var t0 = tca - thc;
15298 // t1 = second intersect point - exit point on back of sphere
15299 var t1 = tca + thc;
15301 // test to see if both t0 and t1 are behind the ray - if so, return null
15302 if ( t0 < 0 && t1 < 0 ) return null;
15304 // test to see if t0 is behind the ray:
15305 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
15306 // in order to always return an intersect point that is in front of the ray.
15307 if ( t0 < 0 ) return this.at( t1, optionalTarget );
15309 // else t0 is in front of the ray, so return the first collision point scaled by t0
15310 return this.at( t0, optionalTarget );
15316 intersectsSphere: function ( sphere ) {
15318 return this.distanceToPoint( sphere.center ) <= sphere.radius;
15322 distanceToPlane: function ( plane ) {
15324 var denominator = plane.normal.dot( this.direction );
15326 if ( denominator === 0 ) {
15328 // line is coplanar, return origin
15329 if ( plane.distanceToPoint( this.origin ) === 0 ) {
15335 // Null is preferable to undefined since undefined means.... it is undefined
15341 var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
15343 // Return if the ray never intersects the plane
15345 return t >= 0 ? t : null;
15349 intersectPlane: function ( plane, optionalTarget ) {
15351 var t = this.distanceToPlane( plane );
15353 if ( t === null ) {
15359 return this.at( t, optionalTarget );
15363 intersectsPlane: function ( plane ) {
15365 // check if the ray lies on the plane first
15367 var distToPoint = plane.distanceToPoint( this.origin );
15369 if ( distToPoint === 0 ) {
15375 var denominator = plane.normal.dot( this.direction );
15377 if ( denominator * distToPoint < 0 ) {
15383 // ray origin is behind the plane (and is pointing behind it)
15389 intersectBox: function ( box, optionalTarget ) {
15391 var tmin, tmax, tymin, tymax, tzmin, tzmax;
15393 var invdirx = 1 / this.direction.x,
15394 invdiry = 1 / this.direction.y,
15395 invdirz = 1 / this.direction.z;
15397 var origin = this.origin;
15399 if ( invdirx >= 0 ) {
15401 tmin = ( box.min.x - origin.x ) * invdirx;
15402 tmax = ( box.max.x - origin.x ) * invdirx;
15406 tmin = ( box.max.x - origin.x ) * invdirx;
15407 tmax = ( box.min.x - origin.x ) * invdirx;
15411 if ( invdiry >= 0 ) {
15413 tymin = ( box.min.y - origin.y ) * invdiry;
15414 tymax = ( box.max.y - origin.y ) * invdiry;
15418 tymin = ( box.max.y - origin.y ) * invdiry;
15419 tymax = ( box.min.y - origin.y ) * invdiry;
15423 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
15425 // These lines also handle the case where tmin or tmax is NaN
15426 // (result of 0 * Infinity). x !== x returns true if x is NaN
15428 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
15430 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
15432 if ( invdirz >= 0 ) {
15434 tzmin = ( box.min.z - origin.z ) * invdirz;
15435 tzmax = ( box.max.z - origin.z ) * invdirz;
15439 tzmin = ( box.max.z - origin.z ) * invdirz;
15440 tzmax = ( box.min.z - origin.z ) * invdirz;
15444 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
15446 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
15448 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
15450 //return point closest to the ray (positive side)
15452 if ( tmax < 0 ) return null;
15454 return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
15458 intersectsBox: ( function () {
15460 var v = new Vector3();
15462 return function intersectsBox( box ) {
15464 return this.intersectBox( box, v ) !== null;
15470 intersectTriangle: function () {
15472 // Compute the offset origin, edges, and normal.
15473 var diff = new Vector3();
15474 var edge1 = new Vector3();
15475 var edge2 = new Vector3();
15476 var normal = new Vector3();
15478 return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {
15480 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
15482 edge1.subVectors( b, a );
15483 edge2.subVectors( c, a );
15484 normal.crossVectors( edge1, edge2 );
15486 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
15487 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
15488 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
15489 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
15490 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
15491 var DdN = this.direction.dot( normal );
15496 if ( backfaceCulling ) return null;
15499 } else if ( DdN < 0 ) {
15510 diff.subVectors( this.origin, a );
15511 var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
15513 // b1 < 0, no intersection
15514 if ( DdQxE2 < 0 ) {
15520 var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
15522 // b2 < 0, no intersection
15523 if ( DdE1xQ < 0 ) {
15529 // b1+b2 > 1, no intersection
15530 if ( DdQxE2 + DdE1xQ > DdN ) {
15536 // Line intersects triangle, check if ray does.
15537 var QdN = - sign * diff.dot( normal );
15539 // t < 0, no intersection
15546 // Ray intersects triangle.
15547 return this.at( QdN / DdN, optionalTarget );
15553 applyMatrix4: function ( matrix4 ) {
15555 this.origin.applyMatrix4( matrix4 );
15556 this.direction.transformDirection( matrix4 );
15562 equals: function ( ray ) {
15564 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
15571 * @author bhouston / http://clara.io
15574 function Line3( start, end ) {
15576 this.start = ( start !== undefined ) ? start : new Vector3();
15577 this.end = ( end !== undefined ) ? end : new Vector3();
15581 Object.assign( Line3.prototype, {
15583 set: function ( start, end ) {
15585 this.start.copy( start );
15586 this.end.copy( end );
15592 clone: function () {
15594 return new this.constructor().copy( this );
15598 copy: function ( line ) {
15600 this.start.copy( line.start );
15601 this.end.copy( line.end );
15607 getCenter: function ( optionalTarget ) {
15609 var result = optionalTarget || new Vector3();
15610 return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
15614 delta: function ( optionalTarget ) {
15616 var result = optionalTarget || new Vector3();
15617 return result.subVectors( this.end, this.start );
15621 distanceSq: function () {
15623 return this.start.distanceToSquared( this.end );
15627 distance: function () {
15629 return this.start.distanceTo( this.end );
15633 at: function ( t, optionalTarget ) {
15635 var result = optionalTarget || new Vector3();
15637 return this.delta( result ).multiplyScalar( t ).add( this.start );
15641 closestPointToPointParameter: function () {
15643 var startP = new Vector3();
15644 var startEnd = new Vector3();
15646 return function closestPointToPointParameter( point, clampToLine ) {
15648 startP.subVectors( point, this.start );
15649 startEnd.subVectors( this.end, this.start );
15651 var startEnd2 = startEnd.dot( startEnd );
15652 var startEnd_startP = startEnd.dot( startP );
15654 var t = startEnd_startP / startEnd2;
15656 if ( clampToLine ) {
15658 t = _Math.clamp( t, 0, 1 );
15668 closestPointToPoint: function ( point, clampToLine, optionalTarget ) {
15670 var t = this.closestPointToPointParameter( point, clampToLine );
15672 var result = optionalTarget || new Vector3();
15674 return this.delta( result ).multiplyScalar( t ).add( this.start );
15678 applyMatrix4: function ( matrix ) {
15680 this.start.applyMatrix4( matrix );
15681 this.end.applyMatrix4( matrix );
15687 equals: function ( line ) {
15689 return line.start.equals( this.start ) && line.end.equals( this.end );
15696 * @author bhouston / http://clara.io
15697 * @author mrdoob / http://mrdoob.com/
15700 function Triangle( a, b, c ) {
15702 this.a = ( a !== undefined ) ? a : new Vector3();
15703 this.b = ( b !== undefined ) ? b : new Vector3();
15704 this.c = ( c !== undefined ) ? c : new Vector3();
15708 Object.assign( Triangle, {
15710 normal: function () {
15712 var v0 = new Vector3();
15714 return function normal( a, b, c, optionalTarget ) {
15716 var result = optionalTarget || new Vector3();
15718 result.subVectors( c, b );
15719 v0.subVectors( a, b );
15720 result.cross( v0 );
15722 var resultLengthSq = result.lengthSq();
15723 if ( resultLengthSq > 0 ) {
15725 return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
15729 return result.set( 0, 0, 0 );
15735 // static/instance method to calculate barycentric coordinates
15736 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
15737 barycoordFromPoint: function () {
15739 var v0 = new Vector3();
15740 var v1 = new Vector3();
15741 var v2 = new Vector3();
15743 return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
15745 v0.subVectors( c, a );
15746 v1.subVectors( b, a );
15747 v2.subVectors( point, a );
15749 var dot00 = v0.dot( v0 );
15750 var dot01 = v0.dot( v1 );
15751 var dot02 = v0.dot( v2 );
15752 var dot11 = v1.dot( v1 );
15753 var dot12 = v1.dot( v2 );
15755 var denom = ( dot00 * dot11 - dot01 * dot01 );
15757 var result = optionalTarget || new Vector3();
15759 // collinear or singular triangle
15760 if ( denom === 0 ) {
15762 // arbitrary location outside of triangle?
15763 // not sure if this is the best idea, maybe should be returning undefined
15764 return result.set( - 2, - 1, - 1 );
15768 var invDenom = 1 / denom;
15769 var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
15770 var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
15772 // barycentric coordinates must always sum to 1
15773 return result.set( 1 - u - v, v, u );
15779 containsPoint: function () {
15781 var v1 = new Vector3();
15783 return function containsPoint( point, a, b, c ) {
15785 var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
15787 return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
15795 Object.assign( Triangle.prototype, {
15797 set: function ( a, b, c ) {
15807 setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
15809 this.a.copy( points[ i0 ] );
15810 this.b.copy( points[ i1 ] );
15811 this.c.copy( points[ i2 ] );
15817 clone: function () {
15819 return new this.constructor().copy( this );
15823 copy: function ( triangle ) {
15825 this.a.copy( triangle.a );
15826 this.b.copy( triangle.b );
15827 this.c.copy( triangle.c );
15833 area: function () {
15835 var v0 = new Vector3();
15836 var v1 = new Vector3();
15838 return function area() {
15840 v0.subVectors( this.c, this.b );
15841 v1.subVectors( this.a, this.b );
15843 return v0.cross( v1 ).length() * 0.5;
15849 midpoint: function ( optionalTarget ) {
15851 var result = optionalTarget || new Vector3();
15852 return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
15856 normal: function ( optionalTarget ) {
15858 return Triangle.normal( this.a, this.b, this.c, optionalTarget );
15862 plane: function ( optionalTarget ) {
15864 var result = optionalTarget || new Plane();
15866 return result.setFromCoplanarPoints( this.a, this.b, this.c );
15870 barycoordFromPoint: function ( point, optionalTarget ) {
15872 return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
15876 containsPoint: function ( point ) {
15878 return Triangle.containsPoint( point, this.a, this.b, this.c );
15882 closestPointToPoint: function () {
15884 var plane = new Plane();
15885 var edgeList = [ new Line3(), new Line3(), new Line3() ];
15886 var projectedPoint = new Vector3();
15887 var closestPoint = new Vector3();
15889 return function closestPointToPoint( point, optionalTarget ) {
15891 var result = optionalTarget || new Vector3();
15892 var minDistance = Infinity;
15894 // project the point onto the plane of the triangle
15896 plane.setFromCoplanarPoints( this.a, this.b, this.c );
15897 plane.projectPoint( point, projectedPoint );
15899 // check if the projection lies within the triangle
15901 if( this.containsPoint( projectedPoint ) === true ) {
15903 // if so, this is the closest point
15905 result.copy( projectedPoint );
15909 // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices
15911 edgeList[ 0 ].set( this.a, this.b );
15912 edgeList[ 1 ].set( this.b, this.c );
15913 edgeList[ 2 ].set( this.c, this.a );
15915 for( var i = 0; i < edgeList.length; i ++ ) {
15917 edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
15919 var distance = projectedPoint.distanceToSquared( closestPoint );
15921 if( distance < minDistance ) {
15923 minDistance = distance;
15925 result.copy( closestPoint );
15939 equals: function ( triangle ) {
15941 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
15948 * @author mrdoob / http://mrdoob.com/
15949 * @author alteredq / http://alteredqualia.com/
15950 * @author mikael emtinger / http://gomo.se/
15951 * @author jonobr1 / http://jonobr1.com/
15954 function Mesh( geometry, material ) {
15956 Object3D.call( this );
15958 this.type = 'Mesh';
15960 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
15961 this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );
15963 this.drawMode = TrianglesDrawMode;
15965 this.updateMorphTargets();
15969 Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
15975 setDrawMode: function ( value ) {
15977 this.drawMode = value;
15981 copy: function ( source ) {
15983 Object3D.prototype.copy.call( this, source );
15985 this.drawMode = source.drawMode;
15991 updateMorphTargets: function () {
15993 var geometry = this.geometry;
15996 if ( geometry.isBufferGeometry ) {
15998 var morphAttributes = geometry.morphAttributes;
15999 var keys = Object.keys( morphAttributes );
16001 if ( keys.length > 0 ) {
16003 var morphAttribute = morphAttributes[ keys[ 0 ] ];
16005 if ( morphAttribute !== undefined ) {
16007 this.morphTargetInfluences = [];
16008 this.morphTargetDictionary = {};
16010 for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
16012 name = morphAttribute[ m ].name || String( m );
16014 this.morphTargetInfluences.push( 0 );
16015 this.morphTargetDictionary[ name ] = m;
16025 var morphTargets = geometry.morphTargets;
16027 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
16029 this.morphTargetInfluences = [];
16030 this.morphTargetDictionary = {};
16032 for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) {
16034 name = morphTargets[ m ].name || String( m );
16036 this.morphTargetInfluences.push( 0 );
16037 this.morphTargetDictionary[ name ] = m;
16047 raycast: ( function () {
16049 var inverseMatrix = new Matrix4();
16050 var ray = new Ray();
16051 var sphere = new Sphere();
16053 var vA = new Vector3();
16054 var vB = new Vector3();
16055 var vC = new Vector3();
16057 var tempA = new Vector3();
16058 var tempB = new Vector3();
16059 var tempC = new Vector3();
16061 var uvA = new Vector2();
16062 var uvB = new Vector2();
16063 var uvC = new Vector2();
16065 var barycoord = new Vector3();
16067 var intersectionPoint = new Vector3();
16068 var intersectionPointWorld = new Vector3();
16070 function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
16072 Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord );
16074 uv1.multiplyScalar( barycoord.x );
16075 uv2.multiplyScalar( barycoord.y );
16076 uv3.multiplyScalar( barycoord.z );
16078 uv1.add( uv2 ).add( uv3 );
16080 return uv1.clone();
16084 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
16088 if ( material.side === BackSide ) {
16090 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
16094 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
16098 if ( intersect === null ) return null;
16100 intersectionPointWorld.copy( point );
16101 intersectionPointWorld.applyMatrix4( object.matrixWorld );
16103 var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );
16105 if ( distance < raycaster.near || distance > raycaster.far ) return null;
16108 distance: distance,
16109 point: intersectionPointWorld.clone(),
16115 function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {
16117 vA.fromBufferAttribute( position, a );
16118 vB.fromBufferAttribute( position, b );
16119 vC.fromBufferAttribute( position, c );
16121 var intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint );
16123 if ( intersection ) {
16127 uvA.fromBufferAttribute( uv, a );
16128 uvB.fromBufferAttribute( uv, b );
16129 uvC.fromBufferAttribute( uv, c );
16131 intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );
16135 intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );
16136 intersection.faceIndex = a;
16140 return intersection;
16144 return function raycast( raycaster, intersects ) {
16146 var geometry = this.geometry;
16147 var material = this.material;
16148 var matrixWorld = this.matrixWorld;
16150 if ( material === undefined ) return;
16152 // Checking boundingSphere distance to ray
16154 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
16156 sphere.copy( geometry.boundingSphere );
16157 sphere.applyMatrix4( matrixWorld );
16159 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
16163 inverseMatrix.getInverse( matrixWorld );
16164 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
16166 // Check boundingBox before continuing
16168 if ( geometry.boundingBox !== null ) {
16170 if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;
16176 if ( geometry.isBufferGeometry ) {
16179 var index = geometry.index;
16180 var position = geometry.attributes.position;
16181 var uv = geometry.attributes.uv;
16184 if ( index !== null ) {
16186 // indexed buffer geometry
16188 for ( i = 0, l = index.count; i < l; i += 3 ) {
16190 a = index.getX( i );
16191 b = index.getX( i + 1 );
16192 c = index.getX( i + 2 );
16194 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
16196 if ( intersection ) {
16198 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics
16199 intersects.push( intersection );
16207 // non-indexed buffer geometry
16209 for ( i = 0, l = position.count; i < l; i += 3 ) {
16215 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
16217 if ( intersection ) {
16219 intersection.index = a; // triangle number in positions buffer semantics
16220 intersects.push( intersection );
16228 } else if ( geometry.isGeometry ) {
16231 var isMultiMaterial = Array.isArray( material );
16233 var vertices = geometry.vertices;
16234 var faces = geometry.faces;
16237 var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
16238 if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
16240 for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
16242 var face = faces[ f ];
16243 var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;
16245 if ( faceMaterial === undefined ) continue;
16247 fvA = vertices[ face.a ];
16248 fvB = vertices[ face.b ];
16249 fvC = vertices[ face.c ];
16251 if ( faceMaterial.morphTargets === true ) {
16253 var morphTargets = geometry.morphTargets;
16254 var morphInfluences = this.morphTargetInfluences;
16260 for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
16262 var influence = morphInfluences[ t ];
16264 if ( influence === 0 ) continue;
16266 var targets = morphTargets[ t ].vertices;
16268 vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );
16269 vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );
16270 vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );
16284 intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
16286 if ( intersection ) {
16288 if ( uvs && uvs[ f ] ) {
16290 var uvs_f = uvs[ f ];
16291 uvA.copy( uvs_f[ 0 ] );
16292 uvB.copy( uvs_f[ 1 ] );
16293 uvC.copy( uvs_f[ 2 ] );
16295 intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );
16299 intersection.face = face;
16300 intersection.faceIndex = f;
16301 intersects.push( intersection );
16313 clone: function () {
16315 return new this.constructor( this.geometry, this.material ).copy( this );
16322 * @author mrdoob / http://mrdoob.com/
16325 function WebGLBackground( renderer, state, geometries, premultipliedAlpha ) {
16327 var clearColor = new Color( 0x000000 );
16328 var clearAlpha = 0;
16330 var planeCamera, planeMesh;
16333 function render( renderList, scene, camera, forceClear ) {
16335 var background = scene.background;
16337 if ( background === null ) {
16339 setClear( clearColor, clearAlpha );
16341 } else if ( background && background.isColor ) {
16343 setClear( background, 1 );
16348 if ( renderer.autoClear || forceClear ) {
16350 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
16354 if ( background && background.isCubeTexture ) {
16356 if ( boxMesh === undefined ) {
16358 boxMesh = new Mesh(
16359 new BoxBufferGeometry( 1, 1, 1 ),
16360 new ShaderMaterial( {
16361 uniforms: ShaderLib.cube.uniforms,
16362 vertexShader: ShaderLib.cube.vertexShader,
16363 fragmentShader: ShaderLib.cube.fragmentShader,
16367 polygonOffset: true,
16372 boxMesh.geometry.removeAttribute( 'normal' );
16373 boxMesh.geometry.removeAttribute( 'uv' );
16375 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
16377 var scale = camera.far;
16379 this.matrixWorld.makeScale( scale, scale, scale );
16380 this.matrixWorld.copyPosition( camera.matrixWorld );
16382 this.material.polygonOffsetUnits = scale * 10;
16386 geometries.update( boxMesh.geometry );
16390 boxMesh.material.uniforms.tCube.value = background;
16392 renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );
16394 } else if ( background && background.isTexture ) {
16396 if ( planeCamera === undefined ) {
16398 planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
16400 planeMesh = new Mesh(
16401 new PlaneBufferGeometry( 2, 2 ),
16402 new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
16405 geometries.update( planeMesh.geometry );
16409 planeMesh.material.map = background;
16411 // TODO Push this to renderList
16413 renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null );
16419 function setClear( color, alpha ) {
16421 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
16427 getClearColor: function () {
16432 setClearColor: function ( color, alpha ) {
16434 clearColor.set( color );
16435 clearAlpha = alpha !== undefined ? alpha : 1;
16436 setClear( clearColor, clearAlpha );
16439 getClearAlpha: function () {
16444 setClearAlpha: function ( alpha ) {
16446 clearAlpha = alpha;
16447 setClear( clearColor, clearAlpha );
16457 * @author mrdoob / http://mrdoob.com/
16460 function painterSortStable( a, b ) {
16462 if ( a.renderOrder !== b.renderOrder ) {
16464 return a.renderOrder - b.renderOrder;
16466 } else if ( a.program && b.program && a.program !== b.program ) {
16468 return a.program.id - b.program.id;
16470 } else if ( a.material.id !== b.material.id ) {
16472 return a.material.id - b.material.id;
16474 } else if ( a.z !== b.z ) {
16480 return a.id - b.id;
16486 function reversePainterSortStable( a, b ) {
16488 if ( a.renderOrder !== b.renderOrder ) {
16490 return a.renderOrder - b.renderOrder;
16492 } if ( a.z !== b.z ) {
16498 return a.id - b.id;
16504 function WebGLRenderList() {
16506 var renderItems = [];
16507 var renderItemsIndex = 0;
16510 var transparent = [];
16514 renderItemsIndex = 0;
16517 transparent.length = 0;
16521 function push( object, geometry, material, z, group ) {
16523 var renderItem = renderItems[ renderItemsIndex ];
16525 if ( renderItem === undefined ) {
16530 geometry: geometry,
16531 material: material,
16532 program: material.program,
16533 renderOrder: object.renderOrder,
16538 renderItems[ renderItemsIndex ] = renderItem;
16542 renderItem.id = object.id;
16543 renderItem.object = object;
16544 renderItem.geometry = geometry;
16545 renderItem.material = material;
16546 renderItem.program = material.program;
16547 renderItem.renderOrder = object.renderOrder;
16549 renderItem.group = group;
16553 ( material.transparent === true ? transparent : opaque ).push( renderItem );
16555 renderItemsIndex ++;
16561 if ( opaque.length > 1 ) opaque.sort( painterSortStable );
16562 if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable );
16568 transparent: transparent,
16578 function WebGLRenderLists() {
16582 function get( scene, camera ) {
16584 var hash = scene.id + ',' + camera.id;
16585 var list = lists[ hash ];
16587 if ( list === undefined ) {
16589 // console.log( 'THREE.WebGLRenderLists:', hash );
16591 list = new WebGLRenderList();
16592 lists[ hash ] = list;
16600 function dispose() {
16614 * @author mrdoob / http://mrdoob.com/
16617 function absNumericalSort( a, b ) {
16619 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
16623 function WebGLMorphtargets( gl ) {
16625 var influencesList = {};
16626 var morphInfluences = new Float32Array( 8 );
16628 function update( object, geometry, material, program ) {
16630 var objectInfluences = object.morphTargetInfluences;
16632 var length = objectInfluences.length;
16634 var influences = influencesList[ geometry.id ];
16636 if ( influences === undefined ) {
16642 for ( var i = 0; i < length; i ++ ) {
16644 influences[ i ] = [ i, 0 ];
16648 influencesList[ geometry.id ] = influences;
16652 var morphTargets = material.morphTargets && geometry.morphAttributes.position;
16653 var morphNormals = material.morphNormals && geometry.morphAttributes.normal;
16655 // Remove current morphAttributes
16657 for ( var i = 0; i < length; i ++ ) {
16659 var influence = influences[ i ];
16661 if ( influence[ 1 ] !== 0 ) {
16663 if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i );
16664 if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i );
16670 // Collect influences
16672 for ( var i = 0; i < length; i ++ ) {
16674 var influence = influences[ i ];
16676 influence[ 0 ] = i;
16677 influence[ 1 ] = objectInfluences[ i ];
16681 influences.sort( absNumericalSort );
16683 // Add morphAttributes
16685 for ( var i = 0; i < 8; i ++ ) {
16687 var influence = influences[ i ];
16691 var index = influence[ 0 ];
16692 var value = influence[ 1 ];
16696 if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] );
16697 if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] );
16699 morphInfluences[ i ] = value;
16706 morphInfluences[ i ] = 0;
16710 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
16723 * @author mrdoob / http://mrdoob.com/
16726 function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {
16730 function setMode( value ) {
16736 var type, bytesPerElement;
16738 function setIndex( value ) {
16741 bytesPerElement = value.bytesPerElement;
16745 function render( start, count ) {
16747 gl.drawElements( mode, count, type, start * bytesPerElement );
16749 infoRender.calls ++;
16750 infoRender.vertices += count;
16752 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
16753 else if ( mode === gl.POINTS ) infoRender.points += count;
16757 function renderInstances( geometry, start, count ) {
16759 var extension = extensions.get( 'ANGLE_instanced_arrays' );
16761 if ( extension === null ) {
16763 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
16768 extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );
16770 infoRender.calls ++;
16771 infoRender.vertices += count * geometry.maxInstancedCount;
16773 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
16774 else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;
16780 this.setMode = setMode;
16781 this.setIndex = setIndex;
16782 this.render = render;
16783 this.renderInstances = renderInstances;
16788 * @author mrdoob / http://mrdoob.com/
16791 function WebGLBufferRenderer( gl, extensions, infoRender ) {
16795 function setMode( value ) {
16801 function render( start, count ) {
16803 gl.drawArrays( mode, start, count );
16805 infoRender.calls ++;
16806 infoRender.vertices += count;
16808 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
16809 else if ( mode === gl.POINTS ) infoRender.points += count;
16813 function renderInstances( geometry, start, count ) {
16815 var extension = extensions.get( 'ANGLE_instanced_arrays' );
16817 if ( extension === null ) {
16819 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
16824 var position = geometry.attributes.position;
16826 if ( position.isInterleavedBufferAttribute ) {
16828 count = position.data.count;
16830 extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );
16834 extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount );
16838 infoRender.calls ++;
16839 infoRender.vertices += count * geometry.maxInstancedCount;
16841 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
16842 else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;
16848 this.setMode = setMode;
16849 this.render = render;
16850 this.renderInstances = renderInstances;
16855 * @author mrdoob / http://mrdoob.com/
16858 function WebGLGeometries( gl, attributes, infoMemory ) {
16860 var geometries = {};
16861 var wireframeAttributes = {};
16863 function onGeometryDispose( event ) {
16865 var geometry = event.target;
16866 var buffergeometry = geometries[ geometry.id ];
16868 if ( buffergeometry.index !== null ) {
16870 attributes.remove( buffergeometry.index );
16874 for ( var name in buffergeometry.attributes ) {
16876 attributes.remove( buffergeometry.attributes[ name ] );
16880 geometry.removeEventListener( 'dispose', onGeometryDispose );
16882 delete geometries[ geometry.id ];
16884 // TODO Remove duplicate code
16886 var attribute = wireframeAttributes[ geometry.id ];
16890 attributes.remove( attribute );
16891 delete wireframeAttributes[ geometry.id ];
16895 attribute = wireframeAttributes[ buffergeometry.id ];
16899 attributes.remove( attribute );
16900 delete wireframeAttributes[ buffergeometry.id ];
16906 infoMemory.geometries --;
16910 function get( object, geometry ) {
16912 var buffergeometry = geometries[ geometry.id ];
16914 if ( buffergeometry ) return buffergeometry;
16916 geometry.addEventListener( 'dispose', onGeometryDispose );
16918 if ( geometry.isBufferGeometry ) {
16920 buffergeometry = geometry;
16922 } else if ( geometry.isGeometry ) {
16924 if ( geometry._bufferGeometry === undefined ) {
16926 geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
16930 buffergeometry = geometry._bufferGeometry;
16934 geometries[ geometry.id ] = buffergeometry;
16936 infoMemory.geometries ++;
16938 return buffergeometry;
16942 function update( geometry ) {
16944 var index = geometry.index;
16945 var geometryAttributes = geometry.attributes;
16947 if ( index !== null ) {
16949 attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
16953 for ( var name in geometryAttributes ) {
16955 attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
16961 var morphAttributes = geometry.morphAttributes;
16963 for ( var name in morphAttributes ) {
16965 var array = morphAttributes[ name ];
16967 for ( var i = 0, l = array.length; i < l; i ++ ) {
16969 attributes.update( array[ i ], gl.ARRAY_BUFFER );
16977 function getWireframeAttribute( geometry ) {
16979 var attribute = wireframeAttributes[ geometry.id ];
16981 if ( attribute ) return attribute;
16985 var geometryIndex = geometry.index;
16986 var geometryAttributes = geometry.attributes;
16988 // console.time( 'wireframe' );
16990 if ( geometryIndex !== null ) {
16992 var array = geometryIndex.array;
16994 for ( var i = 0, l = array.length; i < l; i += 3 ) {
16996 var a = array[ i + 0 ];
16997 var b = array[ i + 1 ];
16998 var c = array[ i + 2 ];
17000 indices.push( a, b, b, c, c, a );
17006 var array = geometryAttributes.position.array;
17008 for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
17014 indices.push( a, b, b, c, c, a );
17020 // console.timeEnd( 'wireframe' );
17022 attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
17024 attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );
17026 wireframeAttributes[ geometry.id ] = attribute;
17037 getWireframeAttribute: getWireframeAttribute
17044 * @author mrdoob / http://mrdoob.com/
17047 function UniformsCache() {
17053 get: function ( light ) {
17055 if ( lights[ light.id ] !== undefined ) {
17057 return lights[ light.id ];
17063 switch ( light.type ) {
17065 case 'DirectionalLight':
17067 direction: new Vector3(),
17068 color: new Color(),
17073 shadowMapSize: new Vector2()
17079 position: new Vector3(),
17080 direction: new Vector3(),
17081 color: new Color(),
17090 shadowMapSize: new Vector2()
17096 position: new Vector3(),
17097 color: new Color(),
17104 shadowMapSize: new Vector2(),
17105 shadowCameraNear: 1,
17106 shadowCameraFar: 1000
17110 case 'HemisphereLight':
17112 direction: new Vector3(),
17113 skyColor: new Color(),
17114 groundColor: new Color()
17118 case 'RectAreaLight':
17120 color: new Color(),
17121 position: new Vector3(),
17122 halfWidth: new Vector3(),
17123 halfHeight: new Vector3()
17124 // TODO (abelnation): set RectAreaLight shadow uniforms
17130 lights[ light.id ] = uniforms;
17140 function WebGLLights() {
17142 var cache = new UniformsCache();
17148 ambient: [ 0, 0, 0 ],
17150 directionalShadowMap: [],
17151 directionalShadowMatrix: [],
17154 spotShadowMatrix: [],
17157 pointShadowMap: [],
17158 pointShadowMatrix: [],
17163 var vector3 = new Vector3();
17164 var matrix4 = new Matrix4();
17165 var matrix42 = new Matrix4();
17167 function setup( lights, shadows, camera ) {
17169 var r = 0, g = 0, b = 0;
17171 var directionalLength = 0;
17172 var pointLength = 0;
17173 var spotLength = 0;
17174 var rectAreaLength = 0;
17175 var hemiLength = 0;
17177 var viewMatrix = camera.matrixWorldInverse;
17179 for ( var i = 0, l = lights.length; i < l; i ++ ) {
17181 var light = lights[ i ];
17183 var color = light.color;
17184 var intensity = light.intensity;
17185 var distance = light.distance;
17187 var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
17189 if ( light.isAmbientLight ) {
17191 r += color.r * intensity;
17192 g += color.g * intensity;
17193 b += color.b * intensity;
17195 } else if ( light.isDirectionalLight ) {
17197 var uniforms = cache.get( light );
17199 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
17200 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
17201 vector3.setFromMatrixPosition( light.target.matrixWorld );
17202 uniforms.direction.sub( vector3 );
17203 uniforms.direction.transformDirection( viewMatrix );
17205 uniforms.shadow = light.castShadow;
17207 if ( light.castShadow ) {
17209 var shadow = light.shadow;
17211 uniforms.shadowBias = shadow.bias;
17212 uniforms.shadowRadius = shadow.radius;
17213 uniforms.shadowMapSize = shadow.mapSize;
17217 state.directionalShadowMap[ directionalLength ] = shadowMap;
17218 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
17219 state.directional[ directionalLength ] = uniforms;
17221 directionalLength ++;
17223 } else if ( light.isSpotLight ) {
17225 var uniforms = cache.get( light );
17227 uniforms.position.setFromMatrixPosition( light.matrixWorld );
17228 uniforms.position.applyMatrix4( viewMatrix );
17230 uniforms.color.copy( color ).multiplyScalar( intensity );
17231 uniforms.distance = distance;
17233 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
17234 vector3.setFromMatrixPosition( light.target.matrixWorld );
17235 uniforms.direction.sub( vector3 );
17236 uniforms.direction.transformDirection( viewMatrix );
17238 uniforms.coneCos = Math.cos( light.angle );
17239 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
17240 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
17242 uniforms.shadow = light.castShadow;
17244 if ( light.castShadow ) {
17246 var shadow = light.shadow;
17248 uniforms.shadowBias = shadow.bias;
17249 uniforms.shadowRadius = shadow.radius;
17250 uniforms.shadowMapSize = shadow.mapSize;
17254 state.spotShadowMap[ spotLength ] = shadowMap;
17255 state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
17256 state.spot[ spotLength ] = uniforms;
17260 } else if ( light.isRectAreaLight ) {
17262 var uniforms = cache.get( light );
17264 // (a) intensity controls irradiance of entire light
17267 .multiplyScalar( intensity / ( light.width * light.height ) );
17269 // (b) intensity controls the radiance per light area
17270 // uniforms.color.copy( color ).multiplyScalar( intensity );
17272 uniforms.position.setFromMatrixPosition( light.matrixWorld );
17273 uniforms.position.applyMatrix4( viewMatrix );
17275 // extract local rotation of light to derive width/height half vectors
17276 matrix42.identity();
17277 matrix4.copy( light.matrixWorld );
17278 matrix4.premultiply( viewMatrix );
17279 matrix42.extractRotation( matrix4 );
17281 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
17282 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
17284 uniforms.halfWidth.applyMatrix4( matrix42 );
17285 uniforms.halfHeight.applyMatrix4( matrix42 );
17287 // TODO (abelnation): RectAreaLight distance?
17288 // uniforms.distance = distance;
17290 state.rectArea[ rectAreaLength ] = uniforms;
17294 } else if ( light.isPointLight ) {
17296 var uniforms = cache.get( light );
17298 uniforms.position.setFromMatrixPosition( light.matrixWorld );
17299 uniforms.position.applyMatrix4( viewMatrix );
17301 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
17302 uniforms.distance = light.distance;
17303 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
17305 uniforms.shadow = light.castShadow;
17307 if ( light.castShadow ) {
17309 var shadow = light.shadow;
17311 uniforms.shadowBias = shadow.bias;
17312 uniforms.shadowRadius = shadow.radius;
17313 uniforms.shadowMapSize = shadow.mapSize;
17314 uniforms.shadowCameraNear = shadow.camera.near;
17315 uniforms.shadowCameraFar = shadow.camera.far;
17319 state.pointShadowMap[ pointLength ] = shadowMap;
17320 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
17321 state.point[ pointLength ] = uniforms;
17325 } else if ( light.isHemisphereLight ) {
17327 var uniforms = cache.get( light );
17329 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
17330 uniforms.direction.transformDirection( viewMatrix );
17331 uniforms.direction.normalize();
17333 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
17334 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
17336 state.hemi[ hemiLength ] = uniforms;
17344 state.ambient[ 0 ] = r;
17345 state.ambient[ 1 ] = g;
17346 state.ambient[ 2 ] = b;
17348 state.directional.length = directionalLength;
17349 state.spot.length = spotLength;
17350 state.rectArea.length = rectAreaLength;
17351 state.point.length = pointLength;
17352 state.hemi.length = hemiLength;
17354 // TODO (sam-g-steel) why aren't we using join
17355 state.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length;
17367 * @author mrdoob / http://mrdoob.com/
17370 function WebGLObjects( geometries, infoRender ) {
17372 var updateList = {};
17374 function update( object ) {
17376 var frame = infoRender.frame;
17378 var geometry = object.geometry;
17379 var buffergeometry = geometries.get( object, geometry );
17381 // Update once per frame
17383 if ( updateList[ buffergeometry.id ] !== frame ) {
17385 if ( geometry.isGeometry ) {
17387 buffergeometry.updateFromObject( object );
17391 geometries.update( buffergeometry );
17393 updateList[ buffergeometry.id ] = frame;
17397 return buffergeometry;
17417 * @author mrdoob / http://mrdoob.com/
17420 function addLineNumbers( string ) {
17422 var lines = string.split( '\n' );
17424 for ( var i = 0; i < lines.length; i ++ ) {
17426 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
17430 return lines.join( '\n' );
17434 function WebGLShader( gl, type, string ) {
17436 var shader = gl.createShader( type );
17438 gl.shaderSource( shader, string );
17439 gl.compileShader( shader );
17441 if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
17443 console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
17447 if ( gl.getShaderInfoLog( shader ) !== '' ) {
17449 console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );
17453 // --enable-privileged-webgl-extension
17454 // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
17461 * @author mrdoob / http://mrdoob.com/
17464 var programIdCount = 0;
17466 function getEncodingComponents( encoding ) {
17468 switch ( encoding ) {
17470 case LinearEncoding:
17471 return [ 'Linear','( value )' ];
17473 return [ 'sRGB','( value )' ];
17475 return [ 'RGBE','( value )' ];
17476 case RGBM7Encoding:
17477 return [ 'RGBM','( value, 7.0 )' ];
17478 case RGBM16Encoding:
17479 return [ 'RGBM','( value, 16.0 )' ];
17481 return [ 'RGBD','( value, 256.0 )' ];
17482 case GammaEncoding:
17483 return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ];
17485 throw new Error( 'unsupported encoding: ' + encoding );
17491 function getTexelDecodingFunction( functionName, encoding ) {
17493 var components = getEncodingComponents( encoding );
17494 return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }";
17498 function getTexelEncodingFunction( functionName, encoding ) {
17500 var components = getEncodingComponents( encoding );
17501 return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }";
17505 function getToneMappingFunction( functionName, toneMapping ) {
17507 var toneMappingName;
17509 switch ( toneMapping ) {
17511 case LinearToneMapping:
17512 toneMappingName = "Linear";
17515 case ReinhardToneMapping:
17516 toneMappingName = "Reinhard";
17519 case Uncharted2ToneMapping:
17520 toneMappingName = "Uncharted2";
17523 case CineonToneMapping:
17524 toneMappingName = "OptimizedCineon";
17528 throw new Error( 'unsupported toneMapping: ' + toneMapping );
17532 return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }";
17536 function generateExtensions( extensions, parameters, rendererExtensions ) {
17538 extensions = extensions || {};
17541 ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
17542 ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
17543 ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
17544 ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
17547 return chunks.filter( filterEmptyLine ).join( '\n' );
17551 function generateDefines( defines ) {
17555 for ( var name in defines ) {
17557 var value = defines[ name ];
17559 if ( value === false ) continue;
17561 chunks.push( '#define ' + name + ' ' + value );
17565 return chunks.join( '\n' );
17569 function fetchAttributeLocations( gl, program, identifiers ) {
17571 var attributes = {};
17573 var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
17575 for ( var i = 0; i < n; i ++ ) {
17577 var info = gl.getActiveAttrib( program, i );
17578 var name = info.name;
17580 // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i );
17582 attributes[ name ] = gl.getAttribLocation( program, name );
17590 function filterEmptyLine( string ) {
17592 return string !== '';
17596 function replaceLightNums( string, parameters ) {
17599 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
17600 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
17601 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
17602 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
17603 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
17607 function parseIncludes( string ) {
17609 var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;
17611 function replace( match, include ) {
17613 var replace = ShaderChunk[ include ];
17615 if ( replace === undefined ) {
17617 throw new Error( 'Can not resolve #include <' + include + '>' );
17621 return parseIncludes( replace );
17625 return string.replace( pattern, replace );
17629 function unrollLoops( string ) {
17631 var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
17633 function replace( match, start, end, snippet ) {
17637 for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
17639 unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
17647 return string.replace( pattern, replace );
17651 function WebGLProgram( renderer, extensions, code, material, shader, parameters ) {
17653 var gl = renderer.context;
17655 var defines = material.defines;
17657 var vertexShader = shader.vertexShader;
17658 var fragmentShader = shader.fragmentShader;
17660 var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
17662 if ( parameters.shadowMapType === PCFShadowMap ) {
17664 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
17666 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
17668 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
17672 var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
17673 var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
17674 var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
17676 if ( parameters.envMap ) {
17678 switch ( material.envMap.mapping ) {
17680 case CubeReflectionMapping:
17681 case CubeRefractionMapping:
17682 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
17685 case CubeUVReflectionMapping:
17686 case CubeUVRefractionMapping:
17687 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
17690 case EquirectangularReflectionMapping:
17691 case EquirectangularRefractionMapping:
17692 envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
17695 case SphericalReflectionMapping:
17696 envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
17701 switch ( material.envMap.mapping ) {
17703 case CubeRefractionMapping:
17704 case EquirectangularRefractionMapping:
17705 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
17710 switch ( material.combine ) {
17712 case MultiplyOperation:
17713 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
17717 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
17721 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
17728 var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
17730 // console.log( 'building new program ' );
17734 var customExtensions = generateExtensions( material.extensions, parameters, extensions );
17736 var customDefines = generateDefines( defines );
17740 var program = gl.createProgram();
17742 var prefixVertex, prefixFragment;
17744 if ( material.isRawShaderMaterial ) {
17752 ].filter( filterEmptyLine ).join( '\n' );
17761 ].filter( filterEmptyLine ).join( '\n' );
17767 'precision ' + parameters.precision + ' float;',
17768 'precision ' + parameters.precision + ' int;',
17770 '#define SHADER_NAME ' + shader.name,
17774 parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
17776 '#define GAMMA_FACTOR ' + gammaFactorDefine,
17778 '#define MAX_BONES ' + parameters.maxBones,
17779 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
17780 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
17782 parameters.map ? '#define USE_MAP' : '',
17783 parameters.envMap ? '#define USE_ENVMAP' : '',
17784 parameters.envMap ? '#define ' + envMapModeDefine : '',
17785 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
17786 parameters.aoMap ? '#define USE_AOMAP' : '',
17787 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
17788 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
17789 parameters.normalMap ? '#define USE_NORMALMAP' : '',
17790 parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
17791 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
17792 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
17793 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
17794 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
17795 parameters.vertexColors ? '#define USE_COLOR' : '',
17797 parameters.flatShading ? '#define FLAT_SHADED' : '',
17799 parameters.skinning ? '#define USE_SKINNING' : '',
17800 parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
17802 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
17803 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
17804 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
17805 parameters.flipSided ? '#define FLIP_SIDED' : '',
17807 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
17809 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
17810 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
17812 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
17814 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
17815 parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
17817 'uniform mat4 modelMatrix;',
17818 'uniform mat4 modelViewMatrix;',
17819 'uniform mat4 projectionMatrix;',
17820 'uniform mat4 viewMatrix;',
17821 'uniform mat3 normalMatrix;',
17822 'uniform vec3 cameraPosition;',
17824 'attribute vec3 position;',
17825 'attribute vec3 normal;',
17826 'attribute vec2 uv;',
17828 '#ifdef USE_COLOR',
17830 ' attribute vec3 color;',
17834 '#ifdef USE_MORPHTARGETS',
17836 ' attribute vec3 morphTarget0;',
17837 ' attribute vec3 morphTarget1;',
17838 ' attribute vec3 morphTarget2;',
17839 ' attribute vec3 morphTarget3;',
17841 ' #ifdef USE_MORPHNORMALS',
17843 ' attribute vec3 morphNormal0;',
17844 ' attribute vec3 morphNormal1;',
17845 ' attribute vec3 morphNormal2;',
17846 ' attribute vec3 morphNormal3;',
17850 ' attribute vec3 morphTarget4;',
17851 ' attribute vec3 morphTarget5;',
17852 ' attribute vec3 morphTarget6;',
17853 ' attribute vec3 morphTarget7;',
17859 '#ifdef USE_SKINNING',
17861 ' attribute vec4 skinIndex;',
17862 ' attribute vec4 skinWeight;',
17868 ].filter( filterEmptyLine ).join( '\n' );
17874 'precision ' + parameters.precision + ' float;',
17875 'precision ' + parameters.precision + ' int;',
17877 '#define SHADER_NAME ' + shader.name,
17881 parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',
17883 '#define GAMMA_FACTOR ' + gammaFactorDefine,
17885 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
17886 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
17888 parameters.map ? '#define USE_MAP' : '',
17889 parameters.envMap ? '#define USE_ENVMAP' : '',
17890 parameters.envMap ? '#define ' + envMapTypeDefine : '',
17891 parameters.envMap ? '#define ' + envMapModeDefine : '',
17892 parameters.envMap ? '#define ' + envMapBlendingDefine : '',
17893 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
17894 parameters.aoMap ? '#define USE_AOMAP' : '',
17895 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
17896 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
17897 parameters.normalMap ? '#define USE_NORMALMAP' : '',
17898 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
17899 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
17900 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
17901 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
17902 parameters.vertexColors ? '#define USE_COLOR' : '',
17904 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
17906 parameters.flatShading ? '#define FLAT_SHADED' : '',
17908 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
17909 parameters.flipSided ? '#define FLIP_SIDED' : '',
17911 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
17912 '#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),
17914 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
17915 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
17917 parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '',
17919 parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '',
17921 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
17922 parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
17924 parameters.envMap && extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',
17926 'uniform mat4 viewMatrix;',
17927 'uniform vec3 cameraPosition;',
17929 ( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '',
17930 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
17931 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '',
17933 parameters.dithering ? '#define DITHERING' : '',
17935 ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
17936 parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
17937 parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
17938 parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
17939 parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '',
17941 parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '',
17945 ].filter( filterEmptyLine ).join( '\n' );
17949 vertexShader = parseIncludes( vertexShader );
17950 vertexShader = replaceLightNums( vertexShader, parameters );
17952 fragmentShader = parseIncludes( fragmentShader );
17953 fragmentShader = replaceLightNums( fragmentShader, parameters );
17955 if ( ! material.isShaderMaterial ) {
17957 vertexShader = unrollLoops( vertexShader );
17958 fragmentShader = unrollLoops( fragmentShader );
17962 var vertexGlsl = prefixVertex + vertexShader;
17963 var fragmentGlsl = prefixFragment + fragmentShader;
17965 // console.log( '*VERTEX*', vertexGlsl );
17966 // console.log( '*FRAGMENT*', fragmentGlsl );
17968 var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
17969 var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
17971 gl.attachShader( program, glVertexShader );
17972 gl.attachShader( program, glFragmentShader );
17974 // Force a particular attribute to index 0.
17976 if ( material.index0AttributeName !== undefined ) {
17978 gl.bindAttribLocation( program, 0, material.index0AttributeName );
17980 } else if ( parameters.morphTargets === true ) {
17982 // programs with morphTargets displace position out of attribute 0
17983 gl.bindAttribLocation( program, 0, 'position' );
17987 gl.linkProgram( program );
17989 var programLog = gl.getProgramInfoLog( program );
17990 var vertexLog = gl.getShaderInfoLog( glVertexShader );
17991 var fragmentLog = gl.getShaderInfoLog( glFragmentShader );
17993 var runnable = true;
17994 var haveDiagnostics = true;
17996 // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
17997 // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
17999 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
18003 console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );
18005 } else if ( programLog !== '' ) {
18007 console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
18009 } else if ( vertexLog === '' || fragmentLog === '' ) {
18011 haveDiagnostics = false;
18015 if ( haveDiagnostics ) {
18017 this.diagnostics = {
18019 runnable: runnable,
18020 material: material,
18022 programLog: programLog,
18027 prefix: prefixVertex
18034 prefix: prefixFragment
18044 gl.deleteShader( glVertexShader );
18045 gl.deleteShader( glFragmentShader );
18047 // set up caching for uniform locations
18049 var cachedUniforms;
18051 this.getUniforms = function () {
18053 if ( cachedUniforms === undefined ) {
18055 cachedUniforms = new WebGLUniforms( gl, program, renderer );
18059 return cachedUniforms;
18063 // set up caching for attribute locations
18065 var cachedAttributes;
18067 this.getAttributes = function () {
18069 if ( cachedAttributes === undefined ) {
18071 cachedAttributes = fetchAttributeLocations( gl, program );
18075 return cachedAttributes;
18081 this.destroy = function() {
18083 gl.deleteProgram( program );
18084 this.program = undefined;
18090 Object.defineProperties( this, {
18095 console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
18096 return this.getUniforms();
18104 console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
18105 return this.getAttributes();
18115 this.id = programIdCount ++;
18117 this.usedTimes = 1;
18118 this.program = program;
18119 this.vertexShader = glVertexShader;
18120 this.fragmentShader = glFragmentShader;
18127 * @author mrdoob / http://mrdoob.com/
18130 function WebGLPrograms( renderer, extensions, capabilities ) {
18135 MeshDepthMaterial: 'depth',
18136 MeshDistanceMaterial: 'distanceRGBA',
18137 MeshNormalMaterial: 'normal',
18138 MeshBasicMaterial: 'basic',
18139 MeshLambertMaterial: 'lambert',
18140 MeshPhongMaterial: 'phong',
18141 MeshToonMaterial: 'phong',
18142 MeshStandardMaterial: 'physical',
18143 MeshPhysicalMaterial: 'physical',
18144 LineBasicMaterial: 'basic',
18145 LineDashedMaterial: 'dashed',
18146 PointsMaterial: 'points',
18147 ShadowMaterial: 'shadow'
18150 var parameterNames = [
18151 "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
18152 "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
18153 "roughnessMap", "metalnessMap", "gradientMap",
18154 "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
18155 "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
18156 "maxBones", "useVertexTexture", "morphTargets", "morphNormals",
18157 "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
18158 "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
18159 "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
18160 "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
18164 function allocateBones( object ) {
18166 var skeleton = object.skeleton;
18167 var bones = skeleton.bones;
18169 if ( capabilities.floatVertexTextures ) {
18175 // default for when object is not specified
18176 // ( for example when prebuilding shader to be used with multiple objects )
18178 // - leave some extra space for other uniforms
18179 // - limit here is ANGLE's 254 max uniform vectors
18180 // (up to 54 should be safe)
18182 var nVertexUniforms = capabilities.maxVertexUniforms;
18183 var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
18185 var maxBones = Math.min( nVertexMatrices, bones.length );
18187 if ( maxBones < bones.length ) {
18189 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
18200 function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
18206 encoding = LinearEncoding;
18208 } else if ( map.isTexture ) {
18210 encoding = map.encoding;
18212 } else if ( map.isWebGLRenderTarget ) {
18214 console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
18215 encoding = map.texture.encoding;
18219 // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
18220 if ( encoding === LinearEncoding && gammaOverrideLinear ) {
18222 encoding = GammaEncoding;
18230 this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) {
18232 var shaderID = shaderIDs[ material.type ];
18234 // heuristics to create shader parameters according to lights in the scene
18235 // (not to blow over maxLights budget)
18237 var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
18238 var precision = capabilities.precision;
18240 if ( material.precision !== null ) {
18242 precision = capabilities.getMaxPrecision( material.precision );
18244 if ( precision !== material.precision ) {
18246 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
18252 var currentRenderTarget = renderer.getRenderTarget();
18256 shaderID: shaderID,
18258 precision: precision,
18259 supportsVertexTextures: capabilities.vertexTextures,
18260 outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
18261 map: !! material.map,
18262 mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
18263 envMap: !! material.envMap,
18264 envMapMode: material.envMap && material.envMap.mapping,
18265 envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
18266 envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
18267 lightMap: !! material.lightMap,
18268 aoMap: !! material.aoMap,
18269 emissiveMap: !! material.emissiveMap,
18270 emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
18271 bumpMap: !! material.bumpMap,
18272 normalMap: !! material.normalMap,
18273 displacementMap: !! material.displacementMap,
18274 roughnessMap: !! material.roughnessMap,
18275 metalnessMap: !! material.metalnessMap,
18276 specularMap: !! material.specularMap,
18277 alphaMap: !! material.alphaMap,
18279 gradientMap: !! material.gradientMap,
18281 combine: material.combine,
18283 vertexColors: material.vertexColors,
18286 useFog: material.fog,
18287 fogExp: ( fog && fog.isFogExp2 ),
18289 flatShading: material.flatShading,
18291 sizeAttenuation: material.sizeAttenuation,
18292 logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
18294 skinning: material.skinning && maxBones > 0,
18295 maxBones: maxBones,
18296 useVertexTexture: capabilities.floatVertexTextures,
18298 morphTargets: material.morphTargets,
18299 morphNormals: material.morphNormals,
18300 maxMorphTargets: renderer.maxMorphTargets,
18301 maxMorphNormals: renderer.maxMorphNormals,
18303 numDirLights: lights.directional.length,
18304 numPointLights: lights.point.length,
18305 numSpotLights: lights.spot.length,
18306 numRectAreaLights: lights.rectArea.length,
18307 numHemiLights: lights.hemi.length,
18309 numClippingPlanes: nClipPlanes,
18310 numClipIntersection: nClipIntersection,
18312 dithering: material.dithering,
18314 shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,
18315 shadowMapType: renderer.shadowMap.type,
18317 toneMapping: renderer.toneMapping,
18318 physicallyCorrectLights: renderer.physicallyCorrectLights,
18320 premultipliedAlpha: material.premultipliedAlpha,
18322 alphaTest: material.alphaTest,
18323 doubleSided: material.side === DoubleSide,
18324 flipSided: material.side === BackSide,
18326 depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false
18334 this.getProgramCode = function ( material, parameters ) {
18338 if ( parameters.shaderID ) {
18340 array.push( parameters.shaderID );
18344 array.push( material.fragmentShader );
18345 array.push( material.vertexShader );
18349 if ( material.defines !== undefined ) {
18351 for ( var name in material.defines ) {
18353 array.push( name );
18354 array.push( material.defines[ name ] );
18360 for ( var i = 0; i < parameterNames.length; i ++ ) {
18362 array.push( parameters[ parameterNames[ i ] ] );
18366 array.push( material.onBeforeCompile.toString() );
18368 array.push( renderer.gammaOutput );
18370 return array.join();
18374 this.acquireProgram = function ( material, shader, parameters, code ) {
18378 // Check if code has been already compiled
18379 for ( var p = 0, pl = programs.length; p < pl; p ++ ) {
18381 var programInfo = programs[ p ];
18383 if ( programInfo.code === code ) {
18385 program = programInfo;
18386 ++ program.usedTimes;
18394 if ( program === undefined ) {
18396 program = new WebGLProgram( renderer, extensions, code, material, shader, parameters );
18397 programs.push( program );
18405 this.releaseProgram = function ( program ) {
18407 if ( -- program.usedTimes === 0 ) {
18409 // Remove from unordered set
18410 var i = programs.indexOf( program );
18411 programs[ i ] = programs[ programs.length - 1 ];
18414 // Free WebGL resources
18421 // Exposed for resource monitoring & error feedback via renderer.info:
18422 this.programs = programs;
18427 * @author mrdoob / http://mrdoob.com/
18430 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, infoMemory ) {
18432 var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );
18436 function clampToMaxSize( image, maxSize ) {
18438 if ( image.width > maxSize || image.height > maxSize ) {
18440 // Warning: Scaling through the canvas will only work with images that use
18441 // premultiplied alpha.
18443 var scale = maxSize / Math.max( image.width, image.height );
18445 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
18446 canvas.width = Math.floor( image.width * scale );
18447 canvas.height = Math.floor( image.height * scale );
18449 var context = canvas.getContext( '2d' );
18450 context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
18452 console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
18462 function isPowerOfTwo( image ) {
18464 return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
18468 function makePowerOfTwo( image ) {
18470 if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) {
18472 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
18473 canvas.width = _Math.nearestPowerOfTwo( image.width );
18474 canvas.height = _Math.nearestPowerOfTwo( image.height );
18476 var context = canvas.getContext( '2d' );
18477 context.drawImage( image, 0, 0, canvas.width, canvas.height );
18479 console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
18489 function textureNeedsPowerOfTwo( texture ) {
18491 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
18492 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
18496 function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {
18498 return texture.generateMipmaps && isPowerOfTwo &&
18499 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
18503 // Fallback filters for non-power-of-2 textures
18505 function filterFallback( f ) {
18507 if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
18509 return _gl.NEAREST;
18519 function onTextureDispose( event ) {
18521 var texture = event.target;
18523 texture.removeEventListener( 'dispose', onTextureDispose );
18525 deallocateTexture( texture );
18527 infoMemory.textures --;
18532 function onRenderTargetDispose( event ) {
18534 var renderTarget = event.target;
18536 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
18538 deallocateRenderTarget( renderTarget );
18540 infoMemory.textures --;
18546 function deallocateTexture( texture ) {
18548 var textureProperties = properties.get( texture );
18550 if ( texture.image && textureProperties.__image__webglTextureCube ) {
18554 _gl.deleteTexture( textureProperties.__image__webglTextureCube );
18560 if ( textureProperties.__webglInit === undefined ) return;
18562 _gl.deleteTexture( textureProperties.__webglTexture );
18566 // remove all webgl properties
18567 properties.remove( texture );
18571 function deallocateRenderTarget( renderTarget ) {
18573 var renderTargetProperties = properties.get( renderTarget );
18574 var textureProperties = properties.get( renderTarget.texture );
18576 if ( ! renderTarget ) return;
18578 if ( textureProperties.__webglTexture !== undefined ) {
18580 _gl.deleteTexture( textureProperties.__webglTexture );
18584 if ( renderTarget.depthTexture ) {
18586 renderTarget.depthTexture.dispose();
18590 if ( renderTarget.isWebGLRenderTargetCube ) {
18592 for ( var i = 0; i < 6; i ++ ) {
18594 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
18595 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
18601 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
18602 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
18606 properties.remove( renderTarget.texture );
18607 properties.remove( renderTarget );
18615 function setTexture2D( texture, slot ) {
18617 var textureProperties = properties.get( texture );
18619 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
18621 var image = texture.image;
18623 if ( image === undefined ) {
18625 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );
18627 } else if ( image.complete === false ) {
18629 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );
18633 uploadTexture( textureProperties, texture, slot );
18640 state.activeTexture( _gl.TEXTURE0 + slot );
18641 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
18645 function setTextureCube( texture, slot ) {
18647 var textureProperties = properties.get( texture );
18649 if ( texture.image.length === 6 ) {
18651 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
18653 if ( ! textureProperties.__image__webglTextureCube ) {
18655 texture.addEventListener( 'dispose', onTextureDispose );
18657 textureProperties.__image__webglTextureCube = _gl.createTexture();
18659 infoMemory.textures ++;
18663 state.activeTexture( _gl.TEXTURE0 + slot );
18664 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
18666 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
18668 var isCompressed = ( texture && texture.isCompressedTexture );
18669 var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
18671 var cubeImage = [];
18673 for ( var i = 0; i < 6; i ++ ) {
18675 if ( ! isCompressed && ! isDataTexture ) {
18677 cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
18681 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
18687 var image = cubeImage[ 0 ],
18688 isPowerOfTwoImage = isPowerOfTwo( image ),
18689 glFormat = utils.convert( texture.format ),
18690 glType = utils.convert( texture.type );
18692 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );
18694 for ( var i = 0; i < 6; i ++ ) {
18696 if ( ! isCompressed ) {
18698 if ( isDataTexture ) {
18700 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
18704 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
18710 var mipmap, mipmaps = cubeImage[ i ].mipmaps;
18712 for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
18714 mipmap = mipmaps[ j ];
18716 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
18718 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
18720 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
18724 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
18730 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
18740 if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
18742 _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
18746 textureProperties.__version = texture.version;
18748 if ( texture.onUpdate ) texture.onUpdate( texture );
18752 state.activeTexture( _gl.TEXTURE0 + slot );
18753 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
18761 function setTextureCubeDynamic( texture, slot ) {
18763 state.activeTexture( _gl.TEXTURE0 + slot );
18764 state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );
18768 function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {
18772 if ( isPowerOfTwoImage ) {
18774 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );
18775 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );
18777 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );
18778 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) );
18782 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
18783 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
18785 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
18787 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );
18791 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
18792 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
18794 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
18796 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );
18802 extension = extensions.get( 'EXT_texture_filter_anisotropic' );
18806 if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
18807 if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;
18809 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
18811 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
18812 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
18820 function uploadTexture( textureProperties, texture, slot ) {
18822 if ( textureProperties.__webglInit === undefined ) {
18824 textureProperties.__webglInit = true;
18826 texture.addEventListener( 'dispose', onTextureDispose );
18828 textureProperties.__webglTexture = _gl.createTexture();
18830 infoMemory.textures ++;
18834 state.activeTexture( _gl.TEXTURE0 + slot );
18835 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
18837 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
18838 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
18839 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
18841 var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
18843 if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
18845 image = makePowerOfTwo( image );
18849 var isPowerOfTwoImage = isPowerOfTwo( image ),
18850 glFormat = utils.convert( texture.format ),
18851 glType = utils.convert( texture.type );
18853 setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );
18855 var mipmap, mipmaps = texture.mipmaps;
18857 if ( texture.isDepthTexture ) {
18859 // populate depth texture with dummy data
18861 var internalFormat = _gl.DEPTH_COMPONENT;
18863 if ( texture.type === FloatType ) {
18865 if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0');
18866 internalFormat = _gl.DEPTH_COMPONENT32F;
18868 } else if ( _isWebGL2 ) {
18870 // WebGL 2.0 requires signed internalformat for glTexImage2D
18871 internalFormat = _gl.DEPTH_COMPONENT16;
18875 if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {
18877 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
18878 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
18879 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
18880 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
18882 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
18884 texture.type = UnsignedShortType;
18885 glType = utils.convert( texture.type );
18891 // Depth stencil textures need the DEPTH_STENCIL internal format
18892 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
18893 if ( texture.format === DepthStencilFormat ) {
18895 internalFormat = _gl.DEPTH_STENCIL;
18897 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
18898 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
18899 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
18900 if ( texture.type !== UnsignedInt248Type ) {
18902 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
18904 texture.type = UnsignedInt248Type;
18905 glType = utils.convert( texture.type );
18911 state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );
18913 } else if ( texture.isDataTexture ) {
18915 // use manually created mipmaps if available
18916 // if there are no manual mipmaps
18917 // set 0 level mipmap and then use GL to generate other mipmap levels
18919 if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
18921 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
18923 mipmap = mipmaps[ i ];
18924 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
18928 texture.generateMipmaps = false;
18932 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
18936 } else if ( texture.isCompressedTexture ) {
18938 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
18940 mipmap = mipmaps[ i ];
18942 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
18944 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
18946 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
18950 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
18956 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
18964 // regular Texture (image, video, canvas)
18966 // use manually created mipmaps if available
18967 // if there are no manual mipmaps
18968 // set 0 level mipmap and then use GL to generate other mipmap levels
18970 if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
18972 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
18974 mipmap = mipmaps[ i ];
18975 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
18979 texture.generateMipmaps = false;
18983 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );
18989 if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D );
18991 textureProperties.__version = texture.version;
18993 if ( texture.onUpdate ) texture.onUpdate( texture );
18999 // Setup storage for target texture and bind it to correct framebuffer
19000 function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
19002 var glFormat = utils.convert( renderTarget.texture.format );
19003 var glType = utils.convert( renderTarget.texture.type );
19004 state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
19005 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
19006 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
19007 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
19011 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
19012 function setupRenderBufferStorage( renderbuffer, renderTarget ) {
19014 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
19016 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
19018 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
19019 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
19021 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
19023 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
19024 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
19028 // FIXME: We don't support !depth !stencil
19029 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
19033 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
19037 // Setup resources for a Depth Texture for a FBO (needs an extension)
19038 function setupDepthTexture( framebuffer, renderTarget ) {
19040 var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
19041 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
19043 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
19045 if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
19047 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
19051 // upload an empty depth texture with framebuffer size
19052 if ( !properties.get( renderTarget.depthTexture ).__webglTexture ||
19053 renderTarget.depthTexture.image.width !== renderTarget.width ||
19054 renderTarget.depthTexture.image.height !== renderTarget.height ) {
19055 renderTarget.depthTexture.image.width = renderTarget.width;
19056 renderTarget.depthTexture.image.height = renderTarget.height;
19057 renderTarget.depthTexture.needsUpdate = true;
19060 setTexture2D( renderTarget.depthTexture, 0 );
19062 var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
19064 if ( renderTarget.depthTexture.format === DepthFormat ) {
19066 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
19068 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
19070 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
19074 throw new Error( 'Unknown depthTexture format' );
19080 // Setup GL resources for a non-texture depth buffer
19081 function setupDepthRenderbuffer( renderTarget ) {
19083 var renderTargetProperties = properties.get( renderTarget );
19085 var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
19087 if ( renderTarget.depthTexture ) {
19089 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
19091 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
19097 renderTargetProperties.__webglDepthbuffer = [];
19099 for ( var i = 0; i < 6; i ++ ) {
19101 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
19102 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
19103 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );
19109 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
19110 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
19111 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );
19117 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
19121 // Set up GL resources for the render target
19122 function setupRenderTarget( renderTarget ) {
19124 var renderTargetProperties = properties.get( renderTarget );
19125 var textureProperties = properties.get( renderTarget.texture );
19127 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
19129 textureProperties.__webglTexture = _gl.createTexture();
19131 infoMemory.textures ++;
19133 var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
19134 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
19136 // Setup framebuffer
19140 renderTargetProperties.__webglFramebuffer = [];
19142 for ( var i = 0; i < 6; i ++ ) {
19144 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
19150 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
19154 // Setup color buffer
19158 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
19159 setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
19161 for ( var i = 0; i < 6; i ++ ) {
19163 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
19167 if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
19168 state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
19172 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
19173 setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
19174 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
19176 if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D );
19177 state.bindTexture( _gl.TEXTURE_2D, null );
19181 // Setup depth and stencil buffers
19183 if ( renderTarget.depthBuffer ) {
19185 setupDepthRenderbuffer( renderTarget );
19191 function updateRenderTargetMipmap( renderTarget ) {
19193 var texture = renderTarget.texture;
19194 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
19196 if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {
19198 var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
19199 var webglTexture = properties.get( texture ).__webglTexture;
19201 state.bindTexture( target, webglTexture );
19202 _gl.generateMipmap( target );
19203 state.bindTexture( target, null );
19209 this.setTexture2D = setTexture2D;
19210 this.setTextureCube = setTextureCube;
19211 this.setTextureCubeDynamic = setTextureCubeDynamic;
19212 this.setupRenderTarget = setupRenderTarget;
19213 this.updateRenderTargetMipmap = updateRenderTargetMipmap;
19218 * @author fordacious / fordacious.github.io
19221 function WebGLProperties() {
19223 var properties = {};
19225 function get( object ) {
19227 var uuid = object.uuid;
19228 var map = properties[ uuid ];
19230 if ( map === undefined ) {
19233 properties[ uuid ] = map;
19241 function remove( object ) {
19243 delete properties[ object.uuid ];
19262 * @author mrdoob / http://mrdoob.com/
19265 function WebGLState( gl, extensions, utils ) {
19267 function ColorBuffer() {
19269 var locked = false;
19271 var color = new Vector4();
19272 var currentColorMask = null;
19273 var currentColorClear = new Vector4( 0, 0, 0, 0 );
19277 setMask: function ( colorMask ) {
19279 if ( currentColorMask !== colorMask && ! locked ) {
19281 gl.colorMask( colorMask, colorMask, colorMask, colorMask );
19282 currentColorMask = colorMask;
19288 setLocked: function ( lock ) {
19294 setClear: function ( r, g, b, a, premultipliedAlpha ) {
19296 if ( premultipliedAlpha === true ) {
19298 r *= a; g *= a; b *= a;
19302 color.set( r, g, b, a );
19304 if ( currentColorClear.equals( color ) === false ) {
19306 gl.clearColor( r, g, b, a );
19307 currentColorClear.copy( color );
19313 reset: function () {
19317 currentColorMask = null;
19318 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
19326 function DepthBuffer() {
19328 var locked = false;
19330 var currentDepthMask = null;
19331 var currentDepthFunc = null;
19332 var currentDepthClear = null;
19336 setTest: function ( depthTest ) {
19340 enable( gl.DEPTH_TEST );
19344 disable( gl.DEPTH_TEST );
19350 setMask: function ( depthMask ) {
19352 if ( currentDepthMask !== depthMask && ! locked ) {
19354 gl.depthMask( depthMask );
19355 currentDepthMask = depthMask;
19361 setFunc: function ( depthFunc ) {
19363 if ( currentDepthFunc !== depthFunc ) {
19367 switch ( depthFunc ) {
19371 gl.depthFunc( gl.NEVER );
19376 gl.depthFunc( gl.ALWAYS );
19381 gl.depthFunc( gl.LESS );
19384 case LessEqualDepth:
19386 gl.depthFunc( gl.LEQUAL );
19391 gl.depthFunc( gl.EQUAL );
19394 case GreaterEqualDepth:
19396 gl.depthFunc( gl.GEQUAL );
19401 gl.depthFunc( gl.GREATER );
19404 case NotEqualDepth:
19406 gl.depthFunc( gl.NOTEQUAL );
19411 gl.depthFunc( gl.LEQUAL );
19417 gl.depthFunc( gl.LEQUAL );
19421 currentDepthFunc = depthFunc;
19427 setLocked: function ( lock ) {
19433 setClear: function ( depth ) {
19435 if ( currentDepthClear !== depth ) {
19437 gl.clearDepth( depth );
19438 currentDepthClear = depth;
19444 reset: function () {
19448 currentDepthMask = null;
19449 currentDepthFunc = null;
19450 currentDepthClear = null;
19458 function StencilBuffer() {
19460 var locked = false;
19462 var currentStencilMask = null;
19463 var currentStencilFunc = null;
19464 var currentStencilRef = null;
19465 var currentStencilFuncMask = null;
19466 var currentStencilFail = null;
19467 var currentStencilZFail = null;
19468 var currentStencilZPass = null;
19469 var currentStencilClear = null;
19473 setTest: function ( stencilTest ) {
19475 if ( stencilTest ) {
19477 enable( gl.STENCIL_TEST );
19481 disable( gl.STENCIL_TEST );
19487 setMask: function ( stencilMask ) {
19489 if ( currentStencilMask !== stencilMask && ! locked ) {
19491 gl.stencilMask( stencilMask );
19492 currentStencilMask = stencilMask;
19498 setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
19500 if ( currentStencilFunc !== stencilFunc ||
19501 currentStencilRef !== stencilRef ||
19502 currentStencilFuncMask !== stencilMask ) {
19504 gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
19506 currentStencilFunc = stencilFunc;
19507 currentStencilRef = stencilRef;
19508 currentStencilFuncMask = stencilMask;
19514 setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
19516 if ( currentStencilFail !== stencilFail ||
19517 currentStencilZFail !== stencilZFail ||
19518 currentStencilZPass !== stencilZPass ) {
19520 gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
19522 currentStencilFail = stencilFail;
19523 currentStencilZFail = stencilZFail;
19524 currentStencilZPass = stencilZPass;
19530 setLocked: function ( lock ) {
19536 setClear: function ( stencil ) {
19538 if ( currentStencilClear !== stencil ) {
19540 gl.clearStencil( stencil );
19541 currentStencilClear = stencil;
19547 reset: function () {
19551 currentStencilMask = null;
19552 currentStencilFunc = null;
19553 currentStencilRef = null;
19554 currentStencilFuncMask = null;
19555 currentStencilFail = null;
19556 currentStencilZFail = null;
19557 currentStencilZPass = null;
19558 currentStencilClear = null;
19568 var colorBuffer = new ColorBuffer();
19569 var depthBuffer = new DepthBuffer();
19570 var stencilBuffer = new StencilBuffer();
19572 var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
19573 var newAttributes = new Uint8Array( maxVertexAttributes );
19574 var enabledAttributes = new Uint8Array( maxVertexAttributes );
19575 var attributeDivisors = new Uint8Array( maxVertexAttributes );
19577 var capabilities = {};
19579 var compressedTextureFormats = null;
19581 var currentProgram = null;
19583 var currentBlending = null;
19584 var currentBlendEquation = null;
19585 var currentBlendSrc = null;
19586 var currentBlendDst = null;
19587 var currentBlendEquationAlpha = null;
19588 var currentBlendSrcAlpha = null;
19589 var currentBlendDstAlpha = null;
19590 var currentPremultipledAlpha = false;
19592 var currentFlipSided = null;
19593 var currentCullFace = null;
19595 var currentLineWidth = null;
19597 var currentPolygonOffsetFactor = null;
19598 var currentPolygonOffsetUnits = null;
19600 var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
19602 var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );
19603 var lineWidthAvailable = parseFloat( version ) >= 1.0;
19605 var currentTextureSlot = null;
19606 var currentBoundTextures = {};
19608 var currentScissor = new Vector4();
19609 var currentViewport = new Vector4();
19611 function createTexture( type, target, count ) {
19613 var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
19614 var texture = gl.createTexture();
19616 gl.bindTexture( type, texture );
19617 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
19618 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
19620 for ( var i = 0; i < count; i ++ ) {
19622 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
19630 var emptyTextures = {};
19631 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
19632 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
19636 colorBuffer.setClear( 0, 0, 0, 1 );
19637 depthBuffer.setClear( 1 );
19638 stencilBuffer.setClear( 0 );
19640 enable( gl.DEPTH_TEST );
19641 depthBuffer.setFunc( LessEqualDepth );
19643 setFlipSided( false );
19644 setCullFace( CullFaceBack );
19645 enable( gl.CULL_FACE );
19647 enable( gl.BLEND );
19648 setBlending( NormalBlending );
19652 function initAttributes() {
19654 for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {
19656 newAttributes[ i ] = 0;
19662 function enableAttribute( attribute ) {
19664 newAttributes[ attribute ] = 1;
19666 if ( enabledAttributes[ attribute ] === 0 ) {
19668 gl.enableVertexAttribArray( attribute );
19669 enabledAttributes[ attribute ] = 1;
19673 if ( attributeDivisors[ attribute ] !== 0 ) {
19675 var extension = extensions.get( 'ANGLE_instanced_arrays' );
19677 extension.vertexAttribDivisorANGLE( attribute, 0 );
19678 attributeDivisors[ attribute ] = 0;
19684 function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
19686 newAttributes[ attribute ] = 1;
19688 if ( enabledAttributes[ attribute ] === 0 ) {
19690 gl.enableVertexAttribArray( attribute );
19691 enabledAttributes[ attribute ] = 1;
19695 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
19697 var extension = extensions.get( 'ANGLE_instanced_arrays' );
19699 extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );
19700 attributeDivisors[ attribute ] = meshPerAttribute;
19706 function disableUnusedAttributes() {
19708 for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {
19710 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
19712 gl.disableVertexAttribArray( i );
19713 enabledAttributes[ i ] = 0;
19721 function enable( id ) {
19723 if ( capabilities[ id ] !== true ) {
19726 capabilities[ id ] = true;
19732 function disable( id ) {
19734 if ( capabilities[ id ] !== false ) {
19737 capabilities[ id ] = false;
19743 function getCompressedTextureFormats() {
19745 if ( compressedTextureFormats === null ) {
19747 compressedTextureFormats = [];
19749 if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
19750 extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
19751 extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {
19753 var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );
19755 for ( var i = 0; i < formats.length; i ++ ) {
19757 compressedTextureFormats.push( formats[ i ] );
19765 return compressedTextureFormats;
19769 function useProgram( program ) {
19771 if ( currentProgram !== program ) {
19773 gl.useProgram( program );
19775 currentProgram = program;
19785 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
19787 if ( blending !== NoBlending ) {
19789 enable( gl.BLEND );
19793 disable( gl.BLEND );
19797 if ( blending !== CustomBlending ) {
19799 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
19801 switch ( blending ) {
19803 case AdditiveBlending:
19805 if ( premultipliedAlpha ) {
19807 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
19808 gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );
19812 gl.blendEquation( gl.FUNC_ADD );
19813 gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
19818 case SubtractiveBlending:
19820 if ( premultipliedAlpha ) {
19822 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
19823 gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
19827 gl.blendEquation( gl.FUNC_ADD );
19828 gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
19833 case MultiplyBlending:
19835 if ( premultipliedAlpha ) {
19837 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
19838 gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
19842 gl.blendEquation( gl.FUNC_ADD );
19843 gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
19850 if ( premultipliedAlpha ) {
19852 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
19853 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
19857 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
19858 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
19866 currentBlendEquation = null;
19867 currentBlendSrc = null;
19868 currentBlendDst = null;
19869 currentBlendEquationAlpha = null;
19870 currentBlendSrcAlpha = null;
19871 currentBlendDstAlpha = null;
19875 blendEquationAlpha = blendEquationAlpha || blendEquation;
19876 blendSrcAlpha = blendSrcAlpha || blendSrc;
19877 blendDstAlpha = blendDstAlpha || blendDst;
19879 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
19881 gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );
19883 currentBlendEquation = blendEquation;
19884 currentBlendEquationAlpha = blendEquationAlpha;
19888 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
19890 gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );
19892 currentBlendSrc = blendSrc;
19893 currentBlendDst = blendDst;
19894 currentBlendSrcAlpha = blendSrcAlpha;
19895 currentBlendDstAlpha = blendDstAlpha;
19901 currentBlending = blending;
19902 currentPremultipledAlpha = premultipliedAlpha;
19906 function setMaterial( material ) {
19908 material.side === DoubleSide
19909 ? disable( gl.CULL_FACE )
19910 : enable( gl.CULL_FACE );
19912 setFlipSided( material.side === BackSide );
19914 material.transparent === true
19915 ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
19916 : setBlending( NoBlending );
19918 depthBuffer.setFunc( material.depthFunc );
19919 depthBuffer.setTest( material.depthTest );
19920 depthBuffer.setMask( material.depthWrite );
19921 colorBuffer.setMask( material.colorWrite );
19923 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
19929 function setFlipSided( flipSided ) {
19931 if ( currentFlipSided !== flipSided ) {
19935 gl.frontFace( gl.CW );
19939 gl.frontFace( gl.CCW );
19943 currentFlipSided = flipSided;
19949 function setCullFace( cullFace ) {
19951 if ( cullFace !== CullFaceNone ) {
19953 enable( gl.CULL_FACE );
19955 if ( cullFace !== currentCullFace ) {
19957 if ( cullFace === CullFaceBack ) {
19959 gl.cullFace( gl.BACK );
19961 } else if ( cullFace === CullFaceFront ) {
19963 gl.cullFace( gl.FRONT );
19967 gl.cullFace( gl.FRONT_AND_BACK );
19975 disable( gl.CULL_FACE );
19979 currentCullFace = cullFace;
19983 function setLineWidth( width ) {
19985 if ( width !== currentLineWidth ) {
19987 if ( lineWidthAvailable ) gl.lineWidth( width );
19989 currentLineWidth = width;
19995 function setPolygonOffset( polygonOffset, factor, units ) {
19997 if ( polygonOffset ) {
19999 enable( gl.POLYGON_OFFSET_FILL );
20001 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
20003 gl.polygonOffset( factor, units );
20005 currentPolygonOffsetFactor = factor;
20006 currentPolygonOffsetUnits = units;
20012 disable( gl.POLYGON_OFFSET_FILL );
20018 function setScissorTest( scissorTest ) {
20020 if ( scissorTest ) {
20022 enable( gl.SCISSOR_TEST );
20026 disable( gl.SCISSOR_TEST );
20034 function activeTexture( webglSlot ) {
20036 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
20038 if ( currentTextureSlot !== webglSlot ) {
20040 gl.activeTexture( webglSlot );
20041 currentTextureSlot = webglSlot;
20047 function bindTexture( webglType, webglTexture ) {
20049 if ( currentTextureSlot === null ) {
20055 var boundTexture = currentBoundTextures[ currentTextureSlot ];
20057 if ( boundTexture === undefined ) {
20059 boundTexture = { type: undefined, texture: undefined };
20060 currentBoundTextures[ currentTextureSlot ] = boundTexture;
20064 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
20066 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
20068 boundTexture.type = webglType;
20069 boundTexture.texture = webglTexture;
20075 function compressedTexImage2D() {
20079 gl.compressedTexImage2D.apply( gl, arguments );
20081 } catch ( error ) {
20083 console.error( 'THREE.WebGLState:', error );
20089 function texImage2D() {
20093 gl.texImage2D.apply( gl, arguments );
20095 } catch ( error ) {
20097 console.error( 'THREE.WebGLState:', error );
20105 function scissor( scissor ) {
20107 if ( currentScissor.equals( scissor ) === false ) {
20109 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
20110 currentScissor.copy( scissor );
20116 function viewport( viewport ) {
20118 if ( currentViewport.equals( viewport ) === false ) {
20120 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
20121 currentViewport.copy( viewport );
20131 for ( var i = 0; i < enabledAttributes.length; i ++ ) {
20133 if ( enabledAttributes[ i ] === 1 ) {
20135 gl.disableVertexAttribArray( i );
20136 enabledAttributes[ i ] = 0;
20144 compressedTextureFormats = null;
20146 currentTextureSlot = null;
20147 currentBoundTextures = {};
20149 currentProgram = null;
20151 currentBlending = null;
20153 currentFlipSided = null;
20154 currentCullFace = null;
20156 colorBuffer.reset();
20157 depthBuffer.reset();
20158 stencilBuffer.reset();
20165 color: colorBuffer,
20166 depth: depthBuffer,
20167 stencil: stencilBuffer
20170 initAttributes: initAttributes,
20171 enableAttribute: enableAttribute,
20172 enableAttributeAndDivisor: enableAttributeAndDivisor,
20173 disableUnusedAttributes: disableUnusedAttributes,
20176 getCompressedTextureFormats: getCompressedTextureFormats,
20178 useProgram: useProgram,
20180 setBlending: setBlending,
20181 setMaterial: setMaterial,
20183 setFlipSided: setFlipSided,
20184 setCullFace: setCullFace,
20186 setLineWidth: setLineWidth,
20187 setPolygonOffset: setPolygonOffset,
20189 setScissorTest: setScissorTest,
20191 activeTexture: activeTexture,
20192 bindTexture: bindTexture,
20193 compressedTexImage2D: compressedTexImage2D,
20194 texImage2D: texImage2D,
20197 viewport: viewport,
20206 * @author mrdoob / http://mrdoob.com/
20209 function WebGLCapabilities( gl, extensions, parameters ) {
20213 function getMaxAnisotropy() {
20215 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
20217 var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
20219 if ( extension !== null ) {
20221 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
20229 return maxAnisotropy;
20233 function getMaxPrecision( precision ) {
20235 if ( precision === 'highp' ) {
20237 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
20238 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
20244 precision = 'mediump';
20248 if ( precision === 'mediump' ) {
20250 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
20251 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
20263 var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
20264 var maxPrecision = getMaxPrecision( precision );
20266 if ( maxPrecision !== precision ) {
20268 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
20269 precision = maxPrecision;
20273 var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' );
20275 var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
20276 var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
20277 var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
20278 var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
20280 var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
20281 var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
20282 var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
20283 var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
20285 var vertexTextures = maxVertexTextures > 0;
20286 var floatFragmentTextures = !! extensions.get( 'OES_texture_float' );
20287 var floatVertexTextures = vertexTextures && floatFragmentTextures;
20291 getMaxAnisotropy: getMaxAnisotropy,
20292 getMaxPrecision: getMaxPrecision,
20294 precision: precision,
20295 logarithmicDepthBuffer: logarithmicDepthBuffer,
20297 maxTextures: maxTextures,
20298 maxVertexTextures: maxVertexTextures,
20299 maxTextureSize: maxTextureSize,
20300 maxCubemapSize: maxCubemapSize,
20302 maxAttributes: maxAttributes,
20303 maxVertexUniforms: maxVertexUniforms,
20304 maxVaryings: maxVaryings,
20305 maxFragmentUniforms: maxFragmentUniforms,
20307 vertexTextures: vertexTextures,
20308 floatFragmentTextures: floatFragmentTextures,
20309 floatVertexTextures: floatVertexTextures
20316 * @author mrdoob / http://mrdoob.com/
20319 function ArrayCamera( array ) {
20321 PerspectiveCamera.call( this );
20323 this.cameras = array || [];
20327 ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
20329 constructor: ArrayCamera,
20331 isArrayCamera: true
20336 * @author mrdoob / http://mrdoob.com/
20339 function WebVRManager( renderer ) {
20344 var frameData = null;
20346 if ( 'VRFrameData' in window ) {
20348 frameData = new window.VRFrameData();
20352 var matrixWorldInverse = new Matrix4();
20354 var standingMatrix = new Matrix4();
20355 var standingMatrixInverse = new Matrix4();
20357 var cameraL = new PerspectiveCamera();
20358 cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );
20359 cameraL.layers.enable( 1 );
20361 var cameraR = new PerspectiveCamera();
20362 cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );
20363 cameraR.layers.enable( 2 );
20365 var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
20366 cameraVR.layers.enable( 1 );
20367 cameraVR.layers.enable( 2 );
20371 var currentSize, currentPixelRatio;
20373 function onVRDisplayPresentChange() {
20375 if ( device !== null && device.isPresenting ) {
20377 var eyeParameters = device.getEyeParameters( 'left' );
20378 var renderWidth = eyeParameters.renderWidth;
20379 var renderHeight = eyeParameters.renderHeight;
20381 currentPixelRatio = renderer.getPixelRatio();
20382 currentSize = renderer.getSize();
20384 renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );
20386 } else if ( scope.enabled ) {
20388 renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );
20394 window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
20398 this.enabled = false;
20399 this.standing = false;
20401 this.getDevice = function () {
20407 this.setDevice = function ( value ) {
20409 if ( value !== undefined ) device = value;
20413 this.getCamera = function ( camera ) {
20415 if ( device === null ) return camera;
20417 device.depthNear = camera.near;
20418 device.depthFar = camera.far;
20420 device.getFrameData( frameData );
20424 var pose = frameData.pose;
20426 if ( pose.position !== null ) {
20428 camera.position.fromArray( pose.position );
20432 camera.position.set( 0, 0, 0 );
20436 if ( pose.orientation !== null ) {
20438 camera.quaternion.fromArray( pose.orientation );
20442 camera.updateMatrixWorld();
20444 var stageParameters = device.stageParameters;
20446 if ( this.standing && stageParameters ) {
20448 standingMatrix.fromArray( stageParameters.sittingToStandingTransform );
20449 standingMatrixInverse.getInverse( standingMatrix );
20451 camera.matrixWorld.multiply( standingMatrix );
20452 camera.matrixWorldInverse.multiply( standingMatrixInverse );
20456 if ( device.isPresenting === false ) return camera;
20460 cameraL.near = camera.near;
20461 cameraR.near = camera.near;
20463 cameraL.far = camera.far;
20464 cameraR.far = camera.far;
20466 cameraVR.matrixWorld.copy( camera.matrixWorld );
20467 cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
20469 cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
20470 cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
20472 if ( this.standing && stageParameters ) {
20474 cameraL.matrixWorldInverse.multiply( standingMatrixInverse );
20475 cameraR.matrixWorldInverse.multiply( standingMatrixInverse );
20479 var parent = camera.parent;
20481 if ( parent !== null ) {
20483 matrixWorldInverse.getInverse( parent.matrixWorld );
20485 cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
20486 cameraR.matrixWorldInverse.multiply( matrixWorldInverse );
20490 // envMap and Mirror needs camera.matrixWorld
20492 cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );
20493 cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );
20495 cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
20496 cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
20499 // https://github.com/w3c/webvr/issues/203
20501 cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
20505 var layers = device.getLayers();
20507 if ( layers.length ) {
20509 var layer = layers[ 0 ];
20511 if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
20513 cameraL.bounds.fromArray( layer.leftBounds );
20517 if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
20519 cameraR.bounds.fromArray( layer.rightBounds );
20529 this.getStandingMatrix = function () {
20531 return standingMatrix;
20535 this.submitFrame = function () {
20537 if ( device && device.isPresenting ) device.submitFrame();
20541 this.dispose = function() {
20543 window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange );
20550 * @author mrdoob / http://mrdoob.com/
20553 function WebGLExtensions( gl ) {
20555 var extensions = {};
20559 get: function ( name ) {
20561 if ( extensions[ name ] !== undefined ) {
20563 return extensions[ name ];
20571 case 'WEBGL_depth_texture':
20572 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
20575 case 'EXT_texture_filter_anisotropic':
20576 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
20579 case 'WEBGL_compressed_texture_s3tc':
20580 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
20583 case 'WEBGL_compressed_texture_pvrtc':
20584 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
20587 case 'WEBGL_compressed_texture_etc1':
20588 extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );
20592 extension = gl.getExtension( name );
20596 if ( extension === null ) {
20598 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
20602 extensions[ name ] = extension;
20616 function WebGLClipping() {
20620 globalState = null,
20621 numGlobalPlanes = 0,
20622 localClippingEnabled = false,
20623 renderingShadows = false,
20625 plane = new Plane(),
20626 viewNormalMatrix = new Matrix3(),
20628 uniform = { value: null, needsUpdate: false };
20630 this.uniform = uniform;
20631 this.numPlanes = 0;
20632 this.numIntersection = 0;
20634 this.init = function( planes, enableLocalClipping, camera ) {
20637 planes.length !== 0 ||
20638 enableLocalClipping ||
20639 // enable state of previous frame - the clipping code has to
20640 // run another frame in order to reset the state:
20641 numGlobalPlanes !== 0 ||
20642 localClippingEnabled;
20644 localClippingEnabled = enableLocalClipping;
20646 globalState = projectPlanes( planes, camera, 0 );
20647 numGlobalPlanes = planes.length;
20653 this.beginShadows = function() {
20655 renderingShadows = true;
20656 projectPlanes( null );
20660 this.endShadows = function() {
20662 renderingShadows = false;
20663 resetGlobalState();
20667 this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
20669 if ( ! localClippingEnabled ||
20670 planes === null || planes.length === 0 ||
20671 renderingShadows && ! clipShadows ) {
20672 // there's no local clipping
20674 if ( renderingShadows ) {
20675 // there's no global clipping
20677 projectPlanes( null );
20681 resetGlobalState();
20686 var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
20687 lGlobal = nGlobal * 4,
20689 dstArray = cache.clippingState || null;
20691 uniform.value = dstArray; // ensure unique state
20693 dstArray = projectPlanes( planes, camera, lGlobal, fromCache );
20695 for ( var i = 0; i !== lGlobal; ++ i ) {
20697 dstArray[ i ] = globalState[ i ];
20701 cache.clippingState = dstArray;
20702 this.numIntersection = clipIntersection ? this.numPlanes : 0;
20703 this.numPlanes += nGlobal;
20710 function resetGlobalState() {
20712 if ( uniform.value !== globalState ) {
20714 uniform.value = globalState;
20715 uniform.needsUpdate = numGlobalPlanes > 0;
20719 scope.numPlanes = numGlobalPlanes;
20720 scope.numIntersection = 0;
20724 function projectPlanes( planes, camera, dstOffset, skipTransform ) {
20726 var nPlanes = planes !== null ? planes.length : 0,
20729 if ( nPlanes !== 0 ) {
20731 dstArray = uniform.value;
20733 if ( skipTransform !== true || dstArray === null ) {
20735 var flatSize = dstOffset + nPlanes * 4,
20736 viewMatrix = camera.matrixWorldInverse;
20738 viewNormalMatrix.getNormalMatrix( viewMatrix );
20740 if ( dstArray === null || dstArray.length < flatSize ) {
20742 dstArray = new Float32Array( flatSize );
20746 for ( var i = 0, i4 = dstOffset;
20747 i !== nPlanes; ++ i, i4 += 4 ) {
20749 plane.copy( planes[ i ] ).
20750 applyMatrix4( viewMatrix, viewNormalMatrix );
20752 plane.normal.toArray( dstArray, i4 );
20753 dstArray[ i4 + 3 ] = plane.constant;
20759 uniform.value = dstArray;
20760 uniform.needsUpdate = true;
20764 scope.numPlanes = nPlanes;
20773 * @author thespite / http://www.twitter.com/thespite
20776 function WebGLUtils ( gl, extensions ) {
20778 function convert ( p ) {
20782 if ( p === RepeatWrapping ) return gl.REPEAT;
20783 if ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE;
20784 if ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT;
20786 if ( p === NearestFilter ) return gl.NEAREST;
20787 if ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST;
20788 if ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR;
20790 if ( p === LinearFilter ) return gl.LINEAR;
20791 if ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST;
20792 if ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR;
20794 if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
20795 if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
20796 if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
20797 if ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5;
20799 if ( p === ByteType ) return gl.BYTE;
20800 if ( p === ShortType ) return gl.SHORT;
20801 if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
20802 if ( p === IntType ) return gl.INT;
20803 if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
20804 if ( p === FloatType ) return gl.FLOAT;
20806 if ( p === HalfFloatType ) {
20808 extension = extensions.get( 'OES_texture_half_float' );
20810 if ( extension !== null ) return extension.HALF_FLOAT_OES;
20814 if ( p === AlphaFormat ) return gl.ALPHA;
20815 if ( p === RGBFormat ) return gl.RGB;
20816 if ( p === RGBAFormat ) return gl.RGBA;
20817 if ( p === LuminanceFormat ) return gl.LUMINANCE;
20818 if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
20819 if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
20820 if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
20822 if ( p === AddEquation ) return gl.FUNC_ADD;
20823 if ( p === SubtractEquation ) return gl.FUNC_SUBTRACT;
20824 if ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT;
20826 if ( p === ZeroFactor ) return gl.ZERO;
20827 if ( p === OneFactor ) return gl.ONE;
20828 if ( p === SrcColorFactor ) return gl.SRC_COLOR;
20829 if ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR;
20830 if ( p === SrcAlphaFactor ) return gl.SRC_ALPHA;
20831 if ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA;
20832 if ( p === DstAlphaFactor ) return gl.DST_ALPHA;
20833 if ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA;
20835 if ( p === DstColorFactor ) return gl.DST_COLOR;
20836 if ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR;
20837 if ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE;
20839 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
20840 p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
20842 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
20844 if ( extension !== null ) {
20846 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
20847 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
20848 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
20849 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
20855 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
20856 p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
20858 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
20860 if ( extension !== null ) {
20862 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
20863 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
20864 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
20865 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
20871 if ( p === RGB_ETC1_Format ) {
20873 extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
20875 if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
20879 if ( p === MinEquation || p === MaxEquation ) {
20881 extension = extensions.get( 'EXT_blend_minmax' );
20883 if ( extension !== null ) {
20885 if ( p === MinEquation ) return extension.MIN_EXT;
20886 if ( p === MaxEquation ) return extension.MAX_EXT;
20892 if ( p === UnsignedInt248Type ) {
20894 extension = extensions.get( 'WEBGL_depth_texture' );
20896 if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
20904 return { convert: convert }
20908 // import { Sphere } from '../math/Sphere';
20910 * @author supereggbert / http://www.paulbrunt.co.uk/
20911 * @author mrdoob / http://mrdoob.com/
20912 * @author alteredq / http://alteredqualia.com/
20913 * @author szimek / https://github.com/szimek/
20917 function WebGLRenderer( parameters ) {
20919 console.log( 'THREE.WebGLRenderer', REVISION );
20921 parameters = parameters || {};
20923 var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
20924 _context = parameters.context !== undefined ? parameters.context : null,
20926 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
20927 _depth = parameters.depth !== undefined ? parameters.depth : true,
20928 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
20929 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
20930 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
20931 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false;
20933 var lightsArray = [];
20934 var shadowsArray = [];
20936 var currentRenderList = null;
20938 var spritesArray = [];
20939 var flaresArray = [];
20941 // public properties
20943 this.domElement = _canvas;
20944 this.context = null;
20948 this.autoClear = true;
20949 this.autoClearColor = true;
20950 this.autoClearDepth = true;
20951 this.autoClearStencil = true;
20955 this.sortObjects = true;
20957 // user-defined clipping
20959 this.clippingPlanes = [];
20960 this.localClippingEnabled = false;
20962 // physically based shading
20964 this.gammaFactor = 2.0; // for backwards compatibility
20965 this.gammaInput = false;
20966 this.gammaOutput = false;
20970 this.physicallyCorrectLights = false;
20974 this.toneMapping = LinearToneMapping;
20975 this.toneMappingExposure = 1.0;
20976 this.toneMappingWhitePoint = 1.0;
20980 this.maxMorphTargets = 8;
20981 this.maxMorphNormals = 4;
20983 // internal properties
20987 _isContextLost = false,
20989 // internal state cache
20991 _currentRenderTarget = null,
20992 _currentFramebuffer = null,
20993 _currentMaterialId = - 1,
20994 _currentGeometryProgram = '',
20996 _currentCamera = null,
20997 _currentArrayCamera = null,
20999 _currentViewport = new Vector4(),
21000 _currentScissor = new Vector4(),
21001 _currentScissorTest = null,
21005 _usedTextureUnits = 0,
21009 _width = _canvas.width,
21010 _height = _canvas.height,
21014 _viewport = new Vector4( 0, 0, _width, _height ),
21015 _scissor = new Vector4( 0, 0, _width, _height ),
21016 _scissorTest = false,
21020 _frustum = new Frustum(),
21024 _clipping = new WebGLClipping(),
21025 _clippingEnabled = false,
21026 _localClippingEnabled = false,
21028 // camera matrices cache
21030 _projScreenMatrix = new Matrix4(),
21032 _vector3 = new Vector3(),
21053 render: _infoRender,
21054 memory: _infoMemory,
21059 function getTargetPixelRatio() {
21061 return _currentRenderTarget === null ? _pixelRatio : 1;
21071 var contextAttributes = {
21075 antialias: _antialias,
21076 premultipliedAlpha: _premultipliedAlpha,
21077 preserveDrawingBuffer: _preserveDrawingBuffer
21080 _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );
21082 if ( _gl === null ) {
21084 if ( _canvas.getContext( 'webgl' ) !== null ) {
21086 throw 'Error creating WebGL context with your selected attributes.';
21090 throw 'Error creating WebGL context.';
21096 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
21098 if ( _gl.getShaderPrecisionFormat === undefined ) {
21100 _gl.getShaderPrecisionFormat = function () {
21102 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
21108 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
21109 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
21111 } catch ( error ) {
21113 console.error( 'THREE.WebGLRenderer: ' + error );
21117 var extensions, capabilities, state;
21118 var properties, textures, attributes, geometries, objects, lights;
21119 var programCache, renderLists;
21121 var background, morphtargets, bufferRenderer, indexedBufferRenderer;
21122 var flareRenderer, spriteRenderer;
21126 function initGLContext() {
21128 extensions = new WebGLExtensions( _gl );
21129 extensions.get( 'WEBGL_depth_texture' );
21130 extensions.get( 'OES_texture_float' );
21131 extensions.get( 'OES_texture_float_linear' );
21132 extensions.get( 'OES_texture_half_float' );
21133 extensions.get( 'OES_texture_half_float_linear' );
21134 extensions.get( 'OES_standard_derivatives' );
21135 extensions.get( 'ANGLE_instanced_arrays' );
21137 if ( extensions.get( 'OES_element_index_uint' ) ) {
21139 BufferGeometry.MaxIndex = 4294967296;
21143 utils = new WebGLUtils( _gl, extensions );
21145 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
21147 state = new WebGLState( _gl, extensions, utils );
21148 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
21149 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
21151 properties = new WebGLProperties();
21152 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, _infoMemory );
21153 attributes = new WebGLAttributes( _gl );
21154 geometries = new WebGLGeometries( _gl, attributes, _infoMemory );
21155 objects = new WebGLObjects( geometries, _infoRender );
21156 morphtargets = new WebGLMorphtargets( _gl );
21157 programCache = new WebGLPrograms( _this, extensions, capabilities );
21158 lights = new WebGLLights();
21159 renderLists = new WebGLRenderLists();
21161 background = new WebGLBackground( _this, state, geometries, _premultipliedAlpha );
21163 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
21164 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );
21166 flareRenderer = new WebGLFlareRenderer( _this, _gl, state, textures, capabilities );
21167 spriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities );
21169 _this.info.programs = programCache.programs;
21171 _this.context = _gl;
21172 _this.capabilities = capabilities;
21173 _this.extensions = extensions;
21174 _this.properties = properties;
21175 _this.renderLists = renderLists;
21176 _this.state = state;
21184 var vr = new WebVRManager( _this );
21190 var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
21192 this.shadowMap = shadowMap;
21196 this.getContext = function () {
21202 this.getContextAttributes = function () {
21204 return _gl.getContextAttributes();
21208 this.forceContextLoss = function () {
21210 var extension = extensions.get( 'WEBGL_lose_context' );
21211 if ( extension ) extension.loseContext();
21215 this.forceContextRestore = function () {
21217 var extension = extensions.get( 'WEBGL_lose_context' );
21218 if ( extension ) extension.restoreContext();
21222 this.getPixelRatio = function () {
21224 return _pixelRatio;
21228 this.setPixelRatio = function ( value ) {
21230 if ( value === undefined ) return;
21232 _pixelRatio = value;
21234 this.setSize( _width, _height, false );
21238 this.getSize = function () {
21247 this.setSize = function ( width, height, updateStyle ) {
21249 var device = vr.getDevice();
21251 if ( device && device.isPresenting ) {
21253 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
21261 _canvas.width = width * _pixelRatio;
21262 _canvas.height = height * _pixelRatio;
21264 if ( updateStyle !== false ) {
21266 _canvas.style.width = width + 'px';
21267 _canvas.style.height = height + 'px';
21271 this.setViewport( 0, 0, width, height );
21275 this.getDrawingBufferSize = function () {
21278 width: _width * _pixelRatio,
21279 height: _height * _pixelRatio
21284 this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
21289 _pixelRatio = pixelRatio;
21291 _canvas.width = width * pixelRatio;
21292 _canvas.height = height * pixelRatio;
21294 this.setViewport( 0, 0, width, height );
21298 this.setViewport = function ( x, y, width, height ) {
21300 _viewport.set( x, _height - y - height, width, height );
21301 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
21305 this.setScissor = function ( x, y, width, height ) {
21307 _scissor.set( x, _height - y - height, width, height );
21308 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
21312 this.setScissorTest = function ( boolean ) {
21314 state.setScissorTest( _scissorTest = boolean );
21320 this.getClearColor = background.getClearColor;
21321 this.setClearColor = background.setClearColor;
21322 this.getClearAlpha = background.getClearAlpha;
21323 this.setClearAlpha = background.setClearAlpha;
21325 this.clear = function ( color, depth, stencil ) {
21329 if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
21330 if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
21331 if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
21337 this.clearColor = function () {
21339 this.clear( true, false, false );
21343 this.clearDepth = function () {
21345 this.clear( false, true, false );
21349 this.clearStencil = function () {
21351 this.clear( false, false, true );
21355 this.clearTarget = function ( renderTarget, color, depth, stencil ) {
21357 this.setRenderTarget( renderTarget );
21358 this.clear( color, depth, stencil );
21364 this.dispose = function () {
21366 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
21367 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
21369 renderLists.dispose();
21377 function onContextLost( event ) {
21379 event.preventDefault();
21381 console.log( 'THREE.WebGLRenderer: Context Lost.' );
21383 _isContextLost = true;
21387 function onContextRestore( event ) {
21389 console.log( 'THREE.WebGLRenderer: Context Restored.' );
21391 _isContextLost = false;
21397 function onMaterialDispose( event ) {
21399 var material = event.target;
21401 material.removeEventListener( 'dispose', onMaterialDispose );
21403 deallocateMaterial( material );
21407 // Buffer deallocation
21409 function deallocateMaterial( material ) {
21411 releaseMaterialProgramReference( material );
21413 properties.remove( material );
21418 function releaseMaterialProgramReference( material ) {
21420 var programInfo = properties.get( material ).program;
21422 material.program = undefined;
21424 if ( programInfo !== undefined ) {
21426 programCache.releaseProgram( programInfo );
21432 // Buffer rendering
21434 function renderObjectImmediate( object, program, material ) {
21436 object.render( function ( object ) {
21438 _this.renderBufferImmediate( object, program, material );
21444 this.renderBufferImmediate = function ( object, program, material ) {
21446 state.initAttributes();
21448 var buffers = properties.get( object );
21450 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
21451 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
21452 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
21453 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
21455 var programAttributes = program.getAttributes();
21457 if ( object.hasPositions ) {
21459 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
21460 _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
21462 state.enableAttribute( programAttributes.position );
21463 _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );
21467 if ( object.hasNormals ) {
21469 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );
21471 if ( ! material.isMeshPhongMaterial &&
21472 ! material.isMeshStandardMaterial &&
21473 ! material.isMeshNormalMaterial &&
21474 material.flatShading === true ) {
21476 for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {
21478 var array = object.normalArray;
21480 var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
21481 var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
21482 var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;
21484 array[ i + 0 ] = nx;
21485 array[ i + 1 ] = ny;
21486 array[ i + 2 ] = nz;
21488 array[ i + 3 ] = nx;
21489 array[ i + 4 ] = ny;
21490 array[ i + 5 ] = nz;
21492 array[ i + 6 ] = nx;
21493 array[ i + 7 ] = ny;
21494 array[ i + 8 ] = nz;
21500 _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
21502 state.enableAttribute( programAttributes.normal );
21504 _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );
21508 if ( object.hasUvs && material.map ) {
21510 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
21511 _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
21513 state.enableAttribute( programAttributes.uv );
21515 _gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 );
21519 if ( object.hasColors && material.vertexColors !== NoColors ) {
21521 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
21522 _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
21524 state.enableAttribute( programAttributes.color );
21526 _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );
21530 state.disableUnusedAttributes();
21532 _gl.drawArrays( _gl.TRIANGLES, 0, object.count );
21538 this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
21540 state.setMaterial( material );
21542 var program = setProgram( camera, fog, material, object );
21543 var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true );
21545 var updateBuffers = false;
21547 if ( geometryProgram !== _currentGeometryProgram ) {
21549 _currentGeometryProgram = geometryProgram;
21550 updateBuffers = true;
21554 if ( object.morphTargetInfluences ) {
21556 morphtargets.update( object, geometry, material, program );
21558 updateBuffers = true;
21564 var index = geometry.index;
21565 var position = geometry.attributes.position;
21566 var rangeFactor = 1;
21568 if ( material.wireframe === true ) {
21570 index = geometries.getWireframeAttribute( geometry );
21576 var renderer = bufferRenderer;
21578 if ( index !== null ) {
21580 attribute = attributes.get( index );
21582 renderer = indexedBufferRenderer;
21583 renderer.setIndex( attribute );
21587 if ( updateBuffers ) {
21589 setupVertexAttributes( material, program, geometry );
21591 if ( index !== null ) {
21593 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer );
21603 if ( index !== null ) {
21605 dataCount = index.count;
21607 } else if ( position !== undefined ) {
21609 dataCount = position.count;
21613 var rangeStart = geometry.drawRange.start * rangeFactor;
21614 var rangeCount = geometry.drawRange.count * rangeFactor;
21616 var groupStart = group !== null ? group.start * rangeFactor : 0;
21617 var groupCount = group !== null ? group.count * rangeFactor : Infinity;
21619 var drawStart = Math.max( rangeStart, groupStart );
21620 var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
21622 var drawCount = Math.max( 0, drawEnd - drawStart + 1 );
21624 if ( drawCount === 0 ) return;
21628 if ( object.isMesh ) {
21630 if ( material.wireframe === true ) {
21632 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
21633 renderer.setMode( _gl.LINES );
21637 switch ( object.drawMode ) {
21639 case TrianglesDrawMode:
21640 renderer.setMode( _gl.TRIANGLES );
21643 case TriangleStripDrawMode:
21644 renderer.setMode( _gl.TRIANGLE_STRIP );
21647 case TriangleFanDrawMode:
21648 renderer.setMode( _gl.TRIANGLE_FAN );
21656 } else if ( object.isLine ) {
21658 var lineWidth = material.linewidth;
21660 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
21662 state.setLineWidth( lineWidth * getTargetPixelRatio() );
21664 if ( object.isLineSegments ) {
21666 renderer.setMode( _gl.LINES );
21668 } else if ( object.isLineLoop ) {
21670 renderer.setMode( _gl.LINE_LOOP );
21674 renderer.setMode( _gl.LINE_STRIP );
21678 } else if ( object.isPoints ) {
21680 renderer.setMode( _gl.POINTS );
21684 if ( geometry && geometry.isInstancedBufferGeometry ) {
21686 if ( geometry.maxInstancedCount > 0 ) {
21688 renderer.renderInstances( geometry, drawStart, drawCount );
21694 renderer.render( drawStart, drawCount );
21700 function setupVertexAttributes( material, program, geometry, startIndex ) {
21702 if ( geometry && geometry.isInstancedBufferGeometry ) {
21704 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {
21706 console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
21713 if ( startIndex === undefined ) startIndex = 0;
21715 state.initAttributes();
21717 var geometryAttributes = geometry.attributes;
21719 var programAttributes = program.getAttributes();
21721 var materialDefaultAttributeValues = material.defaultAttributeValues;
21723 for ( var name in programAttributes ) {
21725 var programAttribute = programAttributes[ name ];
21727 if ( programAttribute >= 0 ) {
21729 var geometryAttribute = geometryAttributes[ name ];
21731 if ( geometryAttribute !== undefined ) {
21733 var normalized = geometryAttribute.normalized;
21734 var size = geometryAttribute.itemSize;
21736 var attribute = attributes.get( geometryAttribute );
21738 // TODO Attribute may not be available on context restore
21740 if ( attribute === undefined ) continue;
21742 var buffer = attribute.buffer;
21743 var type = attribute.type;
21744 var bytesPerElement = attribute.bytesPerElement;
21746 if ( geometryAttribute.isInterleavedBufferAttribute ) {
21748 var data = geometryAttribute.data;
21749 var stride = data.stride;
21750 var offset = geometryAttribute.offset;
21752 if ( data && data.isInstancedInterleavedBuffer ) {
21754 state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
21756 if ( geometry.maxInstancedCount === undefined ) {
21758 geometry.maxInstancedCount = data.meshPerAttribute * data.count;
21764 state.enableAttribute( programAttribute );
21768 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
21769 _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );
21773 if ( geometryAttribute.isInstancedBufferAttribute ) {
21775 state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
21777 if ( geometry.maxInstancedCount === undefined ) {
21779 geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
21785 state.enableAttribute( programAttribute );
21789 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
21790 _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );
21794 } else if ( materialDefaultAttributeValues !== undefined ) {
21796 var value = materialDefaultAttributeValues[ name ];
21798 if ( value !== undefined ) {
21800 switch ( value.length ) {
21803 _gl.vertexAttrib2fv( programAttribute, value );
21807 _gl.vertexAttrib3fv( programAttribute, value );
21811 _gl.vertexAttrib4fv( programAttribute, value );
21815 _gl.vertexAttrib1fv( programAttribute, value );
21827 state.disableUnusedAttributes();
21833 this.compile = function ( scene, camera ) {
21835 lightsArray.length = 0;
21836 shadowsArray.length = 0;
21838 scene.traverse( function ( object ) {
21840 if ( object.isLight ) {
21842 lightsArray.push( object );
21844 if ( object.castShadow ) {
21846 shadowsArray.push( object );
21854 lights.setup( lightsArray, shadowsArray, camera );
21856 scene.traverse( function ( object ) {
21858 if ( object.material ) {
21860 if ( Array.isArray( object.material ) ) {
21862 for ( var i = 0; i < object.material.length; i ++ ) {
21864 initMaterial( object.material[ i ], scene.fog, object );
21870 initMaterial( object.material, scene.fog, object );
21882 var isAnimating = false;
21883 var onAnimationFrame = null;
21887 if ( isAnimating ) return;
21888 ( vr.getDevice() || window ).requestAnimationFrame( loop );
21889 isAnimating = true;
21893 function loop( time ) {
21895 if ( onAnimationFrame !== null ) onAnimationFrame( time );
21896 ( vr.getDevice() || window ).requestAnimationFrame( loop );
21900 this.animate = function ( callback ) {
21902 onAnimationFrame = callback;
21909 this.render = function ( scene, camera, renderTarget, forceClear ) {
21911 if ( ! ( camera && camera.isCamera ) ) {
21913 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
21918 if ( _isContextLost ) return;
21920 // reset caching for this frame
21922 _currentGeometryProgram = '';
21923 _currentMaterialId = - 1;
21924 _currentCamera = null;
21926 // update scene graph
21928 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
21930 // update camera matrices and frustum
21932 if ( camera.parent === null ) camera.updateMatrixWorld();
21934 if ( vr.enabled ) {
21936 camera = vr.getCamera( camera );
21940 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
21941 _frustum.setFromMatrix( _projScreenMatrix );
21943 lightsArray.length = 0;
21944 shadowsArray.length = 0;
21946 spritesArray.length = 0;
21947 flaresArray.length = 0;
21949 _localClippingEnabled = this.localClippingEnabled;
21950 _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
21952 currentRenderList = renderLists.get( scene, camera );
21953 currentRenderList.init();
21955 projectObject( scene, camera, _this.sortObjects );
21957 if ( _this.sortObjects === true ) {
21959 currentRenderList.sort();
21965 if ( _clippingEnabled ) _clipping.beginShadows();
21967 shadowMap.render( shadowsArray, scene, camera );
21969 lights.setup( lightsArray, shadowsArray, camera );
21971 if ( _clippingEnabled ) _clipping.endShadows();
21975 _infoRender.frame ++;
21976 _infoRender.calls = 0;
21977 _infoRender.vertices = 0;
21978 _infoRender.faces = 0;
21979 _infoRender.points = 0;
21981 if ( renderTarget === undefined ) {
21983 renderTarget = null;
21987 this.setRenderTarget( renderTarget );
21991 background.render( currentRenderList, scene, camera, forceClear );
21995 var opaqueObjects = currentRenderList.opaque;
21996 var transparentObjects = currentRenderList.transparent;
21998 if ( scene.overrideMaterial ) {
22000 var overrideMaterial = scene.overrideMaterial;
22002 if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial );
22003 if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );
22007 // opaque pass (front-to-back order)
22009 if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );
22011 // transparent pass (back-to-front order)
22013 if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );
22017 // custom renderers
22019 spriteRenderer.render( spritesArray, scene, camera );
22020 flareRenderer.render( flaresArray, scene, camera, _currentViewport );
22022 // Generate mipmap if we're using any kind of mipmap filtering
22024 if ( renderTarget ) {
22026 textures.updateRenderTargetMipmap( renderTarget );
22030 // Ensure depth buffer writing is enabled so it can be cleared on next render
22032 state.buffers.depth.setTest( true );
22033 state.buffers.depth.setMask( true );
22034 state.buffers.color.setMask( true );
22036 state.setPolygonOffset( false );
22038 if ( vr.enabled ) {
22049 // TODO Duplicated code (Frustum)
22051 var _sphere = new Sphere();
22053 function isObjectViewable( object ) {
22055 var geometry = object.geometry;
22057 if ( geometry.boundingSphere === null )
22058 geometry.computeBoundingSphere();
22060 _sphere.copy( geometry.boundingSphere ).
22061 applyMatrix4( object.matrixWorld );
22063 return isSphereViewable( _sphere );
22067 function isSpriteViewable( sprite ) {
22069 _sphere.center.set( 0, 0, 0 );
22070 _sphere.radius = 0.7071067811865476;
22071 _sphere.applyMatrix4( sprite.matrixWorld );
22073 return isSphereViewable( _sphere );
22077 function isSphereViewable( sphere ) {
22079 if ( ! _frustum.intersectsSphere( sphere ) ) return false;
22081 var numPlanes = _clipping.numPlanes;
22083 if ( numPlanes === 0 ) return true;
22085 var planes = _this.clippingPlanes,
22087 center = sphere.center,
22088 negRad = - sphere.radius,
22093 // out when deeper than radius in the negative halfspace
22094 if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
22096 } while ( ++ i !== numPlanes );
22103 function projectObject( object, camera, sortObjects ) {
22105 if ( ! object.visible ) return;
22107 var visible = object.layers.test( camera.layers );
22111 if ( object.isLight ) {
22113 lightsArray.push( object );
22115 if ( object.castShadow ) {
22117 shadowsArray.push( object );
22121 } else if ( object.isSprite ) {
22123 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
22125 spritesArray.push( object );
22129 } else if ( object.isLensFlare ) {
22131 flaresArray.push( object );
22133 } else if ( object.isImmediateRenderObject ) {
22135 if ( sortObjects ) {
22137 _vector3.setFromMatrixPosition( object.matrixWorld )
22138 .applyMatrix4( _projScreenMatrix );
22142 currentRenderList.push( object, null, object.material, _vector3.z, null );
22144 } else if ( object.isMesh || object.isLine || object.isPoints ) {
22146 if ( object.isSkinnedMesh ) {
22148 object.skeleton.update();
22152 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
22154 if ( sortObjects ) {
22156 _vector3.setFromMatrixPosition( object.matrixWorld )
22157 .applyMatrix4( _projScreenMatrix );
22161 var geometry = objects.update( object );
22162 var material = object.material;
22164 if ( Array.isArray( material ) ) {
22166 var groups = geometry.groups;
22168 for ( var i = 0, l = groups.length; i < l; i ++ ) {
22170 var group = groups[ i ];
22171 var groupMaterial = material[ group.materialIndex ];
22173 if ( groupMaterial && groupMaterial.visible ) {
22175 currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group );
22181 } else if ( material.visible ) {
22183 currentRenderList.push( object, geometry, material, _vector3.z, null );
22193 var children = object.children;
22195 for ( var i = 0, l = children.length; i < l; i ++ ) {
22197 projectObject( children[ i ], camera, sortObjects );
22203 function renderObjects( renderList, scene, camera, overrideMaterial ) {
22205 for ( var i = 0, l = renderList.length; i < l; i ++ ) {
22207 var renderItem = renderList[ i ];
22209 var object = renderItem.object;
22210 var geometry = renderItem.geometry;
22211 var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
22212 var group = renderItem.group;
22214 if ( camera.isArrayCamera ) {
22216 _currentArrayCamera = camera;
22218 var cameras = camera.cameras;
22220 for ( var j = 0, jl = cameras.length; j < jl; j ++ ) {
22222 var camera2 = cameras[ j ];
22224 if ( object.layers.test( camera2.layers ) ) {
22226 var bounds = camera2.bounds;
22228 var x = bounds.x * _width;
22229 var y = bounds.y * _height;
22230 var width = bounds.z * _width;
22231 var height = bounds.w * _height;
22233 state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
22235 renderObject( object, scene, camera2, geometry, material, group );
22243 _currentArrayCamera = null;
22245 renderObject( object, scene, camera, geometry, material, group );
22253 function renderObject( object, scene, camera, geometry, material, group ) {
22255 object.onBeforeRender( _this, scene, camera, geometry, material, group );
22257 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
22258 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
22260 if ( object.isImmediateRenderObject ) {
22262 state.setMaterial( material );
22264 var program = setProgram( camera, scene.fog, material, object );
22266 _currentGeometryProgram = '';
22268 renderObjectImmediate( object, program, material );
22272 _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );
22276 object.onAfterRender( _this, scene, camera, geometry, material, group );
22280 function initMaterial( material, fog, object ) {
22282 var materialProperties = properties.get( material );
22284 var parameters = programCache.getParameters(
22285 material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object );
22287 var code = programCache.getProgramCode( material, parameters );
22289 var program = materialProperties.program;
22290 var programChange = true;
22292 if ( program === undefined ) {
22295 material.addEventListener( 'dispose', onMaterialDispose );
22297 } else if ( program.code !== code ) {
22299 // changed glsl or parameters
22300 releaseMaterialProgramReference( material );
22302 } else if ( parameters.shaderID !== undefined ) {
22304 // same glsl and uniform list
22309 // only rebuild uniform list
22310 programChange = false;
22314 if ( programChange ) {
22316 if ( parameters.shaderID ) {
22318 var shader = ShaderLib[ parameters.shaderID ];
22320 materialProperties.shader = {
22321 name: material.type,
22322 uniforms: UniformsUtils.clone( shader.uniforms ),
22323 vertexShader: shader.vertexShader,
22324 fragmentShader: shader.fragmentShader
22329 materialProperties.shader = {
22330 name: material.type,
22331 uniforms: material.uniforms,
22332 vertexShader: material.vertexShader,
22333 fragmentShader: material.fragmentShader
22338 material.onBeforeCompile( materialProperties.shader );
22340 program = programCache.acquireProgram( material, materialProperties.shader, parameters, code );
22342 materialProperties.program = program;
22343 material.program = program;
22347 var programAttributes = program.getAttributes();
22349 if ( material.morphTargets ) {
22351 material.numSupportedMorphTargets = 0;
22353 for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
22355 if ( programAttributes[ 'morphTarget' + i ] >= 0 ) {
22357 material.numSupportedMorphTargets ++;
22365 if ( material.morphNormals ) {
22367 material.numSupportedMorphNormals = 0;
22369 for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
22371 if ( programAttributes[ 'morphNormal' + i ] >= 0 ) {
22373 material.numSupportedMorphNormals ++;
22381 var uniforms = materialProperties.shader.uniforms;
22383 if ( ! material.isShaderMaterial &&
22384 ! material.isRawShaderMaterial ||
22385 material.clipping === true ) {
22387 materialProperties.numClippingPlanes = _clipping.numPlanes;
22388 materialProperties.numIntersection = _clipping.numIntersection;
22389 uniforms.clippingPlanes = _clipping.uniform;
22393 materialProperties.fog = fog;
22395 // store the light setup it was created for
22397 materialProperties.lightsHash = lights.state.hash;
22399 if ( material.lights ) {
22401 // wire up the material to this renderer's lighting state
22403 uniforms.ambientLightColor.value = lights.state.ambient;
22404 uniforms.directionalLights.value = lights.state.directional;
22405 uniforms.spotLights.value = lights.state.spot;
22406 uniforms.rectAreaLights.value = lights.state.rectArea;
22407 uniforms.pointLights.value = lights.state.point;
22408 uniforms.hemisphereLights.value = lights.state.hemi;
22410 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
22411 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
22412 uniforms.spotShadowMap.value = lights.state.spotShadowMap;
22413 uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
22414 uniforms.pointShadowMap.value = lights.state.pointShadowMap;
22415 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
22416 // TODO (abelnation): add area lights shadow info to uniforms
22420 var progUniforms = materialProperties.program.getUniforms(),
22422 WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
22424 materialProperties.uniformsList = uniformsList;
22428 function setProgram( camera, fog, material, object ) {
22430 _usedTextureUnits = 0;
22432 var materialProperties = properties.get( material );
22434 if ( _clippingEnabled ) {
22436 if ( _localClippingEnabled || camera !== _currentCamera ) {
22439 camera === _currentCamera &&
22440 material.id === _currentMaterialId;
22442 // we might want to call this function with some ClippingGroup
22443 // object instead of the material, once it becomes feasible
22445 _clipping.setState(
22446 material.clippingPlanes, material.clipIntersection, material.clipShadows,
22447 camera, materialProperties, useCache );
22453 if ( material.needsUpdate === false ) {
22455 if ( materialProperties.program === undefined ) {
22457 material.needsUpdate = true;
22459 } else if ( material.fog && materialProperties.fog !== fog ) {
22461 material.needsUpdate = true;
22463 } else if ( material.lights && materialProperties.lightsHash !== lights.state.hash ) {
22465 material.needsUpdate = true;
22467 } else if ( materialProperties.numClippingPlanes !== undefined &&
22468 ( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
22469 materialProperties.numIntersection !== _clipping.numIntersection ) ) {
22471 material.needsUpdate = true;
22477 if ( material.needsUpdate ) {
22479 initMaterial( material, fog, object );
22480 material.needsUpdate = false;
22484 var refreshProgram = false;
22485 var refreshMaterial = false;
22486 var refreshLights = false;
22488 var program = materialProperties.program,
22489 p_uniforms = program.getUniforms(),
22490 m_uniforms = materialProperties.shader.uniforms;
22492 if ( state.useProgram( program.program ) ) {
22494 refreshProgram = true;
22495 refreshMaterial = true;
22496 refreshLights = true;
22500 if ( material.id !== _currentMaterialId ) {
22502 _currentMaterialId = material.id;
22504 refreshMaterial = true;
22508 if ( refreshProgram || camera !== _currentCamera ) {
22510 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
22512 if ( capabilities.logarithmicDepthBuffer ) {
22514 p_uniforms.setValue( _gl, 'logDepthBufFC',
22515 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
22519 // Avoid unneeded uniform updates per ArrayCamera's sub-camera
22521 if ( _currentCamera !== ( _currentArrayCamera || camera ) ) {
22523 _currentCamera = ( _currentArrayCamera || camera );
22525 // lighting uniforms depend on the camera so enforce an update
22526 // now, in case this material supports lights - or later, when
22527 // the next material that does gets activated:
22529 refreshMaterial = true; // set to true on material change
22530 refreshLights = true; // remains set until update done
22534 // load material specific uniforms
22535 // (shader material also gets them for the sake of genericity)
22537 if ( material.isShaderMaterial ||
22538 material.isMeshPhongMaterial ||
22539 material.isMeshStandardMaterial ||
22540 material.envMap ) {
22542 var uCamPos = p_uniforms.map.cameraPosition;
22544 if ( uCamPos !== undefined ) {
22546 uCamPos.setValue( _gl,
22547 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
22553 if ( material.isMeshPhongMaterial ||
22554 material.isMeshLambertMaterial ||
22555 material.isMeshBasicMaterial ||
22556 material.isMeshStandardMaterial ||
22557 material.isShaderMaterial ||
22558 material.skinning ) {
22560 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
22566 // skinning uniforms must be set even if material didn't change
22567 // auto-setting of texture unit for bone texture must go before other textures
22568 // not sure why, but otherwise weird things happen
22570 if ( material.skinning ) {
22572 p_uniforms.setOptional( _gl, object, 'bindMatrix' );
22573 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
22575 var skeleton = object.skeleton;
22579 var bones = skeleton.bones;
22581 if ( capabilities.floatVertexTextures ) {
22583 if ( skeleton.boneTexture === undefined ) {
22585 // layout (1 matrix = 4 pixels)
22586 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
22587 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
22588 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
22589 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
22590 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
22593 var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
22594 size = _Math.nextPowerOfTwo( Math.ceil( size ) );
22595 size = Math.max( size, 4 );
22597 var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
22598 boneMatrices.set( skeleton.boneMatrices ); // copy current values
22600 var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
22602 skeleton.boneMatrices = boneMatrices;
22603 skeleton.boneTexture = boneTexture;
22604 skeleton.boneTextureSize = size;
22608 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture );
22609 p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
22613 p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
22621 if ( refreshMaterial ) {
22623 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
22624 p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );
22626 if ( material.lights ) {
22628 // the current material requires lighting info
22630 // note: all lighting uniforms are always set correctly
22631 // they simply reference the renderer's state for their
22634 // use the current material's .needsUpdate flags to set
22635 // the GL state when required
22637 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
22641 // refresh uniforms common to several materials
22643 if ( fog && material.fog ) {
22645 refreshUniformsFog( m_uniforms, fog );
22649 if ( material.isMeshBasicMaterial ) {
22651 refreshUniformsCommon( m_uniforms, material );
22653 } else if ( material.isMeshLambertMaterial ) {
22655 refreshUniformsCommon( m_uniforms, material );
22656 refreshUniformsLambert( m_uniforms, material );
22658 } else if ( material.isMeshPhongMaterial ) {
22660 refreshUniformsCommon( m_uniforms, material );
22662 if ( material.isMeshToonMaterial ) {
22664 refreshUniformsToon( m_uniforms, material );
22668 refreshUniformsPhong( m_uniforms, material );
22672 } else if ( material.isMeshStandardMaterial ) {
22674 refreshUniformsCommon( m_uniforms, material );
22676 if ( material.isMeshPhysicalMaterial ) {
22678 refreshUniformsPhysical( m_uniforms, material );
22682 refreshUniformsStandard( m_uniforms, material );
22686 } else if ( material.isMeshDepthMaterial ) {
22688 refreshUniformsCommon( m_uniforms, material );
22689 refreshUniformsDepth( m_uniforms, material );
22691 } else if ( material.isMeshDistanceMaterial ) {
22693 refreshUniformsCommon( m_uniforms, material );
22694 refreshUniformsDistance( m_uniforms, material );
22696 } else if ( material.isMeshNormalMaterial ) {
22698 refreshUniformsCommon( m_uniforms, material );
22699 refreshUniformsNormal( m_uniforms, material );
22701 } else if ( material.isLineBasicMaterial ) {
22703 refreshUniformsLine( m_uniforms, material );
22705 if ( material.isLineDashedMaterial ) {
22707 refreshUniformsDash( m_uniforms, material );
22711 } else if ( material.isPointsMaterial ) {
22713 refreshUniformsPoints( m_uniforms, material );
22715 } else if ( material.isShadowMaterial ) {
22717 m_uniforms.color.value = material.color;
22718 m_uniforms.opacity.value = material.opacity;
22722 // RectAreaLight Texture
22723 // TODO (mrdoob): Find a nicer implementation
22725 if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE;
22726 if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE;
22728 WebGLUniforms.upload(
22729 _gl, materialProperties.uniformsList, m_uniforms, _this );
22736 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
22737 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
22738 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
22744 // Uniforms (refresh uniforms objects)
22746 function refreshUniformsCommon( uniforms, material ) {
22748 uniforms.opacity.value = material.opacity;
22750 if ( material.color ) {
22752 uniforms.diffuse.value = material.color;
22756 if ( material.emissive ) {
22758 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
22762 if ( material.map ) {
22764 uniforms.map.value = material.map;
22768 if ( material.alphaMap ) {
22770 uniforms.alphaMap.value = material.alphaMap;
22774 if ( material.specularMap ) {
22776 uniforms.specularMap.value = material.specularMap;
22780 if ( material.envMap ) {
22782 uniforms.envMap.value = material.envMap;
22784 // don't flip CubeTexture envMaps, flip everything else:
22785 // WebGLRenderTargetCube will be flipped for backwards compatibility
22786 // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
22787 // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
22788 uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;
22790 uniforms.reflectivity.value = material.reflectivity;
22791 uniforms.refractionRatio.value = material.refractionRatio;
22795 if ( material.lightMap ) {
22797 uniforms.lightMap.value = material.lightMap;
22798 uniforms.lightMapIntensity.value = material.lightMapIntensity;
22802 if ( material.aoMap ) {
22804 uniforms.aoMap.value = material.aoMap;
22805 uniforms.aoMapIntensity.value = material.aoMapIntensity;
22809 // uv repeat and offset setting priorities
22819 if ( material.map ) {
22821 uvScaleMap = material.map;
22823 } else if ( material.specularMap ) {
22825 uvScaleMap = material.specularMap;
22827 } else if ( material.displacementMap ) {
22829 uvScaleMap = material.displacementMap;
22831 } else if ( material.normalMap ) {
22833 uvScaleMap = material.normalMap;
22835 } else if ( material.bumpMap ) {
22837 uvScaleMap = material.bumpMap;
22839 } else if ( material.roughnessMap ) {
22841 uvScaleMap = material.roughnessMap;
22843 } else if ( material.metalnessMap ) {
22845 uvScaleMap = material.metalnessMap;
22847 } else if ( material.alphaMap ) {
22849 uvScaleMap = material.alphaMap;
22851 } else if ( material.emissiveMap ) {
22853 uvScaleMap = material.emissiveMap;
22857 if ( uvScaleMap !== undefined ) {
22859 // backwards compatibility
22860 if ( uvScaleMap.isWebGLRenderTarget ) {
22862 uvScaleMap = uvScaleMap.texture;
22866 var offset = uvScaleMap.offset;
22867 var repeat = uvScaleMap.repeat;
22869 uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
22875 function refreshUniformsLine( uniforms, material ) {
22877 uniforms.diffuse.value = material.color;
22878 uniforms.opacity.value = material.opacity;
22882 function refreshUniformsDash( uniforms, material ) {
22884 uniforms.dashSize.value = material.dashSize;
22885 uniforms.totalSize.value = material.dashSize + material.gapSize;
22886 uniforms.scale.value = material.scale;
22890 function refreshUniformsPoints( uniforms, material ) {
22892 uniforms.diffuse.value = material.color;
22893 uniforms.opacity.value = material.opacity;
22894 uniforms.size.value = material.size * _pixelRatio;
22895 uniforms.scale.value = _height * 0.5;
22897 uniforms.map.value = material.map;
22899 if ( material.map !== null ) {
22901 var offset = material.map.offset;
22902 var repeat = material.map.repeat;
22904 uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
22910 function refreshUniformsFog( uniforms, fog ) {
22912 uniforms.fogColor.value = fog.color;
22916 uniforms.fogNear.value = fog.near;
22917 uniforms.fogFar.value = fog.far;
22919 } else if ( fog.isFogExp2 ) {
22921 uniforms.fogDensity.value = fog.density;
22927 function refreshUniformsLambert( uniforms, material ) {
22929 if ( material.emissiveMap ) {
22931 uniforms.emissiveMap.value = material.emissiveMap;
22937 function refreshUniformsPhong( uniforms, material ) {
22939 uniforms.specular.value = material.specular;
22940 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
22942 if ( material.emissiveMap ) {
22944 uniforms.emissiveMap.value = material.emissiveMap;
22948 if ( material.bumpMap ) {
22950 uniforms.bumpMap.value = material.bumpMap;
22951 uniforms.bumpScale.value = material.bumpScale;
22955 if ( material.normalMap ) {
22957 uniforms.normalMap.value = material.normalMap;
22958 uniforms.normalScale.value.copy( material.normalScale );
22962 if ( material.displacementMap ) {
22964 uniforms.displacementMap.value = material.displacementMap;
22965 uniforms.displacementScale.value = material.displacementScale;
22966 uniforms.displacementBias.value = material.displacementBias;
22972 function refreshUniformsToon( uniforms, material ) {
22974 refreshUniformsPhong( uniforms, material );
22976 if ( material.gradientMap ) {
22978 uniforms.gradientMap.value = material.gradientMap;
22984 function refreshUniformsStandard( uniforms, material ) {
22986 uniforms.roughness.value = material.roughness;
22987 uniforms.metalness.value = material.metalness;
22989 if ( material.roughnessMap ) {
22991 uniforms.roughnessMap.value = material.roughnessMap;
22995 if ( material.metalnessMap ) {
22997 uniforms.metalnessMap.value = material.metalnessMap;
23001 if ( material.emissiveMap ) {
23003 uniforms.emissiveMap.value = material.emissiveMap;
23007 if ( material.bumpMap ) {
23009 uniforms.bumpMap.value = material.bumpMap;
23010 uniforms.bumpScale.value = material.bumpScale;
23014 if ( material.normalMap ) {
23016 uniforms.normalMap.value = material.normalMap;
23017 uniforms.normalScale.value.copy( material.normalScale );
23021 if ( material.displacementMap ) {
23023 uniforms.displacementMap.value = material.displacementMap;
23024 uniforms.displacementScale.value = material.displacementScale;
23025 uniforms.displacementBias.value = material.displacementBias;
23029 if ( material.envMap ) {
23031 //uniforms.envMap.value = material.envMap; // part of uniforms common
23032 uniforms.envMapIntensity.value = material.envMapIntensity;
23038 function refreshUniformsPhysical( uniforms, material ) {
23040 uniforms.clearCoat.value = material.clearCoat;
23041 uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
23043 refreshUniformsStandard( uniforms, material );
23047 function refreshUniformsDepth( uniforms, material ) {
23049 if ( material.displacementMap ) {
23051 uniforms.displacementMap.value = material.displacementMap;
23052 uniforms.displacementScale.value = material.displacementScale;
23053 uniforms.displacementBias.value = material.displacementBias;
23059 function refreshUniformsDistance( uniforms, material ) {
23061 if ( material.displacementMap ) {
23063 uniforms.displacementMap.value = material.displacementMap;
23064 uniforms.displacementScale.value = material.displacementScale;
23065 uniforms.displacementBias.value = material.displacementBias;
23069 uniforms.referencePosition.value.copy( material.referencePosition );
23070 uniforms.nearDistance.value = material.nearDistance;
23071 uniforms.farDistance.value = material.farDistance;
23075 function refreshUniformsNormal( uniforms, material ) {
23077 if ( material.bumpMap ) {
23079 uniforms.bumpMap.value = material.bumpMap;
23080 uniforms.bumpScale.value = material.bumpScale;
23084 if ( material.normalMap ) {
23086 uniforms.normalMap.value = material.normalMap;
23087 uniforms.normalScale.value.copy( material.normalScale );
23091 if ( material.displacementMap ) {
23093 uniforms.displacementMap.value = material.displacementMap;
23094 uniforms.displacementScale.value = material.displacementScale;
23095 uniforms.displacementBias.value = material.displacementBias;
23101 // If uniforms are marked as clean, they don't need to be loaded to the GPU.
23103 function markUniformsLightsNeedsUpdate( uniforms, value ) {
23105 uniforms.ambientLightColor.needsUpdate = value;
23107 uniforms.directionalLights.needsUpdate = value;
23108 uniforms.pointLights.needsUpdate = value;
23109 uniforms.spotLights.needsUpdate = value;
23110 uniforms.rectAreaLights.needsUpdate = value;
23111 uniforms.hemisphereLights.needsUpdate = value;
23115 // GL state setting
23117 this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
23119 state.setCullFace( cullFace );
23120 state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );
23126 function allocTextureUnit() {
23128 var textureUnit = _usedTextureUnits;
23130 if ( textureUnit >= capabilities.maxTextures ) {
23132 console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
23136 _usedTextureUnits += 1;
23138 return textureUnit;
23142 this.allocTextureUnit = allocTextureUnit;
23144 // this.setTexture2D = setTexture2D;
23145 this.setTexture2D = ( function () {
23147 var warned = false;
23149 // backwards compatibility: peel texture.texture
23150 return function setTexture2D( texture, slot ) {
23152 if ( texture && texture.isWebGLRenderTarget ) {
23156 console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." );
23161 texture = texture.texture;
23165 textures.setTexture2D( texture, slot );
23171 this.setTexture = ( function () {
23173 var warned = false;
23175 return function setTexture( texture, slot ) {
23179 console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." );
23184 textures.setTexture2D( texture, slot );
23190 this.setTextureCube = ( function () {
23192 var warned = false;
23194 return function setTextureCube( texture, slot ) {
23196 // backwards compatibility: peel texture.texture
23197 if ( texture && texture.isWebGLRenderTargetCube ) {
23201 console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
23206 texture = texture.texture;
23210 // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
23211 // TODO: unify these code paths
23212 if ( ( texture && texture.isCubeTexture ) ||
23213 ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {
23215 // CompressedTexture can have Array in image :/
23217 // this function alone should take care of cube textures
23218 textures.setTextureCube( texture, slot );
23222 // assumed: texture property of THREE.WebGLRenderTargetCube
23224 textures.setTextureCubeDynamic( texture, slot );
23232 this.getRenderTarget = function () {
23234 return _currentRenderTarget;
23238 this.setRenderTarget = function ( renderTarget ) {
23240 _currentRenderTarget = renderTarget;
23242 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
23244 textures.setupRenderTarget( renderTarget );
23248 var framebuffer = null;
23249 var isCube = false;
23251 if ( renderTarget ) {
23253 var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
23255 if ( renderTarget.isWebGLRenderTargetCube ) {
23257 framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ];
23262 framebuffer = __webglFramebuffer;
23266 _currentViewport.copy( renderTarget.viewport );
23267 _currentScissor.copy( renderTarget.scissor );
23268 _currentScissorTest = renderTarget.scissorTest;
23272 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );
23273 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );
23274 _currentScissorTest = _scissorTest;
23278 if ( _currentFramebuffer !== framebuffer ) {
23280 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
23281 _currentFramebuffer = framebuffer;
23285 state.viewport( _currentViewport );
23286 state.scissor( _currentScissor );
23287 state.setScissorTest( _currentScissorTest );
23291 var textureProperties = properties.get( renderTarget.texture );
23292 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );
23298 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {
23300 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
23302 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
23307 var framebuffer = properties.get( renderTarget ).__webglFramebuffer;
23309 if ( framebuffer ) {
23311 var restore = false;
23313 if ( framebuffer !== _currentFramebuffer ) {
23315 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
23323 var texture = renderTarget.texture;
23324 var textureFormat = texture.format;
23325 var textureType = texture.type;
23327 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
23329 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
23334 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)
23335 ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
23336 ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {
23338 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
23343 if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
23345 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
23347 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
23349 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
23355 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
23363 _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
23376 * @author mrdoob / http://mrdoob.com/
23377 * @author alteredq / http://alteredqualia.com/
23380 function FogExp2 ( color, density ) {
23384 this.color = new Color( color );
23385 this.density = ( density !== undefined ) ? density : 0.00025;
23389 FogExp2.prototype.isFogExp2 = true;
23391 FogExp2.prototype.clone = function () {
23393 return new FogExp2( this.color.getHex(), this.density );
23397 FogExp2.prototype.toJSON = function ( meta ) {
23401 color: this.color.getHex(),
23402 density: this.density
23408 * @author mrdoob / http://mrdoob.com/
23409 * @author alteredq / http://alteredqualia.com/
23412 function Fog ( color, near, far ) {
23416 this.color = new Color( color );
23418 this.near = ( near !== undefined ) ? near : 1;
23419 this.far = ( far !== undefined ) ? far : 1000;
23423 Fog.prototype.isFog = true;
23425 Fog.prototype.clone = function () {
23427 return new Fog( this.color.getHex(), this.near, this.far );
23431 Fog.prototype.toJSON = function ( meta ) {
23435 color: this.color.getHex(),
23443 * @author mrdoob / http://mrdoob.com/
23446 function Scene () {
23448 Object3D.call( this );
23450 this.type = 'Scene';
23452 this.background = null;
23454 this.overrideMaterial = null;
23456 this.autoUpdate = true; // checked by the renderer
23460 Scene.prototype = Object.assign( Object.create( Object3D.prototype ), {
23462 constructor: Scene,
23464 copy: function ( source, recursive ) {
23466 Object3D.prototype.copy.call( this, source, recursive );
23468 if ( source.background !== null ) this.background = source.background.clone();
23469 if ( source.fog !== null ) this.fog = source.fog.clone();
23470 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
23472 this.autoUpdate = source.autoUpdate;
23473 this.matrixAutoUpdate = source.matrixAutoUpdate;
23479 toJSON: function ( meta ) {
23481 var data = Object3D.prototype.toJSON.call( this, meta );
23483 if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
23484 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
23493 * @author mikael emtinger / http://gomo.se/
23494 * @author alteredq / http://alteredqualia.com/
23497 function LensFlare( texture, size, distance, blending, color ) {
23499 Object3D.call( this );
23501 this.lensFlares = [];
23503 this.positionScreen = new Vector3();
23504 this.customUpdateCallback = undefined;
23506 if ( texture !== undefined ) {
23508 this.add( texture, size, distance, blending, color );
23514 LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), {
23516 constructor: LensFlare,
23520 copy: function ( source ) {
23522 Object3D.prototype.copy.call( this, source );
23524 this.positionScreen.copy( source.positionScreen );
23525 this.customUpdateCallback = source.customUpdateCallback;
23527 for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) {
23529 this.lensFlares.push( source.lensFlares[ i ] );
23537 add: function ( texture, size, distance, blending, color, opacity ) {
23539 if ( size === undefined ) size = - 1;
23540 if ( distance === undefined ) distance = 0;
23541 if ( opacity === undefined ) opacity = 1;
23542 if ( color === undefined ) color = new Color( 0xffffff );
23543 if ( blending === undefined ) blending = NormalBlending;
23545 distance = Math.min( distance, Math.max( 0, distance ) );
23547 this.lensFlares.push( {
23548 texture: texture, // THREE.Texture
23549 size: size, // size in pixels (-1 = use texture.width)
23550 distance: distance, // distance (0-1) from light source (0=at light source)
23551 x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back
23553 rotation: 0, // rotation
23554 opacity: opacity, // opacity
23555 color: color, // color
23556 blending: blending // blending
23562 * Update lens flares update positions on all flares based on the screen position
23563 * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.
23566 updateLensFlares: function () {
23568 var f, fl = this.lensFlares.length;
23570 var vecX = - this.positionScreen.x * 2;
23571 var vecY = - this.positionScreen.y * 2;
23573 for ( f = 0; f < fl; f ++ ) {
23575 flare = this.lensFlares[ f ];
23577 flare.x = this.positionScreen.x + vecX * flare.distance;
23578 flare.y = this.positionScreen.y + vecY * flare.distance;
23580 flare.wantedRotation = flare.x * Math.PI * 0.25;
23581 flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;
23590 * @author alteredq / http://alteredqualia.com/
23594 * opacity: <float>,
23595 * map: new THREE.Texture( <Image> ),
23597 * uvOffset: new THREE.Vector2(),
23598 * uvScale: new THREE.Vector2()
23602 function SpriteMaterial( parameters ) {
23604 Material.call( this );
23606 this.type = 'SpriteMaterial';
23608 this.color = new Color( 0xffffff );
23614 this.lights = false;
23616 this.setValues( parameters );
23620 SpriteMaterial.prototype = Object.create( Material.prototype );
23621 SpriteMaterial.prototype.constructor = SpriteMaterial;
23622 SpriteMaterial.prototype.isSpriteMaterial = true;
23624 SpriteMaterial.prototype.copy = function ( source ) {
23626 Material.prototype.copy.call( this, source );
23628 this.color.copy( source.color );
23629 this.map = source.map;
23631 this.rotation = source.rotation;
23638 * @author mikael emtinger / http://gomo.se/
23639 * @author alteredq / http://alteredqualia.com/
23642 function Sprite( material ) {
23644 Object3D.call( this );
23646 this.type = 'Sprite';
23648 this.material = ( material !== undefined ) ? material : new SpriteMaterial();
23652 Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
23654 constructor: Sprite,
23658 raycast: ( function () {
23660 var intersectPoint = new Vector3();
23661 var worldPosition = new Vector3();
23662 var worldScale = new Vector3();
23664 return function raycast( raycaster, intersects ) {
23666 worldPosition.setFromMatrixPosition( this.matrixWorld );
23667 raycaster.ray.closestPointToPoint( worldPosition, intersectPoint );
23669 worldScale.setFromMatrixScale( this.matrixWorld );
23670 var guessSizeSq = worldScale.x * worldScale.y / 4;
23672 if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;
23674 var distance = raycaster.ray.origin.distanceTo( intersectPoint );
23676 if ( distance < raycaster.near || distance > raycaster.far ) return;
23680 distance: distance,
23681 point: intersectPoint.clone(),
23691 clone: function () {
23693 return new this.constructor( this.material ).copy( this );
23700 * @author mikael emtinger / http://gomo.se/
23701 * @author alteredq / http://alteredqualia.com/
23702 * @author mrdoob / http://mrdoob.com/
23707 Object3D.call( this );
23711 Object.defineProperties( this, {
23720 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
23724 copy: function ( source ) {
23726 Object3D.prototype.copy.call( this, source, false );
23728 var levels = source.levels;
23730 for ( var i = 0, l = levels.length; i < l; i ++ ) {
23732 var level = levels[ i ];
23734 this.addLevel( level.object.clone(), level.distance );
23742 addLevel: function ( object, distance ) {
23744 if ( distance === undefined ) distance = 0;
23746 distance = Math.abs( distance );
23748 var levels = this.levels;
23750 for ( var l = 0; l < levels.length; l ++ ) {
23752 if ( distance < levels[ l ].distance ) {
23760 levels.splice( l, 0, { distance: distance, object: object } );
23762 this.add( object );
23766 getObjectForDistance: function ( distance ) {
23768 var levels = this.levels;
23770 for ( var i = 1, l = levels.length; i < l; i ++ ) {
23772 if ( distance < levels[ i ].distance ) {
23780 return levels[ i - 1 ].object;
23784 raycast: ( function () {
23786 var matrixPosition = new Vector3();
23788 return function raycast( raycaster, intersects ) {
23790 matrixPosition.setFromMatrixPosition( this.matrixWorld );
23792 var distance = raycaster.ray.origin.distanceTo( matrixPosition );
23794 this.getObjectForDistance( distance ).raycast( raycaster, intersects );
23800 update: function () {
23802 var v1 = new Vector3();
23803 var v2 = new Vector3();
23805 return function update( camera ) {
23807 var levels = this.levels;
23809 if ( levels.length > 1 ) {
23811 v1.setFromMatrixPosition( camera.matrixWorld );
23812 v2.setFromMatrixPosition( this.matrixWorld );
23814 var distance = v1.distanceTo( v2 );
23816 levels[ 0 ].object.visible = true;
23818 for ( var i = 1, l = levels.length; i < l; i ++ ) {
23820 if ( distance >= levels[ i ].distance ) {
23822 levels[ i - 1 ].object.visible = false;
23823 levels[ i ].object.visible = true;
23833 for ( ; i < l; i ++ ) {
23835 levels[ i ].object.visible = false;
23845 toJSON: function ( meta ) {
23847 var data = Object3D.prototype.toJSON.call( this, meta );
23849 data.object.levels = [];
23851 var levels = this.levels;
23853 for ( var i = 0, l = levels.length; i < l; i ++ ) {
23855 var level = levels[ i ];
23857 data.object.levels.push( {
23858 object: level.object.uuid,
23859 distance: level.distance
23871 * @author mikael emtinger / http://gomo.se/
23872 * @author alteredq / http://alteredqualia.com/
23873 * @author michael guerrero / http://realitymeltdown.com
23874 * @author ikerr / http://verold.com
23877 function Skeleton( bones, boneInverses ) {
23879 // copy the bone array
23881 bones = bones || [];
23883 this.bones = bones.slice( 0 );
23884 this.boneMatrices = new Float32Array( this.bones.length * 16 );
23886 // use the supplied bone inverses or calculate the inverses
23888 if ( boneInverses === undefined ) {
23890 this.calculateInverses();
23894 if ( this.bones.length === boneInverses.length ) {
23896 this.boneInverses = boneInverses.slice( 0 );
23900 console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );
23902 this.boneInverses = [];
23904 for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
23906 this.boneInverses.push( new Matrix4() );
23916 Object.assign( Skeleton.prototype, {
23918 calculateInverses: function () {
23920 this.boneInverses = [];
23922 for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
23924 var inverse = new Matrix4();
23926 if ( this.bones[ i ] ) {
23928 inverse.getInverse( this.bones[ i ].matrixWorld );
23932 this.boneInverses.push( inverse );
23938 pose: function () {
23942 // recover the bind-time world matrices
23944 for ( i = 0, il = this.bones.length; i < il; i ++ ) {
23946 bone = this.bones[ i ];
23950 bone.matrixWorld.getInverse( this.boneInverses[ i ] );
23956 // compute the local matrices, positions, rotations and scales
23958 for ( i = 0, il = this.bones.length; i < il; i ++ ) {
23960 bone = this.bones[ i ];
23964 if ( bone.parent && bone.parent.isBone ) {
23966 bone.matrix.getInverse( bone.parent.matrixWorld );
23967 bone.matrix.multiply( bone.matrixWorld );
23971 bone.matrix.copy( bone.matrixWorld );
23975 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
23983 update: ( function () {
23985 var offsetMatrix = new Matrix4();
23986 var identityMatrix = new Matrix4();
23988 return function update() {
23990 var bones = this.bones;
23991 var boneInverses = this.boneInverses;
23992 var boneMatrices = this.boneMatrices;
23993 var boneTexture = this.boneTexture;
23995 // flatten bone matrices to array
23997 for ( var i = 0, il = bones.length; i < il; i ++ ) {
23999 // compute the offset between the current and the original transform
24001 var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix;
24003 offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
24004 offsetMatrix.toArray( boneMatrices, i * 16 );
24008 if ( boneTexture !== undefined ) {
24010 boneTexture.needsUpdate = true;
24018 clone: function () {
24020 return new Skeleton( this.bones, this.boneInverses );
24027 * @author mikael emtinger / http://gomo.se/
24028 * @author alteredq / http://alteredqualia.com/
24029 * @author ikerr / http://verold.com
24034 Object3D.call( this );
24036 this.type = 'Bone';
24040 Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
24049 * @author mikael emtinger / http://gomo.se/
24050 * @author alteredq / http://alteredqualia.com/
24051 * @author ikerr / http://verold.com
24054 function SkinnedMesh( geometry, material ) {
24056 Mesh.call( this, geometry, material );
24058 this.type = 'SkinnedMesh';
24060 this.bindMode = 'attached';
24061 this.bindMatrix = new Matrix4();
24062 this.bindMatrixInverse = new Matrix4();
24064 var bones = this.initBones();
24065 var skeleton = new Skeleton( bones );
24067 this.bind( skeleton, this.matrixWorld );
24069 this.normalizeSkinWeights();
24073 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
24075 constructor: SkinnedMesh,
24077 isSkinnedMesh: true,
24079 initBones: function () {
24081 var bones = [], bone, gbone;
24084 if ( this.geometry && this.geometry.bones !== undefined ) {
24086 // first, create array of 'Bone' objects from geometry data
24088 for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
24090 gbone = this.geometry.bones[ i ];
24092 // create new 'Bone' object
24095 bones.push( bone );
24099 bone.name = gbone.name;
24100 bone.position.fromArray( gbone.pos );
24101 bone.quaternion.fromArray( gbone.rotq );
24102 if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
24106 // second, create bone hierarchy
24108 for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
24110 gbone = this.geometry.bones[ i ];
24112 if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
24114 // subsequent bones in the hierarchy
24116 bones[ gbone.parent ].add( bones[ i ] );
24120 // topmost bone, immediate child of the skinned mesh
24122 this.add( bones[ i ] );
24130 // now the bones are part of the scene graph and children of the skinned mesh.
24131 // let's update the corresponding matrices
24133 this.updateMatrixWorld( true );
24139 bind: function ( skeleton, bindMatrix ) {
24141 this.skeleton = skeleton;
24143 if ( bindMatrix === undefined ) {
24145 this.updateMatrixWorld( true );
24147 this.skeleton.calculateInverses();
24149 bindMatrix = this.matrixWorld;
24153 this.bindMatrix.copy( bindMatrix );
24154 this.bindMatrixInverse.getInverse( bindMatrix );
24158 pose: function () {
24160 this.skeleton.pose();
24164 normalizeSkinWeights: function () {
24168 if ( this.geometry && this.geometry.isGeometry ) {
24170 for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {
24172 var sw = this.geometry.skinWeights[ i ];
24174 scale = 1.0 / sw.lengthManhattan();
24176 if ( scale !== Infinity ) {
24178 sw.multiplyScalar( scale );
24182 sw.set( 1, 0, 0, 0 ); // do something reasonable
24188 } else if ( this.geometry && this.geometry.isBufferGeometry ) {
24190 var vec = new Vector4();
24192 var skinWeight = this.geometry.attributes.skinWeight;
24194 for ( i = 0; i < skinWeight.count; i ++ ) {
24196 vec.x = skinWeight.getX( i );
24197 vec.y = skinWeight.getY( i );
24198 vec.z = skinWeight.getZ( i );
24199 vec.w = skinWeight.getW( i );
24201 scale = 1.0 / vec.lengthManhattan();
24203 if ( scale !== Infinity ) {
24205 vec.multiplyScalar( scale );
24209 vec.set( 1, 0, 0, 0 ); // do something reasonable
24213 skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );
24221 updateMatrixWorld: function ( force ) {
24223 Mesh.prototype.updateMatrixWorld.call( this, force );
24225 if ( this.bindMode === 'attached' ) {
24227 this.bindMatrixInverse.getInverse( this.matrixWorld );
24229 } else if ( this.bindMode === 'detached' ) {
24231 this.bindMatrixInverse.getInverse( this.bindMatrix );
24235 console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
24241 clone: function () {
24243 return new this.constructor( this.geometry, this.material ).copy( this );
24250 * @author mrdoob / http://mrdoob.com/
24251 * @author alteredq / http://alteredqualia.com/
24255 * opacity: <float>,
24257 * linewidth: <float>,
24258 * linecap: "round",
24259 * linejoin: "round"
24263 function LineBasicMaterial( parameters ) {
24265 Material.call( this );
24267 this.type = 'LineBasicMaterial';
24269 this.color = new Color( 0xffffff );
24271 this.linewidth = 1;
24272 this.linecap = 'round';
24273 this.linejoin = 'round';
24275 this.lights = false;
24277 this.setValues( parameters );
24281 LineBasicMaterial.prototype = Object.create( Material.prototype );
24282 LineBasicMaterial.prototype.constructor = LineBasicMaterial;
24284 LineBasicMaterial.prototype.isLineBasicMaterial = true;
24286 LineBasicMaterial.prototype.copy = function ( source ) {
24288 Material.prototype.copy.call( this, source );
24290 this.color.copy( source.color );
24292 this.linewidth = source.linewidth;
24293 this.linecap = source.linecap;
24294 this.linejoin = source.linejoin;
24301 * @author mrdoob / http://mrdoob.com/
24304 function Line( geometry, material, mode ) {
24306 if ( mode === 1 ) {
24308 console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );
24309 return new LineSegments( geometry, material );
24313 Object3D.call( this );
24315 this.type = 'Line';
24317 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
24318 this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );
24322 Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
24328 raycast: ( function () {
24330 var inverseMatrix = new Matrix4();
24331 var ray = new Ray();
24332 var sphere = new Sphere();
24334 return function raycast( raycaster, intersects ) {
24336 var precision = raycaster.linePrecision;
24337 var precisionSq = precision * precision;
24339 var geometry = this.geometry;
24340 var matrixWorld = this.matrixWorld;
24342 // Checking boundingSphere distance to ray
24344 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
24346 sphere.copy( geometry.boundingSphere );
24347 sphere.applyMatrix4( matrixWorld );
24349 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
24353 inverseMatrix.getInverse( matrixWorld );
24354 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
24356 var vStart = new Vector3();
24357 var vEnd = new Vector3();
24358 var interSegment = new Vector3();
24359 var interRay = new Vector3();
24360 var step = (this && this.isLineSegments) ? 2 : 1;
24362 if ( geometry.isBufferGeometry ) {
24364 var index = geometry.index;
24365 var attributes = geometry.attributes;
24366 var positions = attributes.position.array;
24368 if ( index !== null ) {
24370 var indices = index.array;
24372 for ( var i = 0, l = indices.length - 1; i < l; i += step ) {
24374 var a = indices[ i ];
24375 var b = indices[ i + 1 ];
24377 vStart.fromArray( positions, a * 3 );
24378 vEnd.fromArray( positions, b * 3 );
24380 var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
24382 if ( distSq > precisionSq ) continue;
24384 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
24386 var distance = raycaster.ray.origin.distanceTo( interRay );
24388 if ( distance < raycaster.near || distance > raycaster.far ) continue;
24392 distance: distance,
24393 // What do we want? intersection point on the ray or on the segment??
24394 // point: raycaster.ray.at( distance ),
24395 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
24407 for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {
24409 vStart.fromArray( positions, 3 * i );
24410 vEnd.fromArray( positions, 3 * i + 3 );
24412 var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
24414 if ( distSq > precisionSq ) continue;
24416 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
24418 var distance = raycaster.ray.origin.distanceTo( interRay );
24420 if ( distance < raycaster.near || distance > raycaster.far ) continue;
24424 distance: distance,
24425 // What do we want? intersection point on the ray or on the segment??
24426 // point: raycaster.ray.at( distance ),
24427 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
24439 } else if ( geometry.isGeometry ) {
24441 var vertices = geometry.vertices;
24442 var nbVertices = vertices.length;
24444 for ( var i = 0; i < nbVertices - 1; i += step ) {
24446 var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
24448 if ( distSq > precisionSq ) continue;
24450 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
24452 var distance = raycaster.ray.origin.distanceTo( interRay );
24454 if ( distance < raycaster.near || distance > raycaster.far ) continue;
24458 distance: distance,
24459 // What do we want? intersection point on the ray or on the segment??
24460 // point: raycaster.ray.at( distance ),
24461 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
24477 clone: function () {
24479 return new this.constructor( this.geometry, this.material ).copy( this );
24486 * @author mrdoob / http://mrdoob.com/
24489 function LineSegments( geometry, material ) {
24491 Line.call( this, geometry, material );
24493 this.type = 'LineSegments';
24497 LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
24499 constructor: LineSegments,
24501 isLineSegments: true
24506 * @author mgreter / http://github.com/mgreter
24509 function LineLoop( geometry, material ) {
24511 Line.call( this, geometry, material );
24513 this.type = 'LineLoop';
24517 LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
24519 constructor: LineLoop,
24526 * @author mrdoob / http://mrdoob.com/
24527 * @author alteredq / http://alteredqualia.com/
24531 * opacity: <float>,
24532 * map: new THREE.Texture( <Image> ),
24535 * sizeAttenuation: <bool>
24539 function PointsMaterial( parameters ) {
24541 Material.call( this );
24543 this.type = 'PointsMaterial';
24545 this.color = new Color( 0xffffff );
24550 this.sizeAttenuation = true;
24552 this.lights = false;
24554 this.setValues( parameters );
24558 PointsMaterial.prototype = Object.create( Material.prototype );
24559 PointsMaterial.prototype.constructor = PointsMaterial;
24561 PointsMaterial.prototype.isPointsMaterial = true;
24563 PointsMaterial.prototype.copy = function ( source ) {
24565 Material.prototype.copy.call( this, source );
24567 this.color.copy( source.color );
24569 this.map = source.map;
24571 this.size = source.size;
24572 this.sizeAttenuation = source.sizeAttenuation;
24579 * @author alteredq / http://alteredqualia.com/
24582 function Points( geometry, material ) {
24584 Object3D.call( this );
24586 this.type = 'Points';
24588 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
24589 this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );
24593 Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
24595 constructor: Points,
24599 raycast: ( function () {
24601 var inverseMatrix = new Matrix4();
24602 var ray = new Ray();
24603 var sphere = new Sphere();
24605 return function raycast( raycaster, intersects ) {
24608 var geometry = this.geometry;
24609 var matrixWorld = this.matrixWorld;
24610 var threshold = raycaster.params.Points.threshold;
24612 // Checking boundingSphere distance to ray
24614 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
24616 sphere.copy( geometry.boundingSphere );
24617 sphere.applyMatrix4( matrixWorld );
24618 sphere.radius += threshold;
24620 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
24624 inverseMatrix.getInverse( matrixWorld );
24625 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
24627 var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
24628 var localThresholdSq = localThreshold * localThreshold;
24629 var position = new Vector3();
24631 function testPoint( point, index ) {
24633 var rayPointDistanceSq = ray.distanceSqToPoint( point );
24635 if ( rayPointDistanceSq < localThresholdSq ) {
24637 var intersectPoint = ray.closestPointToPoint( point );
24638 intersectPoint.applyMatrix4( matrixWorld );
24640 var distance = raycaster.ray.origin.distanceTo( intersectPoint );
24642 if ( distance < raycaster.near || distance > raycaster.far ) return;
24646 distance: distance,
24647 distanceToRay: Math.sqrt( rayPointDistanceSq ),
24648 point: intersectPoint.clone(),
24659 if ( geometry.isBufferGeometry ) {
24661 var index = geometry.index;
24662 var attributes = geometry.attributes;
24663 var positions = attributes.position.array;
24665 if ( index !== null ) {
24667 var indices = index.array;
24669 for ( var i = 0, il = indices.length; i < il; i ++ ) {
24671 var a = indices[ i ];
24673 position.fromArray( positions, a * 3 );
24675 testPoint( position, a );
24681 for ( var i = 0, l = positions.length / 3; i < l; i ++ ) {
24683 position.fromArray( positions, i * 3 );
24685 testPoint( position, i );
24693 var vertices = geometry.vertices;
24695 for ( var i = 0, l = vertices.length; i < l; i ++ ) {
24697 testPoint( vertices[ i ], i );
24707 clone: function () {
24709 return new this.constructor( this.geometry, this.material ).copy( this );
24716 * @author mrdoob / http://mrdoob.com/
24721 Object3D.call( this );
24723 this.type = 'Group';
24727 Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
24734 * @author mrdoob / http://mrdoob.com/
24737 function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
24739 Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
24741 this.generateMipmaps = false;
24745 function update() {
24747 requestAnimationFrame( update );
24749 if ( video.readyState >= video.HAVE_CURRENT_DATA ) {
24751 scope.needsUpdate = true;
24761 VideoTexture.prototype = Object.create( Texture.prototype );
24762 VideoTexture.prototype.constructor = VideoTexture;
24765 * @author alteredq / http://alteredqualia.com/
24768 function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
24770 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
24772 this.image = { width: width, height: height };
24773 this.mipmaps = mipmaps;
24775 // no flipping for cube textures
24776 // (also flipping doesn't work for compressed textures )
24778 this.flipY = false;
24780 // can't generate mipmaps for compressed textures
24781 // mips must be embedded in DDS files
24783 this.generateMipmaps = false;
24787 CompressedTexture.prototype = Object.create( Texture.prototype );
24788 CompressedTexture.prototype.constructor = CompressedTexture;
24790 CompressedTexture.prototype.isCompressedTexture = true;
24793 * @author Matt DesLauriers / @mattdesl
24794 * @author atix / arthursilber.de
24797 function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
24799 format = format !== undefined ? format : DepthFormat;
24801 if ( format !== DepthFormat && format !== DepthStencilFormat ) {
24803 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
24807 if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
24808 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
24810 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
24812 this.image = { width: width, height: height };
24814 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
24815 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
24817 this.flipY = false;
24818 this.generateMipmaps = false;
24822 DepthTexture.prototype = Object.create( Texture.prototype );
24823 DepthTexture.prototype.constructor = DepthTexture;
24824 DepthTexture.prototype.isDepthTexture = true;
24827 * @author mrdoob / http://mrdoob.com/
24828 * @author Mugen87 / https://github.com/Mugen87
24831 function WireframeGeometry( geometry ) {
24833 BufferGeometry.call( this );
24835 this.type = 'WireframeGeometry';
24841 // helper variables
24843 var i, j, l, o, ol;
24844 var edge = [ 0, 0 ], edges = {}, e, edge1, edge2;
24845 var key, keys = [ 'a', 'b', 'c' ];
24848 // different logic for Geometry and BufferGeometry
24850 if ( geometry && geometry.isGeometry ) {
24852 // create a data structure that contains all edges without duplicates
24854 var faces = geometry.faces;
24856 for ( i = 0, l = faces.length; i < l; i ++ ) {
24858 var face = faces[ i ];
24860 for ( j = 0; j < 3; j ++ ) {
24862 edge1 = face[ keys[ j ] ];
24863 edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
24864 edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
24865 edge[ 1 ] = Math.max( edge1, edge2 );
24867 key = edge[ 0 ] + ',' + edge[ 1 ];
24869 if ( edges[ key ] === undefined ) {
24871 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
24879 // generate vertices
24881 for ( key in edges ) {
24885 vertex = geometry.vertices[ e.index1 ];
24886 vertices.push( vertex.x, vertex.y, vertex.z );
24888 vertex = geometry.vertices[ e.index2 ];
24889 vertices.push( vertex.x, vertex.y, vertex.z );
24893 } else if ( geometry && geometry.isBufferGeometry ) {
24895 var position, indices, groups;
24896 var group, start, count;
24897 var index1, index2;
24899 vertex = new Vector3();
24901 if ( geometry.index !== null ) {
24903 // indexed BufferGeometry
24905 position = geometry.attributes.position;
24906 indices = geometry.index;
24907 groups = geometry.groups;
24909 if ( groups.length === 0 ) {
24911 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
24915 // create a data structure that contains all eges without duplicates
24917 for ( o = 0, ol = groups.length; o < ol; ++ o ) {
24919 group = groups[ o ];
24921 start = group.start;
24922 count = group.count;
24924 for ( i = start, l = ( start + count ); i < l; i += 3 ) {
24926 for ( j = 0; j < 3; j ++ ) {
24928 edge1 = indices.getX( i + j );
24929 edge2 = indices.getX( i + ( j + 1 ) % 3 );
24930 edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
24931 edge[ 1 ] = Math.max( edge1, edge2 );
24933 key = edge[ 0 ] + ',' + edge[ 1 ];
24935 if ( edges[ key ] === undefined ) {
24937 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
24947 // generate vertices
24949 for ( key in edges ) {
24953 vertex.fromBufferAttribute( position, e.index1 );
24954 vertices.push( vertex.x, vertex.y, vertex.z );
24956 vertex.fromBufferAttribute( position, e.index2 );
24957 vertices.push( vertex.x, vertex.y, vertex.z );
24963 // non-indexed BufferGeometry
24965 position = geometry.attributes.position;
24967 for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
24969 for ( j = 0; j < 3; j ++ ) {
24971 // three edges per triangle, an edge is represented as (index1, index2)
24972 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
24974 index1 = 3 * i + j;
24975 vertex.fromBufferAttribute( position, index1 );
24976 vertices.push( vertex.x, vertex.y, vertex.z );
24978 index2 = 3 * i + ( ( j + 1 ) % 3 );
24979 vertex.fromBufferAttribute( position, index2 );
24980 vertices.push( vertex.x, vertex.y, vertex.z );
24992 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
24996 WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
24997 WireframeGeometry.prototype.constructor = WireframeGeometry;
25000 * @author zz85 / https://github.com/zz85
25001 * @author Mugen87 / https://github.com/Mugen87
25003 * Parametric Surfaces Geometry
25004 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
25007 // ParametricGeometry
25009 function ParametricGeometry( func, slices, stacks ) {
25011 Geometry.call( this );
25013 this.type = 'ParametricGeometry';
25015 this.parameters = {
25021 this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
25022 this.mergeVertices();
25026 ParametricGeometry.prototype = Object.create( Geometry.prototype );
25027 ParametricGeometry.prototype.constructor = ParametricGeometry;
25029 // ParametricBufferGeometry
25031 function ParametricBufferGeometry( func, slices, stacks ) {
25033 BufferGeometry.call( this );
25035 this.type = 'ParametricBufferGeometry';
25037 this.parameters = {
25052 var normal = new Vector3();
25054 var p0 = new Vector3(), p1 = new Vector3();
25055 var pu = new Vector3(), pv = new Vector3();
25059 // generate vertices, normals and uvs
25061 var sliceCount = slices + 1;
25063 for ( i = 0; i <= stacks; i ++ ) {
25065 var v = i / stacks;
25067 for ( j = 0; j <= slices; j ++ ) {
25069 var u = j / slices;
25073 p0 = func( u, v, p0 );
25074 vertices.push( p0.x, p0.y, p0.z );
25078 // approximate tangent vectors via finite differences
25080 if ( u - EPS >= 0 ) {
25082 p1 = func( u - EPS, v, p1 );
25083 pu.subVectors( p0, p1 );
25087 p1 = func( u + EPS, v, p1 );
25088 pu.subVectors( p1, p0 );
25092 if ( v - EPS >= 0 ) {
25094 p1 = func( u, v - EPS, p1 );
25095 pv.subVectors( p0, p1 );
25099 p1 = func( u, v + EPS, p1 );
25100 pv.subVectors( p1, p0 );
25104 // cross product of tangent vectors returns surface normal
25106 normal.crossVectors( pu, pv ).normalize();
25107 normals.push( normal.x, normal.y, normal.z );
25117 // generate indices
25119 for ( i = 0; i < stacks; i ++ ) {
25121 for ( j = 0; j < slices; j ++ ) {
25123 var a = i * sliceCount + j;
25124 var b = i * sliceCount + j + 1;
25125 var c = ( i + 1 ) * sliceCount + j + 1;
25126 var d = ( i + 1 ) * sliceCount + j;
25128 // faces one and two
25130 indices.push( a, b, d );
25131 indices.push( b, c, d );
25139 this.setIndex( indices );
25140 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
25141 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
25142 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
25146 ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
25147 ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
25150 * @author clockworkgeek / https://github.com/clockworkgeek
25151 * @author timothypratley / https://github.com/timothypratley
25152 * @author WestLangley / http://github.com/WestLangley
25153 * @author Mugen87 / https://github.com/Mugen87
25156 // PolyhedronGeometry
25158 function PolyhedronGeometry( vertices, indices, radius, detail ) {
25160 Geometry.call( this );
25162 this.type = 'PolyhedronGeometry';
25164 this.parameters = {
25165 vertices: vertices,
25171 this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
25172 this.mergeVertices();
25176 PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
25177 PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
25179 // PolyhedronBufferGeometry
25181 function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
25183 BufferGeometry.call( this );
25185 this.type = 'PolyhedronBufferGeometry';
25187 this.parameters = {
25188 vertices: vertices,
25194 radius = radius || 1;
25195 detail = detail || 0;
25197 // default buffer data
25199 var vertexBuffer = [];
25202 // the subdivision creates the vertex buffer data
25204 subdivide( detail );
25206 // all vertices should lie on a conceptual sphere with a given radius
25208 appplyRadius( radius );
25210 // finally, create the uv data
25214 // build non-indexed geometry
25216 this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
25217 this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
25218 this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
25220 if ( detail === 0 ) {
25222 this.computeVertexNormals(); // flat normals
25226 this.normalizeNormals(); // smooth normals
25230 // helper functions
25232 function subdivide( detail ) {
25234 var a = new Vector3();
25235 var b = new Vector3();
25236 var c = new Vector3();
25238 // iterate over all faces and apply a subdivison with the given detail value
25240 for ( var i = 0; i < indices.length; i += 3 ) {
25242 // get the vertices of the face
25244 getVertexByIndex( indices[ i + 0 ], a );
25245 getVertexByIndex( indices[ i + 1 ], b );
25246 getVertexByIndex( indices[ i + 2 ], c );
25248 // perform subdivision
25250 subdivideFace( a, b, c, detail );
25256 function subdivideFace( a, b, c, detail ) {
25258 var cols = Math.pow( 2, detail );
25260 // we use this multidimensional array as a data structure for creating the subdivision
25266 // construct all of the vertices for this subdivision
25268 for ( i = 0; i <= cols; i ++ ) {
25272 var aj = a.clone().lerp( c, i / cols );
25273 var bj = b.clone().lerp( c, i / cols );
25275 var rows = cols - i;
25277 for ( j = 0; j <= rows; j ++ ) {
25279 if ( j === 0 && i === cols ) {
25285 v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
25293 // construct all of the faces
25295 for ( i = 0; i < cols; i ++ ) {
25297 for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
25299 var k = Math.floor( j / 2 );
25301 if ( j % 2 === 0 ) {
25303 pushVertex( v[ i ][ k + 1 ] );
25304 pushVertex( v[ i + 1 ][ k ] );
25305 pushVertex( v[ i ][ k ] );
25309 pushVertex( v[ i ][ k + 1 ] );
25310 pushVertex( v[ i + 1 ][ k + 1 ] );
25311 pushVertex( v[ i + 1 ][ k ] );
25321 function appplyRadius( radius ) {
25323 var vertex = new Vector3();
25325 // iterate over the entire buffer and apply the radius to each vertex
25327 for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
25329 vertex.x = vertexBuffer[ i + 0 ];
25330 vertex.y = vertexBuffer[ i + 1 ];
25331 vertex.z = vertexBuffer[ i + 2 ];
25333 vertex.normalize().multiplyScalar( radius );
25335 vertexBuffer[ i + 0 ] = vertex.x;
25336 vertexBuffer[ i + 1 ] = vertex.y;
25337 vertexBuffer[ i + 2 ] = vertex.z;
25343 function generateUVs() {
25345 var vertex = new Vector3();
25347 for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
25349 vertex.x = vertexBuffer[ i + 0 ];
25350 vertex.y = vertexBuffer[ i + 1 ];
25351 vertex.z = vertexBuffer[ i + 2 ];
25353 var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
25354 var v = inclination( vertex ) / Math.PI + 0.5;
25355 uvBuffer.push( u, 1 - v );
25365 function correctSeam() {
25367 // handle case when face straddles the seam, see #3269
25369 for ( var i = 0; i < uvBuffer.length; i += 6 ) {
25371 // uv data of a single face
25373 var x0 = uvBuffer[ i + 0 ];
25374 var x1 = uvBuffer[ i + 2 ];
25375 var x2 = uvBuffer[ i + 4 ];
25377 var max = Math.max( x0, x1, x2 );
25378 var min = Math.min( x0, x1, x2 );
25380 // 0.9 is somewhat arbitrary
25382 if ( max > 0.9 && min < 0.1 ) {
25384 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
25385 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
25386 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
25394 function pushVertex( vertex ) {
25396 vertexBuffer.push( vertex.x, vertex.y, vertex.z );
25400 function getVertexByIndex( index, vertex ) {
25402 var stride = index * 3;
25404 vertex.x = vertices[ stride + 0 ];
25405 vertex.y = vertices[ stride + 1 ];
25406 vertex.z = vertices[ stride + 2 ];
25410 function correctUVs() {
25412 var a = new Vector3();
25413 var b = new Vector3();
25414 var c = new Vector3();
25416 var centroid = new Vector3();
25418 var uvA = new Vector2();
25419 var uvB = new Vector2();
25420 var uvC = new Vector2();
25422 for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
25424 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
25425 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
25426 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
25428 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
25429 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
25430 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
25432 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
25434 var azi = azimuth( centroid );
25436 correctUV( uvA, j + 0, a, azi );
25437 correctUV( uvB, j + 2, b, azi );
25438 correctUV( uvC, j + 4, c, azi );
25444 function correctUV( uv, stride, vector, azimuth ) {
25446 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
25448 uvBuffer[ stride ] = uv.x - 1;
25452 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
25454 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
25460 // Angle around the Y axis, counter-clockwise when looking from above.
25462 function azimuth( vector ) {
25464 return Math.atan2( vector.z, - vector.x );
25469 // Angle above the XZ plane.
25471 function inclination( vector ) {
25473 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
25479 PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
25480 PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
25483 * @author timothypratley / https://github.com/timothypratley
25484 * @author Mugen87 / https://github.com/Mugen87
25487 // TetrahedronGeometry
25489 function TetrahedronGeometry( radius, detail ) {
25491 Geometry.call( this );
25493 this.type = 'TetrahedronGeometry';
25495 this.parameters = {
25500 this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
25501 this.mergeVertices();
25505 TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
25506 TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
25508 // TetrahedronBufferGeometry
25510 function TetrahedronBufferGeometry( radius, detail ) {
25513 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
25517 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
25520 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
25522 this.type = 'TetrahedronBufferGeometry';
25524 this.parameters = {
25531 TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
25532 TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
25535 * @author timothypratley / https://github.com/timothypratley
25536 * @author Mugen87 / https://github.com/Mugen87
25539 // OctahedronGeometry
25541 function OctahedronGeometry( radius, detail ) {
25543 Geometry.call( this );
25545 this.type = 'OctahedronGeometry';
25547 this.parameters = {
25552 this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
25553 this.mergeVertices();
25557 OctahedronGeometry.prototype = Object.create( Geometry.prototype );
25558 OctahedronGeometry.prototype.constructor = OctahedronGeometry;
25560 // OctahedronBufferGeometry
25562 function OctahedronBufferGeometry( radius, detail ) {
25565 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1
25569 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2
25572 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
25574 this.type = 'OctahedronBufferGeometry';
25576 this.parameters = {
25583 OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
25584 OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
25587 * @author timothypratley / https://github.com/timothypratley
25588 * @author Mugen87 / https://github.com/Mugen87
25591 // IcosahedronGeometry
25593 function IcosahedronGeometry( radius, detail ) {
25595 Geometry.call( this );
25597 this.type = 'IcosahedronGeometry';
25599 this.parameters = {
25604 this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
25605 this.mergeVertices();
25609 IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
25610 IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
25612 // IcosahedronBufferGeometry
25614 function IcosahedronBufferGeometry( radius, detail ) {
25616 var t = ( 1 + Math.sqrt( 5 ) ) / 2;
25619 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
25620 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
25621 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
25625 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
25626 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
25627 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
25628 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
25631 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
25633 this.type = 'IcosahedronBufferGeometry';
25635 this.parameters = {
25642 IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
25643 IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
25646 * @author Abe Pazos / https://hamoid.com
25647 * @author Mugen87 / https://github.com/Mugen87
25650 // DodecahedronGeometry
25652 function DodecahedronGeometry( radius, detail ) {
25654 Geometry.call( this );
25656 this.type = 'DodecahedronGeometry';
25658 this.parameters = {
25663 this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
25664 this.mergeVertices();
25668 DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
25669 DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
25671 // DodecahedronBufferGeometry
25673 function DodecahedronBufferGeometry( radius, detail ) {
25675 var t = ( 1 + Math.sqrt( 5 ) ) / 2;
25681 - 1, - 1, - 1, - 1, - 1, 1,
25682 - 1, 1, - 1, - 1, 1, 1,
25683 1, - 1, - 1, 1, - 1, 1,
25684 1, 1, - 1, 1, 1, 1,
25687 0, - r, - t, 0, - r, t,
25688 0, r, - t, 0, r, t,
25691 - r, - t, 0, - r, t, 0,
25692 r, - t, 0, r, t, 0,
25695 - t, 0, - r, t, 0, - r,
25700 3, 11, 7, 3, 7, 15, 3, 15, 13,
25701 7, 19, 17, 7, 17, 6, 7, 6, 15,
25702 17, 4, 8, 17, 8, 10, 17, 10, 6,
25703 8, 0, 16, 8, 16, 2, 8, 2, 10,
25704 0, 12, 1, 0, 1, 18, 0, 18, 16,
25705 6, 10, 2, 6, 2, 13, 6, 13, 15,
25706 2, 16, 18, 2, 18, 3, 2, 3, 13,
25707 18, 1, 9, 18, 9, 11, 18, 11, 3,
25708 4, 14, 12, 4, 12, 0, 4, 0, 8,
25709 11, 9, 5, 11, 5, 19, 11, 19, 7,
25710 19, 5, 14, 19, 14, 4, 19, 4, 17,
25711 1, 12, 14, 1, 14, 5, 1, 5, 9
25714 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
25716 this.type = 'DodecahedronBufferGeometry';
25718 this.parameters = {
25725 DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
25726 DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
25729 * @author oosmoxiecode / https://github.com/oosmoxiecode
25730 * @author WestLangley / https://github.com/WestLangley
25731 * @author zz85 / https://github.com/zz85
25732 * @author miningold / https://github.com/miningold
25733 * @author jonobr1 / https://github.com/jonobr1
25734 * @author Mugen87 / https://github.com/Mugen87
25740 function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
25742 Geometry.call( this );
25744 this.type = 'TubeGeometry';
25746 this.parameters = {
25748 tubularSegments: tubularSegments,
25750 radialSegments: radialSegments,
25754 if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
25756 var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
25758 // expose internals
25760 this.tangents = bufferGeometry.tangents;
25761 this.normals = bufferGeometry.normals;
25762 this.binormals = bufferGeometry.binormals;
25766 this.fromBufferGeometry( bufferGeometry );
25767 this.mergeVertices();
25771 TubeGeometry.prototype = Object.create( Geometry.prototype );
25772 TubeGeometry.prototype.constructor = TubeGeometry;
25774 // TubeBufferGeometry
25776 function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
25778 BufferGeometry.call( this );
25780 this.type = 'TubeBufferGeometry';
25782 this.parameters = {
25784 tubularSegments: tubularSegments,
25786 radialSegments: radialSegments,
25790 tubularSegments = tubularSegments || 64;
25791 radius = radius || 1;
25792 radialSegments = radialSegments || 8;
25793 closed = closed || false;
25795 var frames = path.computeFrenetFrames( tubularSegments, closed );
25797 // expose internals
25799 this.tangents = frames.tangents;
25800 this.normals = frames.normals;
25801 this.binormals = frames.binormals;
25803 // helper variables
25805 var vertex = new Vector3();
25806 var normal = new Vector3();
25807 var uv = new Vector2();
25818 // create buffer data
25820 generateBufferData();
25824 this.setIndex( indices );
25825 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
25826 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
25827 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
25831 function generateBufferData() {
25833 for ( i = 0; i < tubularSegments; i ++ ) {
25835 generateSegment( i );
25839 // if the geometry is not closed, generate the last row of vertices and normals
25840 // at the regular position on the given path
25842 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
25844 generateSegment( ( closed === false ) ? tubularSegments : 0 );
25846 // uvs are generated in a separate function.
25847 // this makes it easy compute correct values for closed geometries
25851 // finally create faces
25857 function generateSegment( i ) {
25859 // we use getPointAt to sample evenly distributed points from the given path
25861 var P = path.getPointAt( i / tubularSegments );
25863 // retrieve corresponding normal and binormal
25865 var N = frames.normals[ i ];
25866 var B = frames.binormals[ i ];
25868 // generate normals and vertices for the current segment
25870 for ( j = 0; j <= radialSegments; j ++ ) {
25872 var v = j / radialSegments * Math.PI * 2;
25874 var sin = Math.sin( v );
25875 var cos = - Math.cos( v );
25879 normal.x = ( cos * N.x + sin * B.x );
25880 normal.y = ( cos * N.y + sin * B.y );
25881 normal.z = ( cos * N.z + sin * B.z );
25882 normal.normalize();
25884 normals.push( normal.x, normal.y, normal.z );
25888 vertex.x = P.x + radius * normal.x;
25889 vertex.y = P.y + radius * normal.y;
25890 vertex.z = P.z + radius * normal.z;
25892 vertices.push( vertex.x, vertex.y, vertex.z );
25898 function generateIndices() {
25900 for ( j = 1; j <= tubularSegments; j ++ ) {
25902 for ( i = 1; i <= radialSegments; i ++ ) {
25904 var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
25905 var b = ( radialSegments + 1 ) * j + ( i - 1 );
25906 var c = ( radialSegments + 1 ) * j + i;
25907 var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
25911 indices.push( a, b, d );
25912 indices.push( b, c, d );
25920 function generateUVs() {
25922 for ( i = 0; i <= tubularSegments; i ++ ) {
25924 for ( j = 0; j <= radialSegments; j ++ ) {
25926 uv.x = i / tubularSegments;
25927 uv.y = j / radialSegments;
25929 uvs.push( uv.x, uv.y );
25939 TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
25940 TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
25943 * @author oosmoxiecode
25944 * @author Mugen87 / https://github.com/Mugen87
25946 * based on http://www.blackpawn.com/texts/pqtorus/
25949 // TorusKnotGeometry
25951 function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
25953 Geometry.call( this );
25955 this.type = 'TorusKnotGeometry';
25957 this.parameters = {
25960 tubularSegments: tubularSegments,
25961 radialSegments: radialSegments,
25966 if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
25968 this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
25969 this.mergeVertices();
25973 TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
25974 TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
25976 // TorusKnotBufferGeometry
25978 function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {
25980 BufferGeometry.call( this );
25982 this.type = 'TorusKnotBufferGeometry';
25984 this.parameters = {
25987 tubularSegments: tubularSegments,
25988 radialSegments: radialSegments,
25993 radius = radius || 100;
25995 tubularSegments = Math.floor( tubularSegments ) || 64;
25996 radialSegments = Math.floor( radialSegments ) || 8;
26007 // helper variables
26011 var vertex = new Vector3();
26012 var normal = new Vector3();
26014 var P1 = new Vector3();
26015 var P2 = new Vector3();
26017 var B = new Vector3();
26018 var T = new Vector3();
26019 var N = new Vector3();
26021 // generate vertices, normals and uvs
26023 for ( i = 0; i <= tubularSegments; ++ i ) {
26025 // the radian "u" is used to calculate the position on the torus curve of the current tubular segement
26027 var u = i / tubularSegments * p * Math.PI * 2;
26029 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
26030 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
26032 calculatePositionOnCurve( u, p, q, radius, P1 );
26033 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
26035 // calculate orthonormal basis
26037 T.subVectors( P2, P1 );
26038 N.addVectors( P2, P1 );
26039 B.crossVectors( T, N );
26040 N.crossVectors( B, T );
26042 // normalize B, N. T can be ignored, we don't use it
26047 for ( j = 0; j <= radialSegments; ++ j ) {
26049 // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
26050 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
26052 var v = j / radialSegments * Math.PI * 2;
26053 var cx = - tube * Math.cos( v );
26054 var cy = tube * Math.sin( v );
26056 // now calculate the final vertex position.
26057 // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
26059 vertex.x = P1.x + ( cx * N.x + cy * B.x );
26060 vertex.y = P1.y + ( cx * N.y + cy * B.y );
26061 vertex.z = P1.z + ( cx * N.z + cy * B.z );
26063 vertices.push( vertex.x, vertex.y, vertex.z );
26065 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
26067 normal.subVectors( vertex, P1 ).normalize();
26069 normals.push( normal.x, normal.y, normal.z );
26073 uvs.push( i / tubularSegments );
26074 uvs.push( j / radialSegments );
26080 // generate indices
26082 for ( j = 1; j <= tubularSegments; j ++ ) {
26084 for ( i = 1; i <= radialSegments; i ++ ) {
26088 var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
26089 var b = ( radialSegments + 1 ) * j + ( i - 1 );
26090 var c = ( radialSegments + 1 ) * j + i;
26091 var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
26095 indices.push( a, b, d );
26096 indices.push( b, c, d );
26104 this.setIndex( indices );
26105 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
26106 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
26107 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
26109 // this function calculates the current position on the torus curve
26111 function calculatePositionOnCurve( u, p, q, radius, position ) {
26113 var cu = Math.cos( u );
26114 var su = Math.sin( u );
26115 var quOverP = q / p * u;
26116 var cs = Math.cos( quOverP );
26118 position.x = radius * ( 2 + cs ) * 0.5 * cu;
26119 position.y = radius * ( 2 + cs ) * su * 0.5;
26120 position.z = radius * Math.sin( quOverP ) * 0.5;
26126 TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
26127 TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
26130 * @author oosmoxiecode
26131 * @author mrdoob / http://mrdoob.com/
26132 * @author Mugen87 / https://github.com/Mugen87
26137 function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
26139 Geometry.call( this );
26141 this.type = 'TorusGeometry';
26143 this.parameters = {
26146 radialSegments: radialSegments,
26147 tubularSegments: tubularSegments,
26151 this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
26152 this.mergeVertices();
26156 TorusGeometry.prototype = Object.create( Geometry.prototype );
26157 TorusGeometry.prototype.constructor = TorusGeometry;
26159 // TorusBufferGeometry
26161 function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
26163 BufferGeometry.call( this );
26165 this.type = 'TorusBufferGeometry';
26167 this.parameters = {
26170 radialSegments: radialSegments,
26171 tubularSegments: tubularSegments,
26175 radius = radius || 100;
26177 radialSegments = Math.floor( radialSegments ) || 8;
26178 tubularSegments = Math.floor( tubularSegments ) || 6;
26179 arc = arc || Math.PI * 2;
26188 // helper variables
26190 var center = new Vector3();
26191 var vertex = new Vector3();
26192 var normal = new Vector3();
26196 // generate vertices, normals and uvs
26198 for ( j = 0; j <= radialSegments; j ++ ) {
26200 for ( i = 0; i <= tubularSegments; i ++ ) {
26202 var u = i / tubularSegments * arc;
26203 var v = j / radialSegments * Math.PI * 2;
26207 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
26208 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
26209 vertex.z = tube * Math.sin( v );
26211 vertices.push( vertex.x, vertex.y, vertex.z );
26215 center.x = radius * Math.cos( u );
26216 center.y = radius * Math.sin( u );
26217 normal.subVectors( vertex, center ).normalize();
26219 normals.push( normal.x, normal.y, normal.z );
26223 uvs.push( i / tubularSegments );
26224 uvs.push( j / radialSegments );
26230 // generate indices
26232 for ( j = 1; j <= radialSegments; j ++ ) {
26234 for ( i = 1; i <= tubularSegments; i ++ ) {
26238 var a = ( tubularSegments + 1 ) * j + i - 1;
26239 var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
26240 var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
26241 var d = ( tubularSegments + 1 ) * j + i;
26245 indices.push( a, b, d );
26246 indices.push( b, c, d );
26254 this.setIndex( indices );
26255 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
26256 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
26257 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
26261 TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
26262 TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
26265 * @author zz85 / http://www.lab4games.net/zz85/blog
26270 // calculate area of the contour polygon
26272 area: function ( contour ) {
26274 var n = contour.length;
26277 for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
26279 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
26287 triangulate: ( function () {
26290 * This code is a quick port of code written in C++ which was submitted to
26291 * flipcode.com by John W. Ratcliff // July 22, 2000
26292 * See original code and more information here:
26293 * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
26295 * ported to actionscript by Zevan Rosser
26296 * www.actionsnippet.com
26298 * ported to javascript by Joshua Koo
26299 * http://www.lab4games.net/zz85/blog
26303 function snip( contour, u, v, w, n, verts ) {
26306 var ax, ay, bx, by;
26307 var cx, cy, px, py;
26309 ax = contour[ verts[ u ] ].x;
26310 ay = contour[ verts[ u ] ].y;
26312 bx = contour[ verts[ v ] ].x;
26313 by = contour[ verts[ v ] ].y;
26315 cx = contour[ verts[ w ] ].x;
26316 cy = contour[ verts[ w ] ].y;
26318 if ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false;
26320 var aX, aY, bX, bY, cX, cY;
26321 var apx, apy, bpx, bpy, cpx, cpy;
26322 var cCROSSap, bCROSScp, aCROSSbp;
26324 aX = cx - bx; aY = cy - by;
26325 bX = ax - cx; bY = ay - cy;
26326 cX = bx - ax; cY = by - ay;
26328 for ( p = 0; p < n; p ++ ) {
26330 px = contour[ verts[ p ] ].x;
26331 py = contour[ verts[ p ] ].y;
26333 if ( ( ( px === ax ) && ( py === ay ) ) ||
26334 ( ( px === bx ) && ( py === by ) ) ||
26335 ( ( px === cx ) && ( py === cy ) ) ) continue;
26337 apx = px - ax; apy = py - ay;
26338 bpx = px - bx; bpy = py - by;
26339 cpx = px - cx; cpy = py - cy;
26341 // see if p is inside triangle abc
26343 aCROSSbp = aX * bpy - aY * bpx;
26344 cCROSSap = cX * apy - cY * apx;
26345 bCROSScp = bX * cpy - bY * cpx;
26347 if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false;
26355 // takes in an contour array and returns
26357 return function triangulate( contour, indices ) {
26359 var n = contour.length;
26361 if ( n < 3 ) return null;
26367 /* we want a counter-clockwise polygon in verts */
26371 if ( ShapeUtils.area( contour ) > 0.0 ) {
26373 for ( v = 0; v < n; v ++ ) verts[ v ] = v;
26377 for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;
26383 /* remove nv - 2 vertices, creating 1 triangle every time */
26385 var count = 2 * nv; /* error detection */
26387 for ( v = nv - 1; nv > 2; ) {
26389 /* if we loop, it is probably a non-simple polygon */
26391 if ( ( count -- ) <= 0 ) {
26393 //** Triangulate: ERROR - probable bad polygon!
26395 //throw ( "Warning, unable to triangulate polygon!" );
26397 // Sometimes warning is fine, especially polygons are triangulated in reverse.
26398 console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' );
26400 if ( indices ) return vertIndices;
26405 /* three consecutive vertices in current polygon, <u,v,w> */
26407 u = v; if ( nv <= u ) u = 0; /* previous */
26408 v = u + 1; if ( nv <= v ) v = 0; /* new v */
26409 w = v + 1; if ( nv <= w ) w = 0; /* next */
26411 if ( snip( contour, u, v, w, nv, verts ) ) {
26415 /* true names of the vertices */
26421 /* output Triangle */
26423 result.push( [ contour[ a ],
26428 vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
26430 /* remove v from the remaining polygon */
26432 for ( s = v, t = v + 1; t < nv; s ++, t ++ ) {
26434 verts[ s ] = verts[ t ];
26440 /* reset error detection counter */
26448 if ( indices ) return vertIndices;
26455 triangulateShape: function ( contour, holes ) {
26457 function removeDupEndPts(points) {
26459 var l = points.length;
26461 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
26469 removeDupEndPts( contour );
26470 holes.forEach( removeDupEndPts );
26472 function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
26474 // inOtherPt needs to be collinear to the inSegment
26475 if ( inSegPt1.x !== inSegPt2.x ) {
26477 if ( inSegPt1.x < inSegPt2.x ) {
26479 return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
26483 return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
26489 if ( inSegPt1.y < inSegPt2.y ) {
26491 return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
26495 return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
26503 function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
26505 var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
26506 var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;
26508 var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
26509 var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;
26511 var limit = seg1dy * seg2dx - seg1dx * seg2dy;
26512 var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;
26514 if ( Math.abs( limit ) > Number.EPSILON ) {
26521 if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return [];
26522 perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
26523 if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return [];
26527 if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return [];
26528 perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
26529 if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return [];
26533 // i.e. to reduce rounding errors
26534 // intersection at endpoint of segment#1?
26535 if ( perpSeg2 === 0 ) {
26537 if ( ( inExcludeAdjacentSegs ) &&
26538 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return [];
26539 return [ inSeg1Pt1 ];
26542 if ( perpSeg2 === limit ) {
26544 if ( ( inExcludeAdjacentSegs ) &&
26545 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return [];
26546 return [ inSeg1Pt2 ];
26549 // intersection at endpoint of segment#2?
26550 if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ];
26551 if ( perpSeg1 === limit ) return [ inSeg2Pt2 ];
26553 // return real intersection point
26554 var factorSeg1 = perpSeg2 / limit;
26555 return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
26556 y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];
26560 // parallel or collinear
26561 if ( ( perpSeg1 !== 0 ) ||
26562 ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return [];
26564 // they are collinear or degenerate
26565 var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point?
26566 var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point?
26567 // both segments are points
26568 if ( seg1Pt && seg2Pt ) {
26570 if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) ||
26571 ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points
26572 return [ inSeg1Pt1 ]; // they are the same point
26575 // segment#1 is a single point
26578 if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2
26579 return [ inSeg1Pt1 ];
26582 // segment#2 is a single point
26585 if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1
26586 return [ inSeg2Pt1 ];
26590 // they are collinear segments, which might overlap
26591 var seg1min, seg1max, seg1minVal, seg1maxVal;
26592 var seg2min, seg2max, seg2minVal, seg2maxVal;
26593 if ( seg1dx !== 0 ) {
26595 // the segments are NOT on a vertical line
26596 if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
26598 seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
26599 seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
26603 seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
26604 seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
26607 if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
26609 seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
26610 seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
26614 seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
26615 seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
26621 // the segments are on a vertical line
26622 if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
26624 seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
26625 seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
26629 seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
26630 seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
26633 if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
26635 seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
26636 seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
26640 seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
26641 seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
26646 if ( seg1minVal <= seg2minVal ) {
26648 if ( seg1maxVal < seg2minVal ) return [];
26649 if ( seg1maxVal === seg2minVal ) {
26651 if ( inExcludeAdjacentSegs ) return [];
26652 return [ seg2min ];
26655 if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ];
26656 return [ seg2min, seg2max ];
26660 if ( seg1minVal > seg2maxVal ) return [];
26661 if ( seg1minVal === seg2maxVal ) {
26663 if ( inExcludeAdjacentSegs ) return [];
26664 return [ seg1min ];
26667 if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ];
26668 return [ seg1min, seg2max ];
26676 function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
26678 // The order of legs is important
26680 // translation of all points, so that Vertex is at (0,0)
26681 var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y;
26682 var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y;
26683 var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y;
26685 // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
26686 var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX;
26687 var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX;
26689 if ( Math.abs( from2toAngle ) > Number.EPSILON ) {
26691 // angle != 180 deg.
26693 var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX;
26694 // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );
26696 if ( from2toAngle > 0 ) {
26698 // main angle < 180 deg.
26699 return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
26703 // main angle > 180 deg.
26704 return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
26710 // angle == 180 deg.
26711 // console.log( "from2to: 180 deg., from2other: " + from2otherAngle );
26712 return ( from2otherAngle > 0 );
26719 function removeHoles( contour, holes ) {
26721 var shape = contour.concat(); // work on this shape
26724 function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
26726 // Check if hole point lies within angle around shape point
26727 var lastShapeIdx = shape.length - 1;
26729 var prevShapeIdx = inShapeIdx - 1;
26730 if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx;
26732 var nextShapeIdx = inShapeIdx + 1;
26733 if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0;
26735 var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] );
26736 if ( ! insideAngle ) {
26738 // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
26743 // Check if shape point lies within angle around hole point
26744 var lastHoleIdx = hole.length - 1;
26746 var prevHoleIdx = inHoleIdx - 1;
26747 if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx;
26749 var nextHoleIdx = inHoleIdx + 1;
26750 if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0;
26752 insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] );
26753 if ( ! insideAngle ) {
26755 // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
26764 function intersectsShapeEdge( inShapePt, inHolePt ) {
26766 // checks for intersections with shape edges
26767 var sIdx, nextIdx, intersection;
26768 for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
26770 nextIdx = sIdx + 1; nextIdx %= shape.length;
26771 intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true );
26772 if ( intersection.length > 0 ) return true;
26780 var indepHoles = [];
26782 function intersectsHoleEdge( inShapePt, inHolePt ) {
26784 // checks for intersections with hole edges
26785 var ihIdx, chkHole,
26786 hIdx, nextIdx, intersection;
26787 for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
26789 chkHole = holes[ indepHoles[ ihIdx ] ];
26790 for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
26792 nextIdx = hIdx + 1; nextIdx %= chkHole.length;
26793 intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true );
26794 if ( intersection.length > 0 ) return true;
26803 var holeIndex, shapeIndex,
26805 holeIdx, cutKey, failedCuts = [],
26806 tmpShape1, tmpShape2,
26807 tmpHole1, tmpHole2;
26809 for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
26811 indepHoles.push( h );
26815 var minShapeIndex = 0;
26816 var counter = indepHoles.length * 2;
26817 while ( indepHoles.length > 0 ) {
26820 if ( counter < 0 ) {
26822 console.log( 'THREE.ShapeUtils: Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!' );
26827 // search for shape-vertex and hole-vertex,
26828 // which can be connected without intersections
26829 for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {
26831 shapePt = shape[ shapeIndex ];
26834 // search for hole which can be reached without intersections
26835 for ( var h = 0; h < indepHoles.length; h ++ ) {
26837 holeIdx = indepHoles[ h ];
26839 // prevent multiple checks
26840 cutKey = shapePt.x + ':' + shapePt.y + ':' + holeIdx;
26841 if ( failedCuts[ cutKey ] !== undefined ) continue;
26843 hole = holes[ holeIdx ];
26844 for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
26846 holePt = hole[ h2 ];
26847 if ( ! isCutLineInsideAngles( shapeIndex, h2 ) ) continue;
26848 if ( intersectsShapeEdge( shapePt, holePt ) ) continue;
26849 if ( intersectsHoleEdge( shapePt, holePt ) ) continue;
26852 indepHoles.splice( h, 1 );
26854 tmpShape1 = shape.slice( 0, shapeIndex + 1 );
26855 tmpShape2 = shape.slice( shapeIndex );
26856 tmpHole1 = hole.slice( holeIndex );
26857 tmpHole2 = hole.slice( 0, holeIndex + 1 );
26859 shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
26861 minShapeIndex = shapeIndex;
26863 // Debug only, to show the selected cuts
26864 // glob_CutLines.push( [ shapePt, holePt ] );
26869 if ( holeIndex >= 0 ) break; // hole-vertex found
26871 failedCuts[ cutKey ] = true; // remember failure
26874 if ( holeIndex >= 0 ) break; // hole-vertex found
26880 return shape; /* shape with no holes */
26885 var i, il, f, face,
26889 // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
26891 var allpoints = contour.concat();
26893 for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
26895 Array.prototype.push.apply( allpoints, holes[ h ] );
26899 //console.log( "allpoints",allpoints, allpoints.length );
26901 // prepare all points map
26903 for ( i = 0, il = allpoints.length; i < il; i ++ ) {
26905 key = allpoints[ i ].x + ':' + allpoints[ i ].y;
26907 if ( allPointsMap[ key ] !== undefined ) {
26909 console.warn( 'THREE.ShapeUtils: Duplicate point', key, i );
26913 allPointsMap[ key ] = i;
26917 // remove holes by cutting paths to holes and adding them to the shape
26918 var shapeWithoutHoles = removeHoles( contour, holes );
26920 var triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape
26921 //console.log( "triangles",triangles, triangles.length );
26923 // check all face vertices against all points map
26925 for ( i = 0, il = triangles.length; i < il; i ++ ) {
26927 face = triangles[ i ];
26929 for ( f = 0; f < 3; f ++ ) {
26931 key = face[ f ].x + ':' + face[ f ].y;
26933 index = allPointsMap[ key ];
26935 if ( index !== undefined ) {
26945 return triangles.concat();
26949 isClockWise: function ( pts ) {
26951 return ShapeUtils.area( pts ) < 0;
26958 * @author zz85 / http://www.lab4games.net/zz85/blog
26960 * Creates extruded geometry from a path shape.
26964 * curveSegments: <int>, // number of points on the curves
26965 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
26966 * amount: <int>, // Depth to extrude the shape
26968 * bevelEnabled: <bool>, // turn on bevel
26969 * bevelThickness: <float>, // how deep into the original shape bevel goes
26970 * bevelSize: <float>, // how far from shape outline is bevel
26971 * bevelSegments: <int>, // number of bevel layers
26973 * extrudePath: <THREE.Curve> // curve to extrude shape along
26974 * frames: <Object> // containing arrays of tangents, normals, binormals
26976 * UVGenerator: <Object> // object that provides UV generator functions
26983 function ExtrudeGeometry( shapes, options ) {
26985 Geometry.call( this );
26987 this.type = 'ExtrudeGeometry';
26989 this.parameters = {
26994 this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
26995 this.mergeVertices();
26999 ExtrudeGeometry.prototype = Object.create( Geometry.prototype );
27000 ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;
27002 // ExtrudeBufferGeometry
27004 function ExtrudeBufferGeometry( shapes, options ) {
27006 if ( typeof ( shapes ) === "undefined" ) {
27012 BufferGeometry.call( this );
27014 this.type = 'ExtrudeBufferGeometry';
27016 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
27018 this.addShapeList( shapes, options );
27020 this.computeVertexNormals();
27022 // can't really use automatic vertex normals
27023 // as then front and back sides get smoothed too
27024 // should do separate smoothing just for sides
27026 //this.computeVertexNormals();
27028 //console.log( "took", ( Date.now() - startTime ) );
27032 ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
27033 ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;
27035 ExtrudeBufferGeometry.prototype.getArrays = function () {
27037 var positionAttribute = this.getAttribute( "position" );
27038 var verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : [];
27040 var uvAttribute = this.getAttribute( "uv" );
27041 var uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : [];
27043 var IndexAttribute = this.index;
27044 var indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : [];
27047 position: verticesArray,
27049 index: indicesArray
27054 ExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) {
27056 var sl = shapes.length;
27057 options.arrays = this.getArrays();
27059 for ( var s = 0; s < sl; s ++ ) {
27061 var shape = shapes[ s ];
27062 this.addShape( shape, options );
27066 this.setIndex( options.arrays.index );
27067 this.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) );
27068 this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );
27072 ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) {
27074 var arrays = options.arrays ? options.arrays : this.getArrays();
27075 var verticesArray = arrays.position;
27076 var indicesArray = arrays.index;
27077 var uvArray = arrays.uv;
27079 var placeholder = [];
27082 var amount = options.amount !== undefined ? options.amount : 100;
27084 var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10
27085 var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8
27086 var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
27088 var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false
27090 var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
27092 var steps = options.steps !== undefined ? options.steps : 1;
27094 var extrudePath = options.extrudePath;
27095 var extrudePts, extrudeByPath = false;
27097 // Use default WorldUVGenerator if no UV generators are specified.
27098 var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator;
27100 var splineTube, binormal, normal, position2;
27101 if ( extrudePath ) {
27103 extrudePts = extrudePath.getSpacedPoints( steps );
27105 extrudeByPath = true;
27106 bevelEnabled = false; // bevels not supported for path extrusion
27108 // SETUP TNB variables
27110 // TODO1 - have a .isClosed in spline?
27112 splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false );
27114 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
27116 binormal = new Vector3();
27117 normal = new Vector3();
27118 position2 = new Vector3();
27122 // Safeguards if bevels are not enabled
27124 if ( ! bevelEnabled ) {
27127 bevelThickness = 0;
27132 // Variables initialization
27134 var ahole, h, hl; // looping of holes
27137 var shapePoints = shape.extractPoints( curveSegments );
27139 var vertices = shapePoints.shape;
27140 var holes = shapePoints.holes;
27142 var reverse = ! ShapeUtils.isClockWise( vertices );
27146 vertices = vertices.reverse();
27148 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
27150 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27152 ahole = holes[ h ];
27154 if ( ShapeUtils.isClockWise( ahole ) ) {
27156 holes[ h ] = ahole.reverse();
27165 var faces = ShapeUtils.triangulateShape( vertices, holes );
27169 var contour = vertices; // vertices has all points but contour has only points of circumference
27171 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27173 ahole = holes[ h ];
27175 vertices = vertices.concat( ahole );
27180 function scalePt2( pt, vec, size ) {
27182 if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" );
27184 return vec.clone().multiplyScalar( size ).add( pt );
27189 vert, vlen = vertices.length,
27190 face, flen = faces.length;
27193 // Find directions for point movement
27196 function getBevelVec( inPt, inPrev, inNext ) {
27198 // computes for inPt the corresponding point inPt' on a new contour
27199 // shifted by 1 unit (length of normalized vector) to the left
27200 // if we walk along contour clockwise, this new contour is outside the old one
27202 // inPt' is the intersection of the two lines parallel to the two
27203 // adjacent edges of inPt at a distance of 1 unit on the left side.
27205 var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
27207 // good reading for geometry algorithms (here: line-line intersection)
27208 // http://geomalgorithms.com/a05-_intersect-1.html
27210 var v_prev_x = inPt.x - inPrev.x,
27211 v_prev_y = inPt.y - inPrev.y;
27212 var v_next_x = inNext.x - inPt.x,
27213 v_next_y = inNext.y - inPt.y;
27215 var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
27217 // check for collinear edges
27218 var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
27220 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
27224 // length of vectors for normalizing
27226 var v_prev_len = Math.sqrt( v_prev_lensq );
27227 var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
27229 // shift adjacent points by unit vectors to the left
27231 var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
27232 var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
27234 var ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
27235 var ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
27237 // scaling factor for v_prev to intersection point
27239 var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
27240 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
27241 ( v_prev_x * v_next_y - v_prev_y * v_next_x );
27243 // vector from inPt to intersection point
27245 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
27246 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
27248 // Don't normalize!, otherwise sharp corners become ugly
27249 // but prevent crazy spikes
27250 var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
27251 if ( v_trans_lensq <= 2 ) {
27253 return new Vector2( v_trans_x, v_trans_y );
27257 shrink_by = Math.sqrt( v_trans_lensq / 2 );
27263 // handle special case of collinear edges
27265 var direction_eq = false; // assumes: opposite
27266 if ( v_prev_x > Number.EPSILON ) {
27268 if ( v_next_x > Number.EPSILON ) {
27270 direction_eq = true;
27276 if ( v_prev_x < - Number.EPSILON ) {
27278 if ( v_next_x < - Number.EPSILON ) {
27280 direction_eq = true;
27286 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
27288 direction_eq = true;
27296 if ( direction_eq ) {
27298 // console.log("Warning: lines are a straight sequence");
27299 v_trans_x = - v_prev_y;
27300 v_trans_y = v_prev_x;
27301 shrink_by = Math.sqrt( v_prev_lensq );
27305 // console.log("Warning: lines are a straight spike");
27306 v_trans_x = v_prev_x;
27307 v_trans_y = v_prev_y;
27308 shrink_by = Math.sqrt( v_prev_lensq / 2 );
27314 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
27319 var contourMovements = [];
27321 for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
27323 if ( j === il ) j = 0;
27324 if ( k === il ) k = 0;
27327 // console.log('i,j,k', i, j , k)
27329 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
27333 var holesMovements = [],
27334 oneHoleMovements, verticesMovements = contourMovements.concat();
27336 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27338 ahole = holes[ h ];
27340 oneHoleMovements = [];
27342 for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
27344 if ( j === il ) j = 0;
27345 if ( k === il ) k = 0;
27348 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
27352 holesMovements.push( oneHoleMovements );
27353 verticesMovements = verticesMovements.concat( oneHoleMovements );
27358 // Loop bevelSegments, 1 for the front, 1 for the back
27360 for ( b = 0; b < bevelSegments; b ++ ) {
27362 //for ( b = bevelSegments; b > 0; b -- ) {
27364 t = b / bevelSegments;
27365 z = bevelThickness * Math.cos( t * Math.PI / 2 );
27366 bs = bevelSize * Math.sin( t * Math.PI / 2 );
27370 for ( i = 0, il = contour.length; i < il; i ++ ) {
27372 vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
27374 v( vert.x, vert.y, - z );
27380 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27382 ahole = holes[ h ];
27383 oneHoleMovements = holesMovements[ h ];
27385 for ( i = 0, il = ahole.length; i < il; i ++ ) {
27387 vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
27389 v( vert.x, vert.y, - z );
27399 // Back facing vertices
27401 for ( i = 0; i < vlen; i ++ ) {
27403 vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
27405 if ( ! extrudeByPath ) {
27407 v( vert.x, vert.y, 0 );
27411 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
27413 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
27414 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
27416 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
27418 v( position2.x, position2.y, position2.z );
27424 // Add stepped vertices...
27425 // Including front facing vertices
27429 for ( s = 1; s <= steps; s ++ ) {
27431 for ( i = 0; i < vlen; i ++ ) {
27433 vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
27435 if ( ! extrudeByPath ) {
27437 v( vert.x, vert.y, amount / steps * s );
27441 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
27443 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
27444 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
27446 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
27448 v( position2.x, position2.y, position2.z );
27457 // Add bevel segments planes
27459 //for ( b = 1; b <= bevelSegments; b ++ ) {
27460 for ( b = bevelSegments - 1; b >= 0; b -- ) {
27462 t = b / bevelSegments;
27463 z = bevelThickness * Math.cos( t * Math.PI / 2 );
27464 bs = bevelSize * Math.sin( t * Math.PI / 2 );
27468 for ( i = 0, il = contour.length; i < il; i ++ ) {
27470 vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
27471 v( vert.x, vert.y, amount + z );
27477 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27479 ahole = holes[ h ];
27480 oneHoleMovements = holesMovements[ h ];
27482 for ( i = 0, il = ahole.length; i < il; i ++ ) {
27484 vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
27486 if ( ! extrudeByPath ) {
27488 v( vert.x, vert.y, amount + z );
27492 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
27504 // Top and bottom faces
27513 ///// Internal functions
27515 function buildLidFaces() {
27517 var start = verticesArray.length/3;
27519 if ( bevelEnabled ) {
27521 var layer = 0; // steps + 1
27522 var offset = vlen * layer;
27526 for ( i = 0; i < flen; i ++ ) {
27529 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
27533 layer = steps + bevelSegments * 2;
27534 offset = vlen * layer;
27538 for ( i = 0; i < flen; i ++ ) {
27541 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
27549 for ( i = 0; i < flen; i ++ ) {
27552 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
27558 for ( i = 0; i < flen; i ++ ) {
27561 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
27567 scope.addGroup( start, verticesArray.length/3 -start, options.material !== undefined ? options.material : 0);
27571 // Create faces for the z-sides of the shape
27573 function buildSideFaces() {
27575 var start = verticesArray.length/3;
27576 var layeroffset = 0;
27577 sidewalls( contour, layeroffset );
27578 layeroffset += contour.length;
27580 for ( h = 0, hl = holes.length; h < hl; h ++ ) {
27582 ahole = holes[ h ];
27583 sidewalls( ahole, layeroffset );
27586 layeroffset += ahole.length;
27591 scope.addGroup( start, verticesArray.length/3 -start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1);
27596 function sidewalls( contour, layeroffset ) {
27599 i = contour.length;
27601 while ( -- i >= 0 ) {
27605 if ( k < 0 ) k = contour.length - 1;
27607 //console.log('b', i,j, i-1, k,vertices.length);
27610 sl = steps + bevelSegments * 2;
27612 for ( s = 0; s < sl; s ++ ) {
27614 var slen1 = vlen * s;
27615 var slen2 = vlen * ( s + 1 );
27617 var a = layeroffset + j + slen1,
27618 b = layeroffset + k + slen1,
27619 c = layeroffset + k + slen2,
27620 d = layeroffset + j + slen2;
27622 f4( a, b, c, d, contour, s, sl, j, k );
27630 function v( x, y, z ) {
27632 placeholder.push( x );
27633 placeholder.push( y );
27634 placeholder.push( z );
27639 function f3( a, b, c ) {
27645 var nextIndex = verticesArray.length / 3;
27646 var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
27654 function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {
27665 var nextIndex = verticesArray.length / 3;
27666 var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
27678 function addVertex( index ) {
27680 indicesArray.push( verticesArray.length / 3 );
27681 verticesArray.push( placeholder[ index * 3 + 0 ] );
27682 verticesArray.push( placeholder[ index * 3 + 1 ] );
27683 verticesArray.push( placeholder[ index * 3 + 2 ] );
27688 function addUV( vector2 ) {
27690 uvArray.push( vector2.x );
27691 uvArray.push( vector2.y );
27695 if ( ! options.arrays ) {
27697 this.setIndex( indicesArray );
27698 this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
27699 this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );
27705 ExtrudeGeometry.WorldUVGenerator = {
27707 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
27709 var a_x = vertices[ indexA * 3 ];
27710 var a_y = vertices[ indexA * 3 + 1 ];
27711 var b_x = vertices[ indexB * 3 ];
27712 var b_y = vertices[ indexB * 3 + 1 ];
27713 var c_x = vertices[ indexC * 3 ];
27714 var c_y = vertices[ indexC * 3 + 1 ];
27717 new Vector2( a_x, a_y ),
27718 new Vector2( b_x, b_y ),
27719 new Vector2( c_x, c_y )
27724 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
27726 var a_x = vertices[ indexA * 3 ];
27727 var a_y = vertices[ indexA * 3 + 1 ];
27728 var a_z = vertices[ indexA * 3 + 2 ];
27729 var b_x = vertices[ indexB * 3 ];
27730 var b_y = vertices[ indexB * 3 + 1 ];
27731 var b_z = vertices[ indexB * 3 + 2 ];
27732 var c_x = vertices[ indexC * 3 ];
27733 var c_y = vertices[ indexC * 3 + 1 ];
27734 var c_z = vertices[ indexC * 3 + 2 ];
27735 var d_x = vertices[ indexD * 3 ];
27736 var d_y = vertices[ indexD * 3 + 1 ];
27737 var d_z = vertices[ indexD * 3 + 2 ];
27739 if ( Math.abs( a_y - b_y ) < 0.01 ) {
27742 new Vector2( a_x, 1 - a_z ),
27743 new Vector2( b_x, 1 - b_z ),
27744 new Vector2( c_x, 1 - c_z ),
27745 new Vector2( d_x, 1 - d_z )
27751 new Vector2( a_y, 1 - a_z ),
27752 new Vector2( b_y, 1 - b_z ),
27753 new Vector2( c_y, 1 - c_z ),
27754 new Vector2( d_y, 1 - d_z )
27763 * @author zz85 / http://www.lab4games.net/zz85/blog
27764 * @author alteredq / http://alteredqualia.com/
27769 * font: <THREE.Font>, // font
27771 * size: <float>, // size of the text
27772 * height: <float>, // thickness to extrude text
27773 * curveSegments: <int>, // number of points on the curves
27775 * bevelEnabled: <bool>, // turn on bevel
27776 * bevelThickness: <float>, // how deep into text bevel goes
27777 * bevelSize: <float> // how far from text outline is bevel
27783 function TextGeometry( text, parameters ) {
27785 Geometry.call( this );
27787 this.type = 'TextGeometry';
27789 this.parameters = {
27791 parameters: parameters
27794 this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
27795 this.mergeVertices();
27799 TextGeometry.prototype = Object.create( Geometry.prototype );
27800 TextGeometry.prototype.constructor = TextGeometry;
27802 // TextBufferGeometry
27804 function TextBufferGeometry( text, parameters ) {
27806 parameters = parameters || {};
27808 var font = parameters.font;
27810 if ( ! ( font && font.isFont ) ) {
27812 console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
27813 return new Geometry();
27817 var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );
27819 // translate parameters to ExtrudeGeometry API
27821 parameters.amount = parameters.height !== undefined ? parameters.height : 50;
27825 if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
27826 if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
27827 if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
27829 ExtrudeBufferGeometry.call( this, shapes, parameters );
27831 this.type = 'TextBufferGeometry';
27835 TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );
27836 TextBufferGeometry.prototype.constructor = TextBufferGeometry;
27839 * @author mrdoob / http://mrdoob.com/
27840 * @author benaadams / https://twitter.com/ben_a_adams
27841 * @author Mugen87 / https://github.com/Mugen87
27846 function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
27848 Geometry.call( this );
27850 this.type = 'SphereGeometry';
27852 this.parameters = {
27854 widthSegments: widthSegments,
27855 heightSegments: heightSegments,
27856 phiStart: phiStart,
27857 phiLength: phiLength,
27858 thetaStart: thetaStart,
27859 thetaLength: thetaLength
27862 this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
27863 this.mergeVertices();
27867 SphereGeometry.prototype = Object.create( Geometry.prototype );
27868 SphereGeometry.prototype.constructor = SphereGeometry;
27870 // SphereBufferGeometry
27872 function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
27874 BufferGeometry.call( this );
27876 this.type = 'SphereBufferGeometry';
27878 this.parameters = {
27880 widthSegments: widthSegments,
27881 heightSegments: heightSegments,
27882 phiStart: phiStart,
27883 phiLength: phiLength,
27884 thetaStart: thetaStart,
27885 thetaLength: thetaLength
27888 radius = radius || 50;
27890 widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
27891 heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
27893 phiStart = phiStart !== undefined ? phiStart : 0;
27894 phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
27896 thetaStart = thetaStart !== undefined ? thetaStart : 0;
27897 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
27899 var thetaEnd = thetaStart + thetaLength;
27906 var vertex = new Vector3();
27907 var normal = new Vector3();
27916 // generate vertices, normals and uvs
27918 for ( iy = 0; iy <= heightSegments; iy ++ ) {
27920 var verticesRow = [];
27922 var v = iy / heightSegments;
27924 for ( ix = 0; ix <= widthSegments; ix ++ ) {
27926 var u = ix / widthSegments;
27930 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
27931 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
27932 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
27934 vertices.push( vertex.x, vertex.y, vertex.z );
27938 normal.set( vertex.x, vertex.y, vertex.z ).normalize();
27939 normals.push( normal.x, normal.y, normal.z );
27943 uvs.push( u, 1 - v );
27945 verticesRow.push( index ++ );
27949 grid.push( verticesRow );
27955 for ( iy = 0; iy < heightSegments; iy ++ ) {
27957 for ( ix = 0; ix < widthSegments; ix ++ ) {
27959 var a = grid[ iy ][ ix + 1 ];
27960 var b = grid[ iy ][ ix ];
27961 var c = grid[ iy + 1 ][ ix ];
27962 var d = grid[ iy + 1 ][ ix + 1 ];
27964 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
27965 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
27973 this.setIndex( indices );
27974 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
27975 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
27976 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
27980 SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
27981 SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
27984 * @author Kaleb Murphy
27985 * @author Mugen87 / https://github.com/Mugen87
27990 function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
27992 Geometry.call( this );
27994 this.type = 'RingGeometry';
27996 this.parameters = {
27997 innerRadius: innerRadius,
27998 outerRadius: outerRadius,
27999 thetaSegments: thetaSegments,
28000 phiSegments: phiSegments,
28001 thetaStart: thetaStart,
28002 thetaLength: thetaLength
28005 this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
28006 this.mergeVertices();
28010 RingGeometry.prototype = Object.create( Geometry.prototype );
28011 RingGeometry.prototype.constructor = RingGeometry;
28013 // RingBufferGeometry
28015 function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
28017 BufferGeometry.call( this );
28019 this.type = 'RingBufferGeometry';
28021 this.parameters = {
28022 innerRadius: innerRadius,
28023 outerRadius: outerRadius,
28024 thetaSegments: thetaSegments,
28025 phiSegments: phiSegments,
28026 thetaStart: thetaStart,
28027 thetaLength: thetaLength
28030 innerRadius = innerRadius || 20;
28031 outerRadius = outerRadius || 50;
28033 thetaStart = thetaStart !== undefined ? thetaStart : 0;
28034 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
28036 thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
28037 phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
28046 // some helper variables
28049 var radius = innerRadius;
28050 var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
28051 var vertex = new Vector3();
28052 var uv = new Vector2();
28055 // generate vertices, normals and uvs
28057 for ( j = 0; j <= phiSegments; j ++ ) {
28059 for ( i = 0; i <= thetaSegments; i ++ ) {
28061 // values are generate from the inside of the ring to the outside
28063 segment = thetaStart + i / thetaSegments * thetaLength;
28067 vertex.x = radius * Math.cos( segment );
28068 vertex.y = radius * Math.sin( segment );
28070 vertices.push( vertex.x, vertex.y, vertex.z );
28074 normals.push( 0, 0, 1 );
28078 uv.x = ( vertex.x / outerRadius + 1 ) / 2;
28079 uv.y = ( vertex.y / outerRadius + 1 ) / 2;
28081 uvs.push( uv.x, uv.y );
28085 // increase the radius for next row of vertices
28087 radius += radiusStep;
28093 for ( j = 0; j < phiSegments; j ++ ) {
28095 var thetaSegmentLevel = j * ( thetaSegments + 1 );
28097 for ( i = 0; i < thetaSegments; i ++ ) {
28099 segment = i + thetaSegmentLevel;
28102 var b = segment + thetaSegments + 1;
28103 var c = segment + thetaSegments + 2;
28104 var d = segment + 1;
28108 indices.push( a, b, d );
28109 indices.push( b, c, d );
28117 this.setIndex( indices );
28118 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28119 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28120 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28124 RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
28125 RingBufferGeometry.prototype.constructor = RingBufferGeometry;
28128 * @author astrodud / http://astrodud.isgreat.org/
28129 * @author zz85 / https://github.com/zz85
28130 * @author bhouston / http://clara.io
28131 * @author Mugen87 / https://github.com/Mugen87
28136 function LatheGeometry( points, segments, phiStart, phiLength ) {
28138 Geometry.call( this );
28140 this.type = 'LatheGeometry';
28142 this.parameters = {
28144 segments: segments,
28145 phiStart: phiStart,
28146 phiLength: phiLength
28149 this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
28150 this.mergeVertices();
28154 LatheGeometry.prototype = Object.create( Geometry.prototype );
28155 LatheGeometry.prototype.constructor = LatheGeometry;
28157 // LatheBufferGeometry
28159 function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
28161 BufferGeometry.call( this );
28163 this.type = 'LatheBufferGeometry';
28165 this.parameters = {
28167 segments: segments,
28168 phiStart: phiStart,
28169 phiLength: phiLength
28172 segments = Math.floor( segments ) || 12;
28173 phiStart = phiStart || 0;
28174 phiLength = phiLength || Math.PI * 2;
28176 // clamp phiLength so it's in range of [ 0, 2PI ]
28178 phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );
28187 // helper variables
28190 var inverseSegments = 1.0 / segments;
28191 var vertex = new Vector3();
28192 var uv = new Vector2();
28195 // generate vertices and uvs
28197 for ( i = 0; i <= segments; i ++ ) {
28199 var phi = phiStart + i * inverseSegments * phiLength;
28201 var sin = Math.sin( phi );
28202 var cos = Math.cos( phi );
28204 for ( j = 0; j <= ( points.length - 1 ); j ++ ) {
28208 vertex.x = points[ j ].x * sin;
28209 vertex.y = points[ j ].y;
28210 vertex.z = points[ j ].x * cos;
28212 vertices.push( vertex.x, vertex.y, vertex.z );
28216 uv.x = i / segments;
28217 uv.y = j / ( points.length - 1 );
28219 uvs.push( uv.x, uv.y );
28228 for ( i = 0; i < segments; i ++ ) {
28230 for ( j = 0; j < ( points.length - 1 ); j ++ ) {
28232 base = j + i * points.length;
28235 var b = base + points.length;
28236 var c = base + points.length + 1;
28241 indices.push( a, b, d );
28242 indices.push( b, c, d );
28250 this.setIndex( indices );
28251 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28252 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28254 // generate normals
28256 this.computeVertexNormals();
28258 // if the geometry is closed, we need to average the normals along the seam.
28259 // because the corresponding vertices are identical (but still have different UVs).
28261 if ( phiLength === Math.PI * 2 ) {
28263 var normals = this.attributes.normal.array;
28264 var n1 = new Vector3();
28265 var n2 = new Vector3();
28266 var n = new Vector3();
28268 // this is the buffer offset for the last line of vertices
28270 base = segments * points.length * 3;
28272 for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {
28274 // select the normal of the vertex in the first line
28276 n1.x = normals[ j + 0 ];
28277 n1.y = normals[ j + 1 ];
28278 n1.z = normals[ j + 2 ];
28280 // select the normal of the vertex in the last line
28282 n2.x = normals[ base + j + 0 ];
28283 n2.y = normals[ base + j + 1 ];
28284 n2.z = normals[ base + j + 2 ];
28288 n.addVectors( n1, n2 ).normalize();
28290 // assign the new values to both normals
28292 normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
28293 normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
28294 normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
28302 LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
28303 LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
28306 * @author jonobr1 / http://jonobr1.com
28307 * @author Mugen87 / https://github.com/Mugen87
28312 function ShapeGeometry( shapes, curveSegments ) {
28314 Geometry.call( this );
28316 this.type = 'ShapeGeometry';
28318 if ( typeof curveSegments === 'object' ) {
28320 console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
28322 curveSegments = curveSegments.curveSegments;
28326 this.parameters = {
28328 curveSegments: curveSegments
28331 this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
28332 this.mergeVertices();
28336 ShapeGeometry.prototype = Object.create( Geometry.prototype );
28337 ShapeGeometry.prototype.constructor = ShapeGeometry;
28339 // ShapeBufferGeometry
28341 function ShapeBufferGeometry( shapes, curveSegments ) {
28343 BufferGeometry.call( this );
28345 this.type = 'ShapeBufferGeometry';
28347 this.parameters = {
28349 curveSegments: curveSegments
28352 curveSegments = curveSegments || 12;
28361 // helper variables
28363 var groupStart = 0;
28364 var groupCount = 0;
28366 // allow single and array values for "shapes" parameter
28368 if ( Array.isArray( shapes ) === false ) {
28370 addShape( shapes );
28374 for ( var i = 0; i < shapes.length; i ++ ) {
28376 addShape( shapes[ i ] );
28378 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
28380 groupStart += groupCount;
28389 this.setIndex( indices );
28390 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28391 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28392 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28395 // helper functions
28397 function addShape( shape ) {
28399 var i, l, shapeHole;
28401 var indexOffset = vertices.length / 3;
28402 var points = shape.extractPoints( curveSegments );
28404 var shapeVertices = points.shape;
28405 var shapeHoles = points.holes;
28407 // check direction of vertices
28409 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
28411 shapeVertices = shapeVertices.reverse();
28413 // also check if holes are in the opposite direction
28415 for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
28417 shapeHole = shapeHoles[ i ];
28419 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
28421 shapeHoles[ i ] = shapeHole.reverse();
28429 var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
28431 // join vertices of inner and outer paths to a single array
28433 for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
28435 shapeHole = shapeHoles[ i ];
28436 shapeVertices = shapeVertices.concat( shapeHole );
28440 // vertices, normals, uvs
28442 for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {
28444 var vertex = shapeVertices[ i ];
28446 vertices.push( vertex.x, vertex.y, 0 );
28447 normals.push( 0, 0, 1 );
28448 uvs.push( vertex.x, vertex.y ); // world uvs
28454 for ( i = 0, l = faces.length; i < l; i ++ ) {
28456 var face = faces[ i ];
28458 var a = face[ 0 ] + indexOffset;
28459 var b = face[ 1 ] + indexOffset;
28460 var c = face[ 2 ] + indexOffset;
28462 indices.push( a, b, c );
28471 ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
28472 ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
28475 * @author WestLangley / http://github.com/WestLangley
28476 * @author Mugen87 / https://github.com/Mugen87
28479 function EdgesGeometry( geometry, thresholdAngle ) {
28481 BufferGeometry.call( this );
28483 this.type = 'EdgesGeometry';
28485 this.parameters = {
28486 thresholdAngle: thresholdAngle
28489 thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
28495 // helper variables
28497 var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );
28498 var edge = [ 0, 0 ], edges = {}, edge1, edge2;
28499 var key, keys = [ 'a', 'b', 'c' ];
28501 // prepare source geometry
28505 if ( geometry.isBufferGeometry ) {
28507 geometry2 = new Geometry();
28508 geometry2.fromBufferGeometry( geometry );
28512 geometry2 = geometry.clone();
28516 geometry2.mergeVertices();
28517 geometry2.computeFaceNormals();
28519 var sourceVertices = geometry2.vertices;
28520 var faces = geometry2.faces;
28522 // now create a data structure where each entry represents an edge with its adjoining faces
28524 for ( var i = 0, l = faces.length; i < l; i ++ ) {
28526 var face = faces[ i ];
28528 for ( var j = 0; j < 3; j ++ ) {
28530 edge1 = face[ keys[ j ] ];
28531 edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
28532 edge[ 0 ] = Math.min( edge1, edge2 );
28533 edge[ 1 ] = Math.max( edge1, edge2 );
28535 key = edge[ 0 ] + ',' + edge[ 1 ];
28537 if ( edges[ key ] === undefined ) {
28539 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
28543 edges[ key ].face2 = i;
28551 // generate vertices
28553 for ( key in edges ) {
28555 var e = edges[ key ];
28557 // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
28559 if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
28561 var vertex = sourceVertices[ e.index1 ];
28562 vertices.push( vertex.x, vertex.y, vertex.z );
28564 vertex = sourceVertices[ e.index2 ];
28565 vertices.push( vertex.x, vertex.y, vertex.z );
28573 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28577 EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
28578 EdgesGeometry.prototype.constructor = EdgesGeometry;
28581 * @author mrdoob / http://mrdoob.com/
28582 * @author Mugen87 / https://github.com/Mugen87
28585 // CylinderGeometry
28587 function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
28589 Geometry.call( this );
28591 this.type = 'CylinderGeometry';
28593 this.parameters = {
28594 radiusTop: radiusTop,
28595 radiusBottom: radiusBottom,
28597 radialSegments: radialSegments,
28598 heightSegments: heightSegments,
28599 openEnded: openEnded,
28600 thetaStart: thetaStart,
28601 thetaLength: thetaLength
28604 this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
28605 this.mergeVertices();
28609 CylinderGeometry.prototype = Object.create( Geometry.prototype );
28610 CylinderGeometry.prototype.constructor = CylinderGeometry;
28612 // CylinderBufferGeometry
28614 function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
28616 BufferGeometry.call( this );
28618 this.type = 'CylinderBufferGeometry';
28620 this.parameters = {
28621 radiusTop: radiusTop,
28622 radiusBottom: radiusBottom,
28624 radialSegments: radialSegments,
28625 heightSegments: heightSegments,
28626 openEnded: openEnded,
28627 thetaStart: thetaStart,
28628 thetaLength: thetaLength
28633 radiusTop = radiusTop !== undefined ? radiusTop : 20;
28634 radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
28635 height = height !== undefined ? height : 100;
28637 radialSegments = Math.floor( radialSegments ) || 8;
28638 heightSegments = Math.floor( heightSegments ) || 1;
28640 openEnded = openEnded !== undefined ? openEnded : false;
28641 thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
28642 thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;
28651 // helper variables
28654 var indexArray = [];
28655 var halfHeight = height / 2;
28656 var groupStart = 0;
28658 // generate geometry
28662 if ( openEnded === false ) {
28664 if ( radiusTop > 0 ) generateCap( true );
28665 if ( radiusBottom > 0 ) generateCap( false );
28671 this.setIndex( indices );
28672 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28673 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28674 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28676 function generateTorso() {
28679 var normal = new Vector3();
28680 var vertex = new Vector3();
28682 var groupCount = 0;
28684 // this will be used to calculate the normal
28685 var slope = ( radiusBottom - radiusTop ) / height;
28687 // generate vertices, normals and uvs
28689 for ( y = 0; y <= heightSegments; y ++ ) {
28693 var v = y / heightSegments;
28695 // calculate the radius of the current row
28697 var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
28699 for ( x = 0; x <= radialSegments; x ++ ) {
28701 var u = x / radialSegments;
28703 var theta = u * thetaLength + thetaStart;
28705 var sinTheta = Math.sin( theta );
28706 var cosTheta = Math.cos( theta );
28710 vertex.x = radius * sinTheta;
28711 vertex.y = - v * height + halfHeight;
28712 vertex.z = radius * cosTheta;
28713 vertices.push( vertex.x, vertex.y, vertex.z );
28717 normal.set( sinTheta, slope, cosTheta ).normalize();
28718 normals.push( normal.x, normal.y, normal.z );
28722 uvs.push( u, 1 - v );
28724 // save index of vertex in respective row
28726 indexRow.push( index ++ );
28730 // now save vertices of the row in our index array
28732 indexArray.push( indexRow );
28736 // generate indices
28738 for ( x = 0; x < radialSegments; x ++ ) {
28740 for ( y = 0; y < heightSegments; y ++ ) {
28742 // we use the index array to access the correct indices
28744 var a = indexArray[ y ][ x ];
28745 var b = indexArray[ y + 1 ][ x ];
28746 var c = indexArray[ y + 1 ][ x + 1 ];
28747 var d = indexArray[ y ][ x + 1 ];
28751 indices.push( a, b, d );
28752 indices.push( b, c, d );
28754 // update group counter
28762 // add a group to the geometry. this will ensure multi material support
28764 scope.addGroup( groupStart, groupCount, 0 );
28766 // calculate new start value for groups
28768 groupStart += groupCount;
28772 function generateCap( top ) {
28774 var x, centerIndexStart, centerIndexEnd;
28776 var uv = new Vector2();
28777 var vertex = new Vector3();
28779 var groupCount = 0;
28781 var radius = ( top === true ) ? radiusTop : radiusBottom;
28782 var sign = ( top === true ) ? 1 : - 1;
28784 // save the index of the first center vertex
28785 centerIndexStart = index;
28787 // first we generate the center vertex data of the cap.
28788 // because the geometry needs one set of uvs per face,
28789 // we must generate a center vertex per face/segment
28791 for ( x = 1; x <= radialSegments; x ++ ) {
28795 vertices.push( 0, halfHeight * sign, 0 );
28799 normals.push( 0, sign, 0 );
28803 uvs.push( 0.5, 0.5 );
28811 // save the index of the last center vertex
28813 centerIndexEnd = index;
28815 // now we generate the surrounding vertices, normals and uvs
28817 for ( x = 0; x <= radialSegments; x ++ ) {
28819 var u = x / radialSegments;
28820 var theta = u * thetaLength + thetaStart;
28822 var cosTheta = Math.cos( theta );
28823 var sinTheta = Math.sin( theta );
28827 vertex.x = radius * sinTheta;
28828 vertex.y = halfHeight * sign;
28829 vertex.z = radius * cosTheta;
28830 vertices.push( vertex.x, vertex.y, vertex.z );
28834 normals.push( 0, sign, 0 );
28838 uv.x = ( cosTheta * 0.5 ) + 0.5;
28839 uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
28840 uvs.push( uv.x, uv.y );
28848 // generate indices
28850 for ( x = 0; x < radialSegments; x ++ ) {
28852 var c = centerIndexStart + x;
28853 var i = centerIndexEnd + x;
28855 if ( top === true ) {
28859 indices.push( i, i + 1, c );
28865 indices.push( i + 1, i, c );
28873 // add a group to the geometry. this will ensure multi material support
28875 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
28877 // calculate new start value for groups
28879 groupStart += groupCount;
28885 CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
28886 CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
28889 * @author abelnation / http://github.com/abelnation
28894 function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
28896 CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
28898 this.type = 'ConeGeometry';
28900 this.parameters = {
28903 radialSegments: radialSegments,
28904 heightSegments: heightSegments,
28905 openEnded: openEnded,
28906 thetaStart: thetaStart,
28907 thetaLength: thetaLength
28912 ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
28913 ConeGeometry.prototype.constructor = ConeGeometry;
28915 // ConeBufferGeometry
28917 function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
28919 CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
28921 this.type = 'ConeBufferGeometry';
28923 this.parameters = {
28926 radialSegments: radialSegments,
28927 heightSegments: heightSegments,
28928 openEnded: openEnded,
28929 thetaStart: thetaStart,
28930 thetaLength: thetaLength
28935 ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
28936 ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
28939 * @author benaadams / https://twitter.com/ben_a_adams
28940 * @author Mugen87 / https://github.com/Mugen87
28946 function CircleGeometry( radius, segments, thetaStart, thetaLength ) {
28948 Geometry.call( this );
28950 this.type = 'CircleGeometry';
28952 this.parameters = {
28954 segments: segments,
28955 thetaStart: thetaStart,
28956 thetaLength: thetaLength
28959 this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
28960 this.mergeVertices();
28964 CircleGeometry.prototype = Object.create( Geometry.prototype );
28965 CircleGeometry.prototype.constructor = CircleGeometry;
28967 // CircleBufferGeometry
28969 function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {
28971 BufferGeometry.call( this );
28973 this.type = 'CircleBufferGeometry';
28975 this.parameters = {
28977 segments: segments,
28978 thetaStart: thetaStart,
28979 thetaLength: thetaLength
28982 radius = radius || 50;
28983 segments = segments !== undefined ? Math.max( 3, segments ) : 8;
28985 thetaStart = thetaStart !== undefined ? thetaStart : 0;
28986 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
28995 // helper variables
28998 var vertex = new Vector3();
28999 var uv = new Vector2();
29003 vertices.push( 0, 0, 0 );
29004 normals.push( 0, 0, 1 );
29005 uvs.push( 0.5, 0.5 );
29007 for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {
29009 var segment = thetaStart + s / segments * thetaLength;
29013 vertex.x = radius * Math.cos( segment );
29014 vertex.y = radius * Math.sin( segment );
29016 vertices.push( vertex.x, vertex.y, vertex.z );
29020 normals.push( 0, 0, 1 );
29024 uv.x = ( vertices[ i ] / radius + 1 ) / 2;
29025 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
29027 uvs.push( uv.x, uv.y );
29033 for ( i = 1; i <= segments; i ++ ) {
29035 indices.push( i, i + 1, 0 );
29041 this.setIndex( indices );
29042 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29043 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
29044 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
29048 CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
29049 CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
29053 var Geometries = Object.freeze({
29054 WireframeGeometry: WireframeGeometry,
29055 ParametricGeometry: ParametricGeometry,
29056 ParametricBufferGeometry: ParametricBufferGeometry,
29057 TetrahedronGeometry: TetrahedronGeometry,
29058 TetrahedronBufferGeometry: TetrahedronBufferGeometry,
29059 OctahedronGeometry: OctahedronGeometry,
29060 OctahedronBufferGeometry: OctahedronBufferGeometry,
29061 IcosahedronGeometry: IcosahedronGeometry,
29062 IcosahedronBufferGeometry: IcosahedronBufferGeometry,
29063 DodecahedronGeometry: DodecahedronGeometry,
29064 DodecahedronBufferGeometry: DodecahedronBufferGeometry,
29065 PolyhedronGeometry: PolyhedronGeometry,
29066 PolyhedronBufferGeometry: PolyhedronBufferGeometry,
29067 TubeGeometry: TubeGeometry,
29068 TubeBufferGeometry: TubeBufferGeometry,
29069 TorusKnotGeometry: TorusKnotGeometry,
29070 TorusKnotBufferGeometry: TorusKnotBufferGeometry,
29071 TorusGeometry: TorusGeometry,
29072 TorusBufferGeometry: TorusBufferGeometry,
29073 TextGeometry: TextGeometry,
29074 TextBufferGeometry: TextBufferGeometry,
29075 SphereGeometry: SphereGeometry,
29076 SphereBufferGeometry: SphereBufferGeometry,
29077 RingGeometry: RingGeometry,
29078 RingBufferGeometry: RingBufferGeometry,
29079 PlaneGeometry: PlaneGeometry,
29080 PlaneBufferGeometry: PlaneBufferGeometry,
29081 LatheGeometry: LatheGeometry,
29082 LatheBufferGeometry: LatheBufferGeometry,
29083 ShapeGeometry: ShapeGeometry,
29084 ShapeBufferGeometry: ShapeBufferGeometry,
29085 ExtrudeGeometry: ExtrudeGeometry,
29086 ExtrudeBufferGeometry: ExtrudeBufferGeometry,
29087 EdgesGeometry: EdgesGeometry,
29088 ConeGeometry: ConeGeometry,
29089 ConeBufferGeometry: ConeBufferGeometry,
29090 CylinderGeometry: CylinderGeometry,
29091 CylinderBufferGeometry: CylinderBufferGeometry,
29092 CircleGeometry: CircleGeometry,
29093 CircleBufferGeometry: CircleBufferGeometry,
29094 BoxGeometry: BoxGeometry,
29095 BoxBufferGeometry: BoxBufferGeometry
29099 * @author mrdoob / http://mrdoob.com/
29102 * color: <THREE.Color>,
29107 function ShadowMaterial( parameters ) {
29109 Material.call( this );
29111 this.type = 'ShadowMaterial';
29113 this.color = new Color( 0x000000 );
29114 this.opacity = 1.0;
29116 this.lights = true;
29117 this.transparent = true;
29119 this.setValues( parameters );
29123 ShadowMaterial.prototype = Object.create( Material.prototype );
29124 ShadowMaterial.prototype.constructor = ShadowMaterial;
29126 ShadowMaterial.prototype.isShadowMaterial = true;
29129 * @author mrdoob / http://mrdoob.com/
29132 function RawShaderMaterial( parameters ) {
29134 ShaderMaterial.call( this, parameters );
29136 this.type = 'RawShaderMaterial';
29140 RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
29141 RawShaderMaterial.prototype.constructor = RawShaderMaterial;
29143 RawShaderMaterial.prototype.isRawShaderMaterial = true;
29146 * @author WestLangley / http://github.com/WestLangley
29150 * roughness: <float>,
29151 * metalness: <float>,
29152 * opacity: <float>,
29154 * map: new THREE.Texture( <Image> ),
29156 * lightMap: new THREE.Texture( <Image> ),
29157 * lightMapIntensity: <float>
29159 * aoMap: new THREE.Texture( <Image> ),
29160 * aoMapIntensity: <float>
29163 * emissiveIntensity: <float>
29164 * emissiveMap: new THREE.Texture( <Image> ),
29166 * bumpMap: new THREE.Texture( <Image> ),
29167 * bumpScale: <float>,
29169 * normalMap: new THREE.Texture( <Image> ),
29170 * normalScale: <Vector2>,
29172 * displacementMap: new THREE.Texture( <Image> ),
29173 * displacementScale: <float>,
29174 * displacementBias: <float>,
29176 * roughnessMap: new THREE.Texture( <Image> ),
29178 * metalnessMap: new THREE.Texture( <Image> ),
29180 * alphaMap: new THREE.Texture( <Image> ),
29182 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
29183 * envMapIntensity: <float>
29185 * refractionRatio: <float>,
29187 * wireframe: <boolean>,
29188 * wireframeLinewidth: <float>,
29190 * skinning: <bool>,
29191 * morphTargets: <bool>,
29192 * morphNormals: <bool>
29196 function MeshStandardMaterial( parameters ) {
29198 Material.call( this );
29200 this.defines = { 'STANDARD': '' };
29202 this.type = 'MeshStandardMaterial';
29204 this.color = new Color( 0xffffff ); // diffuse
29205 this.roughness = 0.5;
29206 this.metalness = 0.5;
29210 this.lightMap = null;
29211 this.lightMapIntensity = 1.0;
29214 this.aoMapIntensity = 1.0;
29216 this.emissive = new Color( 0x000000 );
29217 this.emissiveIntensity = 1.0;
29218 this.emissiveMap = null;
29220 this.bumpMap = null;
29221 this.bumpScale = 1;
29223 this.normalMap = null;
29224 this.normalScale = new Vector2( 1, 1 );
29226 this.displacementMap = null;
29227 this.displacementScale = 1;
29228 this.displacementBias = 0;
29230 this.roughnessMap = null;
29232 this.metalnessMap = null;
29234 this.alphaMap = null;
29236 this.envMap = null;
29237 this.envMapIntensity = 1.0;
29239 this.refractionRatio = 0.98;
29241 this.wireframe = false;
29242 this.wireframeLinewidth = 1;
29243 this.wireframeLinecap = 'round';
29244 this.wireframeLinejoin = 'round';
29246 this.skinning = false;
29247 this.morphTargets = false;
29248 this.morphNormals = false;
29250 this.setValues( parameters );
29254 MeshStandardMaterial.prototype = Object.create( Material.prototype );
29255 MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
29257 MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
29259 MeshStandardMaterial.prototype.copy = function ( source ) {
29261 Material.prototype.copy.call( this, source );
29263 this.defines = { 'STANDARD': '' };
29265 this.color.copy( source.color );
29266 this.roughness = source.roughness;
29267 this.metalness = source.metalness;
29269 this.map = source.map;
29271 this.lightMap = source.lightMap;
29272 this.lightMapIntensity = source.lightMapIntensity;
29274 this.aoMap = source.aoMap;
29275 this.aoMapIntensity = source.aoMapIntensity;
29277 this.emissive.copy( source.emissive );
29278 this.emissiveMap = source.emissiveMap;
29279 this.emissiveIntensity = source.emissiveIntensity;
29281 this.bumpMap = source.bumpMap;
29282 this.bumpScale = source.bumpScale;
29284 this.normalMap = source.normalMap;
29285 this.normalScale.copy( source.normalScale );
29287 this.displacementMap = source.displacementMap;
29288 this.displacementScale = source.displacementScale;
29289 this.displacementBias = source.displacementBias;
29291 this.roughnessMap = source.roughnessMap;
29293 this.metalnessMap = source.metalnessMap;
29295 this.alphaMap = source.alphaMap;
29297 this.envMap = source.envMap;
29298 this.envMapIntensity = source.envMapIntensity;
29300 this.refractionRatio = source.refractionRatio;
29302 this.wireframe = source.wireframe;
29303 this.wireframeLinewidth = source.wireframeLinewidth;
29304 this.wireframeLinecap = source.wireframeLinecap;
29305 this.wireframeLinejoin = source.wireframeLinejoin;
29307 this.skinning = source.skinning;
29308 this.morphTargets = source.morphTargets;
29309 this.morphNormals = source.morphNormals;
29316 * @author WestLangley / http://github.com/WestLangley
29319 * reflectivity: <float>
29323 function MeshPhysicalMaterial( parameters ) {
29325 MeshStandardMaterial.call( this );
29327 this.defines = { 'PHYSICAL': '' };
29329 this.type = 'MeshPhysicalMaterial';
29331 this.reflectivity = 0.5; // maps to F0 = 0.04
29333 this.clearCoat = 0.0;
29334 this.clearCoatRoughness = 0.0;
29336 this.setValues( parameters );
29340 MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
29341 MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
29343 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
29345 MeshPhysicalMaterial.prototype.copy = function ( source ) {
29347 MeshStandardMaterial.prototype.copy.call( this, source );
29349 this.defines = { 'PHYSICAL': '' };
29351 this.reflectivity = source.reflectivity;
29353 this.clearCoat = source.clearCoat;
29354 this.clearCoatRoughness = source.clearCoatRoughness;
29361 * @author mrdoob / http://mrdoob.com/
29362 * @author alteredq / http://alteredqualia.com/
29367 * shininess: <float>,
29368 * opacity: <float>,
29370 * map: new THREE.Texture( <Image> ),
29372 * lightMap: new THREE.Texture( <Image> ),
29373 * lightMapIntensity: <float>
29375 * aoMap: new THREE.Texture( <Image> ),
29376 * aoMapIntensity: <float>
29379 * emissiveIntensity: <float>
29380 * emissiveMap: new THREE.Texture( <Image> ),
29382 * bumpMap: new THREE.Texture( <Image> ),
29383 * bumpScale: <float>,
29385 * normalMap: new THREE.Texture( <Image> ),
29386 * normalScale: <Vector2>,
29388 * displacementMap: new THREE.Texture( <Image> ),
29389 * displacementScale: <float>,
29390 * displacementBias: <float>,
29392 * specularMap: new THREE.Texture( <Image> ),
29394 * alphaMap: new THREE.Texture( <Image> ),
29396 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
29397 * combine: THREE.Multiply,
29398 * reflectivity: <float>,
29399 * refractionRatio: <float>,
29401 * wireframe: <boolean>,
29402 * wireframeLinewidth: <float>,
29404 * skinning: <bool>,
29405 * morphTargets: <bool>,
29406 * morphNormals: <bool>
29410 function MeshPhongMaterial( parameters ) {
29412 Material.call( this );
29414 this.type = 'MeshPhongMaterial';
29416 this.color = new Color( 0xffffff ); // diffuse
29417 this.specular = new Color( 0x111111 );
29418 this.shininess = 30;
29422 this.lightMap = null;
29423 this.lightMapIntensity = 1.0;
29426 this.aoMapIntensity = 1.0;
29428 this.emissive = new Color( 0x000000 );
29429 this.emissiveIntensity = 1.0;
29430 this.emissiveMap = null;
29432 this.bumpMap = null;
29433 this.bumpScale = 1;
29435 this.normalMap = null;
29436 this.normalScale = new Vector2( 1, 1 );
29438 this.displacementMap = null;
29439 this.displacementScale = 1;
29440 this.displacementBias = 0;
29442 this.specularMap = null;
29444 this.alphaMap = null;
29446 this.envMap = null;
29447 this.combine = MultiplyOperation;
29448 this.reflectivity = 1;
29449 this.refractionRatio = 0.98;
29451 this.wireframe = false;
29452 this.wireframeLinewidth = 1;
29453 this.wireframeLinecap = 'round';
29454 this.wireframeLinejoin = 'round';
29456 this.skinning = false;
29457 this.morphTargets = false;
29458 this.morphNormals = false;
29460 this.setValues( parameters );
29464 MeshPhongMaterial.prototype = Object.create( Material.prototype );
29465 MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
29467 MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
29469 MeshPhongMaterial.prototype.copy = function ( source ) {
29471 Material.prototype.copy.call( this, source );
29473 this.color.copy( source.color );
29474 this.specular.copy( source.specular );
29475 this.shininess = source.shininess;
29477 this.map = source.map;
29479 this.lightMap = source.lightMap;
29480 this.lightMapIntensity = source.lightMapIntensity;
29482 this.aoMap = source.aoMap;
29483 this.aoMapIntensity = source.aoMapIntensity;
29485 this.emissive.copy( source.emissive );
29486 this.emissiveMap = source.emissiveMap;
29487 this.emissiveIntensity = source.emissiveIntensity;
29489 this.bumpMap = source.bumpMap;
29490 this.bumpScale = source.bumpScale;
29492 this.normalMap = source.normalMap;
29493 this.normalScale.copy( source.normalScale );
29495 this.displacementMap = source.displacementMap;
29496 this.displacementScale = source.displacementScale;
29497 this.displacementBias = source.displacementBias;
29499 this.specularMap = source.specularMap;
29501 this.alphaMap = source.alphaMap;
29503 this.envMap = source.envMap;
29504 this.combine = source.combine;
29505 this.reflectivity = source.reflectivity;
29506 this.refractionRatio = source.refractionRatio;
29508 this.wireframe = source.wireframe;
29509 this.wireframeLinewidth = source.wireframeLinewidth;
29510 this.wireframeLinecap = source.wireframeLinecap;
29511 this.wireframeLinejoin = source.wireframeLinejoin;
29513 this.skinning = source.skinning;
29514 this.morphTargets = source.morphTargets;
29515 this.morphNormals = source.morphNormals;
29522 * @author takahirox / http://github.com/takahirox
29525 * gradientMap: new THREE.Texture( <Image> )
29529 function MeshToonMaterial( parameters ) {
29531 MeshPhongMaterial.call( this );
29533 this.defines = { 'TOON': '' };
29535 this.type = 'MeshToonMaterial';
29537 this.gradientMap = null;
29539 this.setValues( parameters );
29543 MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );
29544 MeshToonMaterial.prototype.constructor = MeshToonMaterial;
29546 MeshToonMaterial.prototype.isMeshToonMaterial = true;
29548 MeshToonMaterial.prototype.copy = function ( source ) {
29550 MeshPhongMaterial.prototype.copy.call( this, source );
29552 this.gradientMap = source.gradientMap;
29559 * @author mrdoob / http://mrdoob.com/
29560 * @author WestLangley / http://github.com/WestLangley
29563 * opacity: <float>,
29565 * bumpMap: new THREE.Texture( <Image> ),
29566 * bumpScale: <float>,
29568 * normalMap: new THREE.Texture( <Image> ),
29569 * normalScale: <Vector2>,
29571 * displacementMap: new THREE.Texture( <Image> ),
29572 * displacementScale: <float>,
29573 * displacementBias: <float>,
29575 * wireframe: <boolean>,
29576 * wireframeLinewidth: <float>
29578 * skinning: <bool>,
29579 * morphTargets: <bool>,
29580 * morphNormals: <bool>
29584 function MeshNormalMaterial( parameters ) {
29586 Material.call( this );
29588 this.type = 'MeshNormalMaterial';
29590 this.bumpMap = null;
29591 this.bumpScale = 1;
29593 this.normalMap = null;
29594 this.normalScale = new Vector2( 1, 1 );
29596 this.displacementMap = null;
29597 this.displacementScale = 1;
29598 this.displacementBias = 0;
29600 this.wireframe = false;
29601 this.wireframeLinewidth = 1;
29604 this.lights = false;
29606 this.skinning = false;
29607 this.morphTargets = false;
29608 this.morphNormals = false;
29610 this.setValues( parameters );
29614 MeshNormalMaterial.prototype = Object.create( Material.prototype );
29615 MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
29617 MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
29619 MeshNormalMaterial.prototype.copy = function ( source ) {
29621 Material.prototype.copy.call( this, source );
29623 this.bumpMap = source.bumpMap;
29624 this.bumpScale = source.bumpScale;
29626 this.normalMap = source.normalMap;
29627 this.normalScale.copy( source.normalScale );
29629 this.displacementMap = source.displacementMap;
29630 this.displacementScale = source.displacementScale;
29631 this.displacementBias = source.displacementBias;
29633 this.wireframe = source.wireframe;
29634 this.wireframeLinewidth = source.wireframeLinewidth;
29636 this.skinning = source.skinning;
29637 this.morphTargets = source.morphTargets;
29638 this.morphNormals = source.morphNormals;
29645 * @author mrdoob / http://mrdoob.com/
29646 * @author alteredq / http://alteredqualia.com/
29650 * opacity: <float>,
29652 * map: new THREE.Texture( <Image> ),
29654 * lightMap: new THREE.Texture( <Image> ),
29655 * lightMapIntensity: <float>
29657 * aoMap: new THREE.Texture( <Image> ),
29658 * aoMapIntensity: <float>
29661 * emissiveIntensity: <float>
29662 * emissiveMap: new THREE.Texture( <Image> ),
29664 * specularMap: new THREE.Texture( <Image> ),
29666 * alphaMap: new THREE.Texture( <Image> ),
29668 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
29669 * combine: THREE.Multiply,
29670 * reflectivity: <float>,
29671 * refractionRatio: <float>,
29673 * wireframe: <boolean>,
29674 * wireframeLinewidth: <float>,
29676 * skinning: <bool>,
29677 * morphTargets: <bool>,
29678 * morphNormals: <bool>
29682 function MeshLambertMaterial( parameters ) {
29684 Material.call( this );
29686 this.type = 'MeshLambertMaterial';
29688 this.color = new Color( 0xffffff ); // diffuse
29692 this.lightMap = null;
29693 this.lightMapIntensity = 1.0;
29696 this.aoMapIntensity = 1.0;
29698 this.emissive = new Color( 0x000000 );
29699 this.emissiveIntensity = 1.0;
29700 this.emissiveMap = null;
29702 this.specularMap = null;
29704 this.alphaMap = null;
29706 this.envMap = null;
29707 this.combine = MultiplyOperation;
29708 this.reflectivity = 1;
29709 this.refractionRatio = 0.98;
29711 this.wireframe = false;
29712 this.wireframeLinewidth = 1;
29713 this.wireframeLinecap = 'round';
29714 this.wireframeLinejoin = 'round';
29716 this.skinning = false;
29717 this.morphTargets = false;
29718 this.morphNormals = false;
29720 this.setValues( parameters );
29724 MeshLambertMaterial.prototype = Object.create( Material.prototype );
29725 MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
29727 MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
29729 MeshLambertMaterial.prototype.copy = function ( source ) {
29731 Material.prototype.copy.call( this, source );
29733 this.color.copy( source.color );
29735 this.map = source.map;
29737 this.lightMap = source.lightMap;
29738 this.lightMapIntensity = source.lightMapIntensity;
29740 this.aoMap = source.aoMap;
29741 this.aoMapIntensity = source.aoMapIntensity;
29743 this.emissive.copy( source.emissive );
29744 this.emissiveMap = source.emissiveMap;
29745 this.emissiveIntensity = source.emissiveIntensity;
29747 this.specularMap = source.specularMap;
29749 this.alphaMap = source.alphaMap;
29751 this.envMap = source.envMap;
29752 this.combine = source.combine;
29753 this.reflectivity = source.reflectivity;
29754 this.refractionRatio = source.refractionRatio;
29756 this.wireframe = source.wireframe;
29757 this.wireframeLinewidth = source.wireframeLinewidth;
29758 this.wireframeLinecap = source.wireframeLinecap;
29759 this.wireframeLinejoin = source.wireframeLinejoin;
29761 this.skinning = source.skinning;
29762 this.morphTargets = source.morphTargets;
29763 this.morphNormals = source.morphNormals;
29770 * @author alteredq / http://alteredqualia.com/
29774 * opacity: <float>,
29776 * linewidth: <float>,
29779 * dashSize: <float>,
29784 function LineDashedMaterial( parameters ) {
29786 LineBasicMaterial.call( this );
29788 this.type = 'LineDashedMaterial';
29794 this.setValues( parameters );
29798 LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
29799 LineDashedMaterial.prototype.constructor = LineDashedMaterial;
29801 LineDashedMaterial.prototype.isLineDashedMaterial = true;
29803 LineDashedMaterial.prototype.copy = function ( source ) {
29805 LineBasicMaterial.prototype.copy.call( this, source );
29807 this.scale = source.scale;
29808 this.dashSize = source.dashSize;
29809 this.gapSize = source.gapSize;
29817 var Materials = Object.freeze({
29818 ShadowMaterial: ShadowMaterial,
29819 SpriteMaterial: SpriteMaterial,
29820 RawShaderMaterial: RawShaderMaterial,
29821 ShaderMaterial: ShaderMaterial,
29822 PointsMaterial: PointsMaterial,
29823 MeshPhysicalMaterial: MeshPhysicalMaterial,
29824 MeshStandardMaterial: MeshStandardMaterial,
29825 MeshPhongMaterial: MeshPhongMaterial,
29826 MeshToonMaterial: MeshToonMaterial,
29827 MeshNormalMaterial: MeshNormalMaterial,
29828 MeshLambertMaterial: MeshLambertMaterial,
29829 MeshDepthMaterial: MeshDepthMaterial,
29830 MeshDistanceMaterial: MeshDistanceMaterial,
29831 MeshBasicMaterial: MeshBasicMaterial,
29832 LineDashedMaterial: LineDashedMaterial,
29833 LineBasicMaterial: LineBasicMaterial,
29838 * @author mrdoob / http://mrdoob.com/
29847 add: function ( key, file ) {
29849 if ( this.enabled === false ) return;
29851 // console.log( 'THREE.Cache', 'Adding key:', key );
29853 this.files[ key ] = file;
29857 get: function ( key ) {
29859 if ( this.enabled === false ) return;
29861 // console.log( 'THREE.Cache', 'Checking key:', key );
29863 return this.files[ key ];
29867 remove: function ( key ) {
29869 delete this.files[ key ];
29873 clear: function () {
29882 * @author mrdoob / http://mrdoob.com/
29885 function LoadingManager( onLoad, onProgress, onError ) {
29889 var isLoading = false, itemsLoaded = 0, itemsTotal = 0;
29891 this.onStart = undefined;
29892 this.onLoad = onLoad;
29893 this.onProgress = onProgress;
29894 this.onError = onError;
29896 this.itemStart = function ( url ) {
29900 if ( isLoading === false ) {
29902 if ( scope.onStart !== undefined ) {
29904 scope.onStart( url, itemsLoaded, itemsTotal );
29914 this.itemEnd = function ( url ) {
29918 if ( scope.onProgress !== undefined ) {
29920 scope.onProgress( url, itemsLoaded, itemsTotal );
29924 if ( itemsLoaded === itemsTotal ) {
29928 if ( scope.onLoad !== undefined ) {
29938 this.itemError = function ( url ) {
29940 if ( scope.onError !== undefined ) {
29942 scope.onError( url );
29950 var DefaultLoadingManager = new LoadingManager();
29953 * @author mrdoob / http://mrdoob.com/
29956 function FileLoader( manager ) {
29958 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
29962 Object.assign( FileLoader.prototype, {
29964 load: function ( url, onLoad, onProgress, onError ) {
29966 if ( url === undefined ) url = '';
29968 if ( this.path !== undefined ) url = this.path + url;
29972 var cached = Cache.get( url );
29974 if ( cached !== undefined ) {
29976 scope.manager.itemStart( url );
29978 setTimeout( function () {
29980 if ( onLoad ) onLoad( cached );
29982 scope.manager.itemEnd( url );
29990 // Check for data: URI
29991 var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
29992 var dataUriRegexResult = url.match( dataUriRegex );
29994 // Safari can not handle Data URIs through XMLHttpRequest so process manually
29995 if ( dataUriRegexResult ) {
29997 var mimeType = dataUriRegexResult[ 1 ];
29998 var isBase64 = !! dataUriRegexResult[ 2 ];
29999 var data = dataUriRegexResult[ 3 ];
30001 data = window.decodeURIComponent( data );
30003 if ( isBase64 ) data = window.atob( data );
30008 var responseType = ( this.responseType || '' ).toLowerCase();
30010 switch ( responseType ) {
30012 case 'arraybuffer':
30015 response = new ArrayBuffer( data.length );
30017 var view = new Uint8Array( response );
30019 for ( var i = 0; i < data.length; i ++ ) {
30021 view[ i ] = data.charCodeAt( i );
30025 if ( responseType === 'blob' ) {
30027 response = new Blob( [ response ], { type: mimeType } );
30035 var parser = new DOMParser();
30036 response = parser.parseFromString( data, mimeType );
30042 response = JSON.parse( data );
30046 default: // 'text' or other
30054 // Wait for next browser tick
30055 window.setTimeout( function () {
30057 if ( onLoad ) onLoad( response );
30059 scope.manager.itemEnd( url );
30063 } catch ( error ) {
30065 // Wait for next browser tick
30066 window.setTimeout( function () {
30068 if ( onError ) onError( error );
30070 scope.manager.itemEnd( url );
30071 scope.manager.itemError( url );
30079 var request = new XMLHttpRequest();
30080 request.open( 'GET', url, true );
30082 request.addEventListener( 'load', function ( event ) {
30084 var response = event.target.response;
30086 Cache.add( url, response );
30088 if ( this.status === 200 ) {
30090 if ( onLoad ) onLoad( response );
30092 scope.manager.itemEnd( url );
30094 } else if ( this.status === 0 ) {
30096 // Some browsers return HTTP Status 0 when using non-http protocol
30097 // e.g. 'file://' or 'data://'. Handle as success.
30099 console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
30101 if ( onLoad ) onLoad( response );
30103 scope.manager.itemEnd( url );
30107 if ( onError ) onError( event );
30109 scope.manager.itemEnd( url );
30110 scope.manager.itemError( url );
30116 if ( onProgress !== undefined ) {
30118 request.addEventListener( 'progress', function ( event ) {
30120 onProgress( event );
30126 request.addEventListener( 'error', function ( event ) {
30128 if ( onError ) onError( event );
30130 scope.manager.itemEnd( url );
30131 scope.manager.itemError( url );
30135 if ( this.responseType !== undefined ) request.responseType = this.responseType;
30136 if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
30138 if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
30140 for ( var header in this.requestHeader ) {
30142 request.setRequestHeader( header, this.requestHeader[ header ] );
30146 request.send( null );
30150 scope.manager.itemStart( url );
30156 setPath: function ( value ) {
30163 setResponseType: function ( value ) {
30165 this.responseType = value;
30170 setWithCredentials: function ( value ) {
30172 this.withCredentials = value;
30177 setMimeType: function ( value ) {
30179 this.mimeType = value;
30184 setRequestHeader: function ( value ) {
30186 this.requestHeader = value;
30194 * @author mrdoob / http://mrdoob.com/
30196 * Abstract Base class to block based textures loader (dds, pvr, ...)
30199 function CompressedTextureLoader( manager ) {
30201 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
30203 // override in sub classes
30204 this._parser = null;
30208 Object.assign( CompressedTextureLoader.prototype, {
30210 load: function ( url, onLoad, onProgress, onError ) {
30216 var texture = new CompressedTexture();
30217 texture.image = images;
30219 var loader = new FileLoader( this.manager );
30220 loader.setPath( this.path );
30221 loader.setResponseType( 'arraybuffer' );
30223 function loadTexture( i ) {
30225 loader.load( url[ i ], function ( buffer ) {
30227 var texDatas = scope._parser( buffer, true );
30230 width: texDatas.width,
30231 height: texDatas.height,
30232 format: texDatas.format,
30233 mipmaps: texDatas.mipmaps
30238 if ( loaded === 6 ) {
30240 if ( texDatas.mipmapCount === 1 )
30241 texture.minFilter = LinearFilter;
30243 texture.format = texDatas.format;
30244 texture.needsUpdate = true;
30246 if ( onLoad ) onLoad( texture );
30250 }, onProgress, onError );
30254 if ( Array.isArray( url ) ) {
30258 for ( var i = 0, il = url.length; i < il; ++ i ) {
30266 // compressed cubemap texture stored in a single DDS file
30268 loader.load( url, function ( buffer ) {
30270 var texDatas = scope._parser( buffer, true );
30272 if ( texDatas.isCubemap ) {
30274 var faces = texDatas.mipmaps.length / texDatas.mipmapCount;
30276 for ( var f = 0; f < faces; f ++ ) {
30278 images[ f ] = { mipmaps : [] };
30280 for ( var i = 0; i < texDatas.mipmapCount; i ++ ) {
30282 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
30283 images[ f ].format = texDatas.format;
30284 images[ f ].width = texDatas.width;
30285 images[ f ].height = texDatas.height;
30293 texture.image.width = texDatas.width;
30294 texture.image.height = texDatas.height;
30295 texture.mipmaps = texDatas.mipmaps;
30299 if ( texDatas.mipmapCount === 1 ) {
30301 texture.minFilter = LinearFilter;
30305 texture.format = texDatas.format;
30306 texture.needsUpdate = true;
30308 if ( onLoad ) onLoad( texture );
30310 }, onProgress, onError );
30318 setPath: function ( value ) {
30328 * @author Nikos M. / https://github.com/foo123/
30330 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
30333 function DataTextureLoader( manager ) {
30335 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
30337 // override in sub classes
30338 this._parser = null;
30342 Object.assign( DataTextureLoader.prototype, {
30344 load: function ( url, onLoad, onProgress, onError ) {
30348 var texture = new DataTexture();
30350 var loader = new FileLoader( this.manager );
30351 loader.setResponseType( 'arraybuffer' );
30353 loader.load( url, function ( buffer ) {
30355 var texData = scope._parser( buffer );
30357 if ( ! texData ) return;
30359 if ( undefined !== texData.image ) {
30361 texture.image = texData.image;
30363 } else if ( undefined !== texData.data ) {
30365 texture.image.width = texData.width;
30366 texture.image.height = texData.height;
30367 texture.image.data = texData.data;
30371 texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;
30372 texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;
30374 texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;
30375 texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;
30377 texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;
30379 if ( undefined !== texData.format ) {
30381 texture.format = texData.format;
30384 if ( undefined !== texData.type ) {
30386 texture.type = texData.type;
30390 if ( undefined !== texData.mipmaps ) {
30392 texture.mipmaps = texData.mipmaps;
30396 if ( 1 === texData.mipmapCount ) {
30398 texture.minFilter = LinearFilter;
30402 texture.needsUpdate = true;
30404 if ( onLoad ) onLoad( texture, texData );
30406 }, onProgress, onError );
30416 * @author mrdoob / http://mrdoob.com/
30419 function ImageLoader( manager ) {
30421 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
30425 Object.assign( ImageLoader.prototype, {
30427 crossOrigin: 'Anonymous',
30429 load: function ( url, onLoad, onProgress, onError ) {
30431 if ( url === undefined ) url = '';
30433 if ( this.path !== undefined ) url = this.path + url;
30437 var cached = Cache.get( url );
30439 if ( cached !== undefined ) {
30441 scope.manager.itemStart( url );
30443 setTimeout( function () {
30445 if ( onLoad ) onLoad( cached );
30447 scope.manager.itemEnd( url );
30455 var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
30457 image.addEventListener( 'load', function () {
30459 Cache.add( url, this );
30461 if ( onLoad ) onLoad( this );
30463 scope.manager.itemEnd( url );
30468 image.addEventListener( 'progress', function ( event ) {
30470 if ( onProgress ) onProgress( event );
30475 image.addEventListener( 'error', function ( event ) {
30477 if ( onError ) onError( event );
30479 scope.manager.itemEnd( url );
30480 scope.manager.itemError( url );
30484 if ( url.substr( 0, 5 ) !== 'data:' ) {
30486 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
30490 scope.manager.itemStart( url );
30498 setCrossOrigin: function ( value ) {
30500 this.crossOrigin = value;
30505 setPath: function ( value ) {
30515 * @author mrdoob / http://mrdoob.com/
30518 function CubeTextureLoader( manager ) {
30520 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
30524 Object.assign( CubeTextureLoader.prototype, {
30526 crossOrigin: 'Anonymous',
30528 load: function ( urls, onLoad, onProgress, onError ) {
30530 var texture = new CubeTexture();
30532 var loader = new ImageLoader( this.manager );
30533 loader.setCrossOrigin( this.crossOrigin );
30534 loader.setPath( this.path );
30538 function loadTexture( i ) {
30540 loader.load( urls[ i ], function ( image ) {
30542 texture.images[ i ] = image;
30546 if ( loaded === 6 ) {
30548 texture.needsUpdate = true;
30550 if ( onLoad ) onLoad( texture );
30554 }, undefined, onError );
30558 for ( var i = 0; i < urls.length; ++ i ) {
30568 setCrossOrigin: function ( value ) {
30570 this.crossOrigin = value;
30575 setPath: function ( value ) {
30585 * @author mrdoob / http://mrdoob.com/
30588 function TextureLoader( manager ) {
30590 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
30594 Object.assign( TextureLoader.prototype, {
30596 crossOrigin: 'Anonymous',
30598 load: function ( url, onLoad, onProgress, onError ) {
30600 var loader = new ImageLoader( this.manager );
30601 loader.setCrossOrigin( this.crossOrigin );
30602 loader.setPath( this.path );
30604 var texture = new Texture();
30605 texture.image = loader.load( url, function () {
30607 // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
30608 var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
30610 texture.format = isJPEG ? RGBFormat : RGBAFormat;
30611 texture.needsUpdate = true;
30613 if ( onLoad !== undefined ) {
30619 }, onProgress, onError );
30625 setCrossOrigin: function ( value ) {
30627 this.crossOrigin = value;
30632 setPath: function ( value ) {
30642 * @author mrdoob / http://mrdoob.com/
30643 * @author alteredq / http://alteredqualia.com/
30646 function Light( color, intensity ) {
30648 Object3D.call( this );
30650 this.type = 'Light';
30652 this.color = new Color( color );
30653 this.intensity = intensity !== undefined ? intensity : 1;
30655 this.receiveShadow = undefined;
30659 Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
30661 constructor: Light,
30665 copy: function ( source ) {
30667 Object3D.prototype.copy.call( this, source );
30669 this.color.copy( source.color );
30670 this.intensity = source.intensity;
30676 toJSON: function ( meta ) {
30678 var data = Object3D.prototype.toJSON.call( this, meta );
30680 data.object.color = this.color.getHex();
30681 data.object.intensity = this.intensity;
30683 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
30685 if ( this.distance !== undefined ) data.object.distance = this.distance;
30686 if ( this.angle !== undefined ) data.object.angle = this.angle;
30687 if ( this.decay !== undefined ) data.object.decay = this.decay;
30688 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
30690 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
30699 * @author alteredq / http://alteredqualia.com/
30702 function HemisphereLight( skyColor, groundColor, intensity ) {
30704 Light.call( this, skyColor, intensity );
30706 this.type = 'HemisphereLight';
30708 this.castShadow = undefined;
30710 this.position.copy( Object3D.DefaultUp );
30711 this.updateMatrix();
30713 this.groundColor = new Color( groundColor );
30717 HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
30719 constructor: HemisphereLight,
30721 isHemisphereLight: true,
30723 copy: function ( source ) {
30725 Light.prototype.copy.call( this, source );
30727 this.groundColor.copy( source.groundColor );
30736 * @author mrdoob / http://mrdoob.com/
30739 function LightShadow( camera ) {
30741 this.camera = camera;
30746 this.mapSize = new Vector2( 512, 512 );
30749 this.matrix = new Matrix4();
30753 Object.assign( LightShadow.prototype, {
30755 copy: function ( source ) {
30757 this.camera = source.camera.clone();
30759 this.bias = source.bias;
30760 this.radius = source.radius;
30762 this.mapSize.copy( source.mapSize );
30768 clone: function () {
30770 return new this.constructor().copy( this );
30774 toJSON: function () {
30778 if ( this.bias !== 0 ) object.bias = this.bias;
30779 if ( this.radius !== 1 ) object.radius = this.radius;
30780 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
30782 object.camera = this.camera.toJSON( false ).object;
30783 delete object.camera.matrix;
30792 * @author mrdoob / http://mrdoob.com/
30795 function SpotLightShadow() {
30797 LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
30801 SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
30803 constructor: SpotLightShadow,
30805 isSpotLightShadow: true,
30807 update: function ( light ) {
30809 var camera = this.camera;
30811 var fov = _Math.RAD2DEG * 2 * light.angle;
30812 var aspect = this.mapSize.width / this.mapSize.height;
30813 var far = light.distance || camera.far;
30815 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
30818 camera.aspect = aspect;
30820 camera.updateProjectionMatrix();
30829 * @author alteredq / http://alteredqualia.com/
30832 function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
30834 Light.call( this, color, intensity );
30836 this.type = 'SpotLight';
30838 this.position.copy( Object3D.DefaultUp );
30839 this.updateMatrix();
30841 this.target = new Object3D();
30843 Object.defineProperty( this, 'power', {
30845 // intensity = power per solid angle.
30846 // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
30847 return this.intensity * Math.PI;
30849 set: function ( power ) {
30850 // intensity = power per solid angle.
30851 // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
30852 this.intensity = power / Math.PI;
30856 this.distance = ( distance !== undefined ) ? distance : 0;
30857 this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
30858 this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
30859 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
30861 this.shadow = new SpotLightShadow();
30865 SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
30867 constructor: SpotLight,
30871 copy: function ( source ) {
30873 Light.prototype.copy.call( this, source );
30875 this.distance = source.distance;
30876 this.angle = source.angle;
30877 this.penumbra = source.penumbra;
30878 this.decay = source.decay;
30880 this.target = source.target.clone();
30882 this.shadow = source.shadow.clone();
30891 * @author mrdoob / http://mrdoob.com/
30895 function PointLight( color, intensity, distance, decay ) {
30897 Light.call( this, color, intensity );
30899 this.type = 'PointLight';
30901 Object.defineProperty( this, 'power', {
30903 // intensity = power per solid angle.
30904 // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
30905 return this.intensity * 4 * Math.PI;
30908 set: function ( power ) {
30909 // intensity = power per solid angle.
30910 // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
30911 this.intensity = power / ( 4 * Math.PI );
30915 this.distance = ( distance !== undefined ) ? distance : 0;
30916 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2.
30918 this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
30922 PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
30924 constructor: PointLight,
30926 isPointLight: true,
30928 copy: function ( source ) {
30930 Light.prototype.copy.call( this, source );
30932 this.distance = source.distance;
30933 this.decay = source.decay;
30935 this.shadow = source.shadow.clone();
30944 * @author mrdoob / http://mrdoob.com/
30947 function DirectionalLightShadow( ) {
30949 LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
30953 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
30955 constructor: DirectionalLightShadow
30960 * @author mrdoob / http://mrdoob.com/
30961 * @author alteredq / http://alteredqualia.com/
30964 function DirectionalLight( color, intensity ) {
30966 Light.call( this, color, intensity );
30968 this.type = 'DirectionalLight';
30970 this.position.copy( Object3D.DefaultUp );
30971 this.updateMatrix();
30973 this.target = new Object3D();
30975 this.shadow = new DirectionalLightShadow();
30979 DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
30981 constructor: DirectionalLight,
30983 isDirectionalLight: true,
30985 copy: function ( source ) {
30987 Light.prototype.copy.call( this, source );
30989 this.target = source.target.clone();
30991 this.shadow = source.shadow.clone();
31000 * @author mrdoob / http://mrdoob.com/
31003 function AmbientLight( color, intensity ) {
31005 Light.call( this, color, intensity );
31007 this.type = 'AmbientLight';
31009 this.castShadow = undefined;
31013 AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
31015 constructor: AmbientLight,
31017 isAmbientLight: true
31022 * @author abelnation / http://github.com/abelnation
31025 function RectAreaLight( color, intensity, width, height ) {
31027 Light.call( this, color, intensity );
31029 this.type = 'RectAreaLight';
31031 this.position.set( 0, 1, 0 );
31032 this.updateMatrix();
31034 this.width = ( width !== undefined ) ? width : 10;
31035 this.height = ( height !== undefined ) ? height : 10;
31037 // TODO (abelnation): distance/decay
31039 // TODO (abelnation): update method for RectAreaLight to update transform to lookat target
31041 // TODO (abelnation): shadows
31045 // TODO (abelnation): RectAreaLight update when light shape is changed
31046 RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
31048 constructor: RectAreaLight,
31050 isRectAreaLight: true,
31052 copy: function ( source ) {
31054 Light.prototype.copy.call( this, source );
31056 this.width = source.width;
31057 this.height = source.height;
31063 toJSON: function ( meta ) {
31065 var data = Light.prototype.toJSON.call( this, meta );
31067 data.object.width = this.width;
31068 data.object.height = this.height;
31078 * @author Ben Houston / http://clara.io/
31079 * @author David Sarno / http://lighthaus.us/
31082 var AnimationUtils = {
31084 // same as Array.prototype.slice, but also works on typed arrays
31085 arraySlice: function ( array, from, to ) {
31087 if ( AnimationUtils.isTypedArray( array ) ) {
31089 // in ios9 array.subarray(from, undefined) will return empty array
31090 // but array.subarray(from) or array.subarray(from, len) is correct
31091 return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
31095 return array.slice( from, to );
31099 // converts an array to a specific type
31100 convertArray: function ( array, type, forceClone ) {
31102 if ( ! array || // let 'undefined' and 'null' pass
31103 ! forceClone && array.constructor === type ) return array;
31105 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
31107 return new type( array ); // create typed array
31111 return Array.prototype.slice.call( array ); // create Array
31115 isTypedArray: function ( object ) {
31117 return ArrayBuffer.isView( object ) &&
31118 ! ( object instanceof DataView );
31122 // returns an array by which times and values can be sorted
31123 getKeyframeOrder: function ( times ) {
31125 function compareTime( i, j ) {
31127 return times[ i ] - times[ j ];
31131 var n = times.length;
31132 var result = new Array( n );
31133 for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
31135 result.sort( compareTime );
31141 // uses the array previously returned by 'getKeyframeOrder' to sort data
31142 sortedArray: function ( values, stride, order ) {
31144 var nValues = values.length;
31145 var result = new values.constructor( nValues );
31147 for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
31149 var srcOffset = order[ i ] * stride;
31151 for ( var j = 0; j !== stride; ++ j ) {
31153 result[ dstOffset ++ ] = values[ srcOffset + j ];
31163 // function for parsing AOS keyframe formats
31164 flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
31166 var i = 1, key = jsonKeys[ 0 ];
31168 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
31170 key = jsonKeys[ i ++ ];
31174 if ( key === undefined ) return; // no data
31176 var value = key[ valuePropertyName ];
31177 if ( value === undefined ) return; // no data
31179 if ( Array.isArray( value ) ) {
31183 value = key[ valuePropertyName ];
31185 if ( value !== undefined ) {
31187 times.push( key.time );
31188 values.push.apply( values, value ); // push all elements
31192 key = jsonKeys[ i ++ ];
31194 } while ( key !== undefined );
31196 } else if ( value.toArray !== undefined ) {
31198 // ...assume THREE.Math-ish
31202 value = key[ valuePropertyName ];
31204 if ( value !== undefined ) {
31206 times.push( key.time );
31207 value.toArray( values, values.length );
31211 key = jsonKeys[ i ++ ];
31213 } while ( key !== undefined );
31217 // otherwise push as-is
31221 value = key[ valuePropertyName ];
31223 if ( value !== undefined ) {
31225 times.push( key.time );
31226 values.push( value );
31230 key = jsonKeys[ i ++ ];
31232 } while ( key !== undefined );
31241 * Abstract base class of interpolants over parametric samples.
31243 * The parameter domain is one dimensional, typically the time or a path
31244 * along a curve defined by the data.
31246 * The sample values can have any dimensionality and derived classes may
31247 * apply special interpretations to the data.
31249 * This class provides the interval seek in a Template Method, deferring
31250 * the actual interpolation to derived classes.
31252 * Time complexity is O(1) for linear access crossing at most two points
31253 * and O(log N) for random access, where N is the number of positions.
31257 * http://www.oodesign.com/template-method-pattern.html
31262 function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
31264 this.parameterPositions = parameterPositions;
31265 this._cachedIndex = 0;
31267 this.resultBuffer = resultBuffer !== undefined ?
31268 resultBuffer : new sampleValues.constructor( sampleSize );
31269 this.sampleValues = sampleValues;
31270 this.valueSize = sampleSize;
31274 Object.assign( Interpolant.prototype, {
31276 evaluate: function( t ) {
31278 var pp = this.parameterPositions,
31279 i1 = this._cachedIndex,
31284 validate_interval: {
31291 //- See http://jsperf.com/comparison-to-undefined/3
31294 //- if ( t >= t1 || t1 === undefined ) {
31295 forward_scan: if ( ! ( t < t1 ) ) {
31297 for ( var giveUpAt = i1 + 2; ;) {
31299 if ( t1 === undefined ) {
31301 if ( t < t0 ) break forward_scan;
31306 this._cachedIndex = i1;
31307 return this.afterEnd_( i1 - 1, t, t0 );
31311 if ( i1 === giveUpAt ) break; // this loop
31318 // we have arrived at the sought interval
31325 // prepare binary search on the right side of the index
31332 //- if ( t < t0 || t0 === undefined ) {
31333 if ( ! ( t >= t0 ) ) {
31337 var t1global = pp[ 1 ];
31339 if ( t < t1global ) {
31341 i1 = 2; // + 1, using the scan for the details
31346 // linear reverse scan
31348 for ( var giveUpAt = i1 - 2; ;) {
31350 if ( t0 === undefined ) {
31354 this._cachedIndex = 0;
31355 return this.beforeStart_( 0, t, t1 );
31359 if ( i1 === giveUpAt ) break; // this loop
31362 t0 = pp[ -- i1 - 1 ];
31366 // we have arrived at the sought interval
31373 // prepare binary search on the left side of the index
31380 // the interval is valid
31382 break validate_interval;
31388 while ( i1 < right ) {
31390 var mid = ( i1 + right ) >>> 1;
31392 if ( t < pp[ mid ] ) {
31407 // check boundary cases, again
31409 if ( t0 === undefined ) {
31411 this._cachedIndex = 0;
31412 return this.beforeStart_( 0, t, t1 );
31416 if ( t1 === undefined ) {
31419 this._cachedIndex = i1;
31420 return this.afterEnd_( i1 - 1, t0, t );
31426 this._cachedIndex = i1;
31428 this.intervalChanged_( i1, t0, t1 );
31430 } // validate_interval
31432 return this.interpolate_( i1, t0, t, t1 );
31436 settings: null, // optional, subclass-specific settings structure
31437 // Note: The indirection allows central control of many interpolants.
31439 // --- Protected interface
31441 DefaultSettings_: {},
31443 getSettings_: function() {
31445 return this.settings || this.DefaultSettings_;
31449 copySampleValue_: function( index ) {
31451 // copies a sample value to the result buffer
31453 var result = this.resultBuffer,
31454 values = this.sampleValues,
31455 stride = this.valueSize,
31456 offset = index * stride;
31458 for ( var i = 0; i !== stride; ++ i ) {
31460 result[ i ] = values[ offset + i ];
31468 // Template methods for derived classes:
31470 interpolate_: function( i1, t0, t, t1 ) {
31472 throw new Error( "call to abstract method" );
31473 // implementations shall return this.resultBuffer
31477 intervalChanged_: function( i1, t0, t1 ) {
31485 //!\ DECLARE ALIAS AFTER assign prototype !
31486 Object.assign( Interpolant.prototype, {
31488 //( 0, t, t0 ), returns this.resultBuffer
31489 beforeStart_: Interpolant.prototype.copySampleValue_,
31491 //( N-1, tN-1, t ), returns this.resultBuffer
31492 afterEnd_: Interpolant.prototype.copySampleValue_,
31497 * Fast and simple cubic spline interpolant.
31499 * It was derived from a Hermitian construction setting the first derivative
31500 * at each sample position to the linear slope between neighboring positions
31501 * over their parameter interval.
31506 function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
31509 this, parameterPositions, sampleValues, sampleSize, resultBuffer );
31511 this._weightPrev = -0;
31512 this._offsetPrev = -0;
31513 this._weightNext = -0;
31514 this._offsetNext = -0;
31518 CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
31520 constructor: CubicInterpolant,
31522 DefaultSettings_: {
31524 endingStart: ZeroCurvatureEnding,
31525 endingEnd: ZeroCurvatureEnding
31529 intervalChanged_: function( i1, t0, t1 ) {
31531 var pp = this.parameterPositions,
31535 tPrev = pp[ iPrev ],
31536 tNext = pp[ iNext ];
31538 if ( tPrev === undefined ) {
31540 switch ( this.getSettings_().endingStart ) {
31542 case ZeroSlopeEnding:
31546 tPrev = 2 * t0 - t1;
31550 case WrapAroundEnding:
31552 // use the other end of the curve
31553 iPrev = pp.length - 2;
31554 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
31558 default: // ZeroCurvatureEnding
31560 // f''(t0) = 0 a.k.a. Natural Spline
31568 if ( tNext === undefined ) {
31570 switch ( this.getSettings_().endingEnd ) {
31572 case ZeroSlopeEnding:
31576 tNext = 2 * t1 - t0;
31580 case WrapAroundEnding:
31582 // use the other end of the curve
31584 tNext = t1 + pp[ 1 ] - pp[ 0 ];
31588 default: // ZeroCurvatureEnding
31590 // f''(tN) = 0, a.k.a. Natural Spline
31598 var halfDt = ( t1 - t0 ) * 0.5,
31599 stride = this.valueSize;
31601 this._weightPrev = halfDt / ( t0 - tPrev );
31602 this._weightNext = halfDt / ( tNext - t1 );
31603 this._offsetPrev = iPrev * stride;
31604 this._offsetNext = iNext * stride;
31608 interpolate_: function( i1, t0, t, t1 ) {
31610 var result = this.resultBuffer,
31611 values = this.sampleValues,
31612 stride = this.valueSize,
31614 o1 = i1 * stride, o0 = o1 - stride,
31615 oP = this._offsetPrev, oN = this._offsetNext,
31616 wP = this._weightPrev, wN = this._weightNext,
31618 p = ( t - t0 ) / ( t1 - t0 ),
31622 // evaluate polynomials
31624 var sP = - wP * ppp + 2 * wP * pp - wP * p;
31625 var s0 = ( 1 + wP ) * ppp + (-1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1;
31626 var s1 = (-1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
31627 var sN = wN * ppp - wN * pp;
31629 // combine data linearly
31631 for ( var i = 0; i !== stride; ++ i ) {
31634 sP * values[ oP + i ] +
31635 s0 * values[ o0 + i ] +
31636 s1 * values[ o1 + i ] +
31637 sN * values[ oN + i ];
31651 function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
31653 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
31657 LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
31659 constructor: LinearInterpolant,
31661 interpolate_: function( i1, t0, t, t1 ) {
31663 var result = this.resultBuffer,
31664 values = this.sampleValues,
31665 stride = this.valueSize,
31667 offset1 = i1 * stride,
31668 offset0 = offset1 - stride,
31670 weight1 = ( t - t0 ) / ( t1 - t0 ),
31671 weight0 = 1 - weight1;
31673 for ( var i = 0; i !== stride; ++ i ) {
31676 values[ offset0 + i ] * weight0 +
31677 values[ offset1 + i ] * weight1;
31689 * Interpolant that evaluates to the sample value at the position preceeding
31695 function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
31697 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
31701 DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
31703 constructor: DiscreteInterpolant,
31705 interpolate_: function( i1, t0, t, t1 ) {
31707 return this.copySampleValue_( i1 - 1 );
31713 var KeyframeTrackPrototype;
31715 KeyframeTrackPrototype = {
31717 TimeBufferType: Float32Array,
31718 ValueBufferType: Float32Array,
31720 DefaultInterpolation: InterpolateLinear,
31722 InterpolantFactoryMethodDiscrete: function ( result ) {
31724 return new DiscreteInterpolant(
31725 this.times, this.values, this.getValueSize(), result );
31729 InterpolantFactoryMethodLinear: function ( result ) {
31731 return new LinearInterpolant(
31732 this.times, this.values, this.getValueSize(), result );
31736 InterpolantFactoryMethodSmooth: function ( result ) {
31738 return new CubicInterpolant(
31739 this.times, this.values, this.getValueSize(), result );
31743 setInterpolation: function ( interpolation ) {
31747 switch ( interpolation ) {
31749 case InterpolateDiscrete:
31751 factoryMethod = this.InterpolantFactoryMethodDiscrete;
31755 case InterpolateLinear:
31757 factoryMethod = this.InterpolantFactoryMethodLinear;
31761 case InterpolateSmooth:
31763 factoryMethod = this.InterpolantFactoryMethodSmooth;
31769 if ( factoryMethod === undefined ) {
31771 var message = "unsupported interpolation for " +
31772 this.ValueTypeName + " keyframe track named " + this.name;
31774 if ( this.createInterpolant === undefined ) {
31776 // fall back to default, unless the default itself is messed up
31777 if ( interpolation !== this.DefaultInterpolation ) {
31779 this.setInterpolation( this.DefaultInterpolation );
31783 throw new Error( message ); // fatal, in this case
31789 console.warn( 'THREE.KeyframeTrackPrototype:', message );
31794 this.createInterpolant = factoryMethod;
31798 getInterpolation: function () {
31800 switch ( this.createInterpolant ) {
31802 case this.InterpolantFactoryMethodDiscrete:
31804 return InterpolateDiscrete;
31806 case this.InterpolantFactoryMethodLinear:
31808 return InterpolateLinear;
31810 case this.InterpolantFactoryMethodSmooth:
31812 return InterpolateSmooth;
31818 getValueSize: function () {
31820 return this.values.length / this.times.length;
31824 // move all keyframes either forwards or backwards in time
31825 shift: function ( timeOffset ) {
31827 if ( timeOffset !== 0.0 ) {
31829 var times = this.times;
31831 for ( var i = 0, n = times.length; i !== n; ++ i ) {
31833 times[ i ] += timeOffset;
31843 // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
31844 scale: function ( timeScale ) {
31846 if ( timeScale !== 1.0 ) {
31848 var times = this.times;
31850 for ( var i = 0, n = times.length; i !== n; ++ i ) {
31852 times[ i ] *= timeScale;
31862 // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
31863 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
31864 trim: function ( startTime, endTime ) {
31866 var times = this.times,
31867 nKeys = times.length,
31871 while ( from !== nKeys && times[ from ] < startTime ) ++ from;
31872 while ( to !== - 1 && times[ to ] > endTime ) -- to;
31874 ++ to; // inclusive -> exclusive bound
31876 if ( from !== 0 || to !== nKeys ) {
31878 // empty tracks are forbidden, so keep at least one keyframe
31879 if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
31881 var stride = this.getValueSize();
31882 this.times = AnimationUtils.arraySlice( times, from, to );
31883 this.values = AnimationUtils.
31884 arraySlice( this.values, from * stride, to * stride );
31892 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
31893 validate: function () {
31897 var valueSize = this.getValueSize();
31898 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
31900 console.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this );
31905 var times = this.times,
31906 values = this.values,
31908 nKeys = times.length;
31910 if ( nKeys === 0 ) {
31912 console.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this );
31917 var prevTime = null;
31919 for ( var i = 0; i !== nKeys; i ++ ) {
31921 var currTime = times[ i ];
31923 if ( typeof currTime === 'number' && isNaN( currTime ) ) {
31925 console.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime );
31931 if ( prevTime !== null && prevTime > currTime ) {
31933 console.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime );
31939 prevTime = currTime;
31943 if ( values !== undefined ) {
31945 if ( AnimationUtils.isTypedArray( values ) ) {
31947 for ( var i = 0, n = values.length; i !== n; ++ i ) {
31949 var value = values[ i ];
31951 if ( isNaN( value ) ) {
31953 console.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value );
31969 // removes equivalent sequential keys as common in morph target sequences
31970 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
31971 optimize: function () {
31973 var times = this.times,
31974 values = this.values,
31975 stride = this.getValueSize(),
31977 smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
31980 lastIndex = times.length - 1;
31982 for ( var i = 1; i < lastIndex; ++ i ) {
31986 var time = times[ i ];
31987 var timeNext = times[ i + 1 ];
31989 // remove adjacent keyframes scheduled at the same time
31991 if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
31993 if ( ! smoothInterpolation ) {
31995 // remove unnecessary keyframes same as their neighbors
31997 var offset = i * stride,
31998 offsetP = offset - stride,
31999 offsetN = offset + stride;
32001 for ( var j = 0; j !== stride; ++ j ) {
32003 var value = values[ offset + j ];
32005 if ( value !== values[ offsetP + j ] ||
32006 value !== values[ offsetN + j ] ) {
32015 } else keep = true;
32019 // in-place compaction
32023 if ( i !== writeIndex ) {
32025 times[ writeIndex ] = times[ i ];
32027 var readOffset = i * stride,
32028 writeOffset = writeIndex * stride;
32030 for ( var j = 0; j !== stride; ++ j )
32032 values[ writeOffset + j ] = values[ readOffset + j ];
32042 // flush last keyframe (compaction looks ahead)
32044 if ( lastIndex > 0 ) {
32046 times[ writeIndex ] = times[ lastIndex ];
32048 for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )
32050 values[ writeOffset + j ] = values[ readOffset + j ];
32056 if ( writeIndex !== times.length ) {
32058 this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
32059 this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
32069 function KeyframeTrackConstructor( name, times, values, interpolation ) {
32071 if ( name === undefined ) throw new Error( "track name is undefined" );
32073 if ( times === undefined || times.length === 0 ) {
32075 throw new Error( "no keyframes in track named " + name );
32081 this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
32082 this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
32084 this.setInterpolation( interpolation || this.DefaultInterpolation );
32093 * A Track of vectored keyframe values.
32096 * @author Ben Houston / http://clara.io/
32097 * @author David Sarno / http://lighthaus.us/
32101 function VectorKeyframeTrack( name, times, values, interpolation ) {
32103 KeyframeTrackConstructor.call( this, name, times, values, interpolation );
32107 VectorKeyframeTrack.prototype =
32108 Object.assign( Object.create( KeyframeTrackPrototype ), {
32110 constructor: VectorKeyframeTrack,
32112 ValueTypeName: 'vector'
32114 // ValueBufferType is inherited
32116 // DefaultInterpolation is inherited
32121 * Spherical linear unit quaternion interpolant.
32126 function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
32128 Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
32132 QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
32134 constructor: QuaternionLinearInterpolant,
32136 interpolate_: function( i1, t0, t, t1 ) {
32138 var result = this.resultBuffer,
32139 values = this.sampleValues,
32140 stride = this.valueSize,
32142 offset = i1 * stride,
32144 alpha = ( t - t0 ) / ( t1 - t0 );
32146 for ( var end = offset + stride; offset !== end; offset += 4 ) {
32148 Quaternion.slerpFlat( result, 0,
32149 values, offset - stride, values, offset, alpha );
32161 * A Track of quaternion keyframe values.
32163 * @author Ben Houston / http://clara.io/
32164 * @author David Sarno / http://lighthaus.us/
32168 function QuaternionKeyframeTrack( name, times, values, interpolation ) {
32170 KeyframeTrackConstructor.call( this, name, times, values, interpolation );
32174 QuaternionKeyframeTrack.prototype =
32175 Object.assign( Object.create( KeyframeTrackPrototype ), {
32177 constructor: QuaternionKeyframeTrack,
32179 ValueTypeName: 'quaternion',
32181 // ValueBufferType is inherited
32183 DefaultInterpolation: InterpolateLinear,
32185 InterpolantFactoryMethodLinear: function( result ) {
32187 return new QuaternionLinearInterpolant(
32188 this.times, this.values, this.getValueSize(), result );
32192 InterpolantFactoryMethodSmooth: undefined // not yet implemented
32198 * A Track of numeric keyframe values.
32200 * @author Ben Houston / http://clara.io/
32201 * @author David Sarno / http://lighthaus.us/
32205 function NumberKeyframeTrack( name, times, values, interpolation ) {
32207 KeyframeTrackConstructor.call( this, name, times, values, interpolation );
32211 NumberKeyframeTrack.prototype =
32212 Object.assign( Object.create( KeyframeTrackPrototype ), {
32214 constructor: NumberKeyframeTrack,
32216 ValueTypeName: 'number'
32218 // ValueBufferType is inherited
32220 // DefaultInterpolation is inherited
32226 * A Track that interpolates Strings
32229 * @author Ben Houston / http://clara.io/
32230 * @author David Sarno / http://lighthaus.us/
32234 function StringKeyframeTrack( name, times, values, interpolation ) {
32236 KeyframeTrackConstructor.call( this, name, times, values, interpolation );
32240 StringKeyframeTrack.prototype =
32241 Object.assign( Object.create( KeyframeTrackPrototype ), {
32243 constructor: StringKeyframeTrack,
32245 ValueTypeName: 'string',
32246 ValueBufferType: Array,
32248 DefaultInterpolation: InterpolateDiscrete,
32250 InterpolantFactoryMethodLinear: undefined,
32252 InterpolantFactoryMethodSmooth: undefined
32258 * A Track of Boolean keyframe values.
32261 * @author Ben Houston / http://clara.io/
32262 * @author David Sarno / http://lighthaus.us/
32266 function BooleanKeyframeTrack( name, times, values ) {
32268 KeyframeTrackConstructor.call( this, name, times, values );
32272 BooleanKeyframeTrack.prototype =
32273 Object.assign( Object.create( KeyframeTrackPrototype ), {
32275 constructor: BooleanKeyframeTrack,
32277 ValueTypeName: 'bool',
32278 ValueBufferType: Array,
32280 DefaultInterpolation: InterpolateDiscrete,
32282 InterpolantFactoryMethodLinear: undefined,
32283 InterpolantFactoryMethodSmooth: undefined
32285 // Note: Actually this track could have a optimized / compressed
32286 // representation of a single value and a custom interpolant that
32287 // computes "firstValue ^ isOdd( index )".
32293 * A Track of keyframe values that represent color.
32296 * @author Ben Houston / http://clara.io/
32297 * @author David Sarno / http://lighthaus.us/
32301 function ColorKeyframeTrack( name, times, values, interpolation ) {
32303 KeyframeTrackConstructor.call( this, name, times, values, interpolation );
32307 ColorKeyframeTrack.prototype =
32308 Object.assign( Object.create( KeyframeTrackPrototype ), {
32310 constructor: ColorKeyframeTrack,
32312 ValueTypeName: 'color'
32314 // ValueBufferType is inherited
32316 // DefaultInterpolation is inherited
32319 // Note: Very basic implementation and nothing special yet.
32320 // However, this is the place for color space parameterization.
32326 * A timed sequence of keyframes for a specific property.
32329 * @author Ben Houston / http://clara.io/
32330 * @author David Sarno / http://lighthaus.us/
32334 function KeyframeTrack( name, times, values, interpolation ) {
32336 KeyframeTrackConstructor.apply( this, arguments );
32340 KeyframeTrack.prototype = KeyframeTrackPrototype;
32341 KeyframeTrackPrototype.constructor = KeyframeTrack;
32345 Object.assign( KeyframeTrack, {
32347 // Serialization (in static context, because of constructor invocation
32348 // and automatic invocation of .toJSON):
32350 parse: function( json ) {
32352 if( json.type === undefined ) {
32354 throw new Error( "track type undefined, can not parse" );
32358 var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
32360 if ( json.times === undefined ) {
32362 var times = [], values = [];
32364 AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
32366 json.times = times;
32367 json.values = values;
32371 // derived classes can define a static parse method
32372 if ( trackType.parse !== undefined ) {
32374 return trackType.parse( json );
32378 // by default, we assume a constructor compatible with the base
32379 return new trackType(
32380 json.name, json.times, json.values, json.interpolation );
32386 toJSON: function( track ) {
32388 var trackType = track.constructor;
32392 // derived classes can define a static toJSON method
32393 if ( trackType.toJSON !== undefined ) {
32395 json = trackType.toJSON( track );
32399 // by default, we assume the data can be serialized as-is
32402 'name': track.name,
32403 'times': AnimationUtils.convertArray( track.times, Array ),
32404 'values': AnimationUtils.convertArray( track.values, Array )
32408 var interpolation = track.getInterpolation();
32410 if ( interpolation !== track.DefaultInterpolation ) {
32412 json.interpolation = interpolation;
32418 json.type = track.ValueTypeName; // mandatory
32424 _getTrackTypeForValueTypeName: function( typeName ) {
32426 switch( typeName.toLowerCase() ) {
32434 return NumberKeyframeTrack;
32441 return VectorKeyframeTrack;
32445 return ColorKeyframeTrack;
32449 return QuaternionKeyframeTrack;
32454 return BooleanKeyframeTrack;
32458 return StringKeyframeTrack;
32462 throw new Error( "Unsupported typeName: " + typeName );
32470 * Reusable set of Tracks that represent an animation.
32472 * @author Ben Houston / http://clara.io/
32473 * @author David Sarno / http://lighthaus.us/
32476 function AnimationClip( name, duration, tracks ) {
32479 this.tracks = tracks;
32480 this.duration = ( duration !== undefined ) ? duration : - 1;
32482 this.uuid = _Math.generateUUID();
32484 // this means it should figure out its duration by scanning the tracks
32485 if ( this.duration < 0 ) {
32487 this.resetDuration();
32495 Object.assign( AnimationClip, {
32497 parse: function ( json ) {
32500 jsonTracks = json.tracks,
32501 frameTime = 1.0 / ( json.fps || 1.0 );
32503 for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {
32505 tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );
32509 return new AnimationClip( json.name, json.duration, tracks );
32513 toJSON: function ( clip ) {
32516 clipTracks = clip.tracks;
32521 'duration': clip.duration,
32526 for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {
32528 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
32536 CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
32538 var numMorphTargets = morphTargetSequence.length;
32541 for ( var i = 0; i < numMorphTargets; i ++ ) {
32547 ( i + numMorphTargets - 1 ) % numMorphTargets,
32549 ( i + 1 ) % numMorphTargets );
32551 values.push( 0, 1, 0 );
32553 var order = AnimationUtils.getKeyframeOrder( times );
32554 times = AnimationUtils.sortedArray( times, 1, order );
32555 values = AnimationUtils.sortedArray( values, 1, order );
32557 // if there is a key at the first frame, duplicate it as the
32558 // last frame as well for perfect loop.
32559 if ( ! noLoop && times[ 0 ] === 0 ) {
32561 times.push( numMorphTargets );
32562 values.push( values[ 0 ] );
32567 new NumberKeyframeTrack(
32568 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
32570 ).scale( 1.0 / fps ) );
32574 return new AnimationClip( name, - 1, tracks );
32578 findByName: function ( objectOrClipArray, name ) {
32580 var clipArray = objectOrClipArray;
32582 if ( ! Array.isArray( objectOrClipArray ) ) {
32584 var o = objectOrClipArray;
32585 clipArray = o.geometry && o.geometry.animations || o.animations;
32589 for ( var i = 0; i < clipArray.length; i ++ ) {
32591 if ( clipArray[ i ].name === name ) {
32593 return clipArray[ i ];
32603 CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
32605 var animationToMorphTargets = {};
32607 // tested with https://regex101.com/ on trick sequences
32608 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
32609 var pattern = /^([\w-]*?)([\d]+)$/;
32611 // sort morph target names into animation groups based
32612 // patterns like Walk_001, Walk_002, Run_001, Run_002
32613 for ( var i = 0, il = morphTargets.length; i < il; i ++ ) {
32615 var morphTarget = morphTargets[ i ];
32616 var parts = morphTarget.name.match( pattern );
32618 if ( parts && parts.length > 1 ) {
32620 var name = parts[ 1 ];
32622 var animationMorphTargets = animationToMorphTargets[ name ];
32623 if ( ! animationMorphTargets ) {
32625 animationToMorphTargets[ name ] = animationMorphTargets = [];
32629 animationMorphTargets.push( morphTarget );
32637 for ( var name in animationToMorphTargets ) {
32639 clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
32647 // parse the animation.hierarchy format
32648 parseAnimation: function ( animation, bones ) {
32650 if ( ! animation ) {
32652 console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
32657 var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
32659 // only return track if there are actually keys.
32660 if ( animationKeys.length !== 0 ) {
32665 AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
32667 // empty keys are filtered out, so check again
32668 if ( times.length !== 0 ) {
32670 destTracks.push( new trackType( trackName, times, values ) );
32680 var clipName = animation.name || 'default';
32681 // automatic length determination in AnimationClip.
32682 var duration = animation.length || - 1;
32683 var fps = animation.fps || 30;
32685 var hierarchyTracks = animation.hierarchy || [];
32687 for ( var h = 0; h < hierarchyTracks.length; h ++ ) {
32689 var animationKeys = hierarchyTracks[ h ].keys;
32691 // skip empty tracks
32692 if ( ! animationKeys || animationKeys.length === 0 ) continue;
32694 // process morph targets
32695 if ( animationKeys[ 0 ].morphTargets ) {
32697 // figure out all morph targets used in this track
32698 var morphTargetNames = {};
32700 for ( var k = 0; k < animationKeys.length; k ++ ) {
32702 if ( animationKeys[ k ].morphTargets ) {
32704 for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
32706 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
32714 // create a track for each morph target with all zero
32715 // morphTargetInfluences except for the keys in which
32716 // the morphTarget is named.
32717 for ( var morphTargetName in morphTargetNames ) {
32722 for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
32724 var animationKey = animationKeys[ k ];
32726 times.push( animationKey.time );
32727 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
32731 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
32735 duration = morphTargetNames.length * ( fps || 1.0 );
32739 // ...assume skeletal animation
32741 var boneName = '.bones[' + bones[ h ].name + ']';
32744 VectorKeyframeTrack, boneName + '.position',
32745 animationKeys, 'pos', tracks );
32748 QuaternionKeyframeTrack, boneName + '.quaternion',
32749 animationKeys, 'rot', tracks );
32752 VectorKeyframeTrack, boneName + '.scale',
32753 animationKeys, 'scl', tracks );
32759 if ( tracks.length === 0 ) {
32765 var clip = new AnimationClip( clipName, duration, tracks );
32773 Object.assign( AnimationClip.prototype, {
32775 resetDuration: function () {
32777 var tracks = this.tracks, duration = 0;
32779 for ( var i = 0, n = tracks.length; i !== n; ++ i ) {
32781 var track = this.tracks[ i ];
32783 duration = Math.max( duration, track.times[ track.times.length - 1 ] );
32787 this.duration = duration;
32791 trim: function () {
32793 for ( var i = 0; i < this.tracks.length; i ++ ) {
32795 this.tracks[ i ].trim( 0, this.duration );
32803 optimize: function () {
32805 for ( var i = 0; i < this.tracks.length; i ++ ) {
32807 this.tracks[ i ].optimize();
32818 * @author mrdoob / http://mrdoob.com/
32821 function MaterialLoader( manager ) {
32823 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
32824 this.textures = {};
32828 Object.assign( MaterialLoader.prototype, {
32830 load: function ( url, onLoad, onProgress, onError ) {
32834 var loader = new FileLoader( scope.manager );
32835 loader.load( url, function ( text ) {
32837 onLoad( scope.parse( JSON.parse( text ) ) );
32839 }, onProgress, onError );
32843 setTextures: function ( value ) {
32845 this.textures = value;
32849 parse: function ( json ) {
32851 var textures = this.textures;
32853 function getTexture( name ) {
32855 if ( textures[ name ] === undefined ) {
32857 console.warn( 'THREE.MaterialLoader: Undefined texture', name );
32861 return textures[ name ];
32865 var material = new Materials[ json.type ]();
32867 if ( json.uuid !== undefined ) material.uuid = json.uuid;
32868 if ( json.name !== undefined ) material.name = json.name;
32869 if ( json.color !== undefined ) material.color.setHex( json.color );
32870 if ( json.roughness !== undefined ) material.roughness = json.roughness;
32871 if ( json.metalness !== undefined ) material.metalness = json.metalness;
32872 if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
32873 if ( json.specular !== undefined ) material.specular.setHex( json.specular );
32874 if ( json.shininess !== undefined ) material.shininess = json.shininess;
32875 if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;
32876 if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;
32877 if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
32878 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
32879 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
32880 if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
32881 if ( json.fog !== undefined ) material.fog = json.fog;
32882 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
32883 if ( json.blending !== undefined ) material.blending = json.blending;
32884 if ( json.side !== undefined ) material.side = json.side;
32885 if ( json.opacity !== undefined ) material.opacity = json.opacity;
32886 if ( json.transparent !== undefined ) material.transparent = json.transparent;
32887 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
32888 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
32889 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
32890 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
32891 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
32892 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
32893 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
32894 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
32896 if ( json.skinning !== undefined ) material.skinning = json.skinning;
32897 if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
32898 if ( json.dithering !== undefined ) material.dithering = json.dithering;
32900 if ( json.visible !== undefined ) material.visible = json.visible;
32901 if ( json.userData !== undefined ) material.userData = json.userData;
32905 if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
32907 // for PointsMaterial
32909 if ( json.size !== undefined ) material.size = json.size;
32910 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
32914 if ( json.map !== undefined ) material.map = getTexture( json.map );
32916 if ( json.alphaMap !== undefined ) {
32918 material.alphaMap = getTexture( json.alphaMap );
32919 material.transparent = true;
32923 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
32924 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
32926 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
32927 if ( json.normalScale !== undefined ) {
32929 var normalScale = json.normalScale;
32931 if ( Array.isArray( normalScale ) === false ) {
32933 // Blender exporter used to export a scalar. See #7459
32935 normalScale = [ normalScale, normalScale ];
32939 material.normalScale = new Vector2().fromArray( normalScale );
32943 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
32944 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
32945 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
32947 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
32948 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
32950 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
32951 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
32953 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
32955 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
32957 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
32959 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
32960 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
32962 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
32963 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
32965 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
32974 * @author mrdoob / http://mrdoob.com/
32977 function BufferGeometryLoader( manager ) {
32979 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
32983 Object.assign( BufferGeometryLoader.prototype, {
32985 load: function ( url, onLoad, onProgress, onError ) {
32989 var loader = new FileLoader( scope.manager );
32990 loader.load( url, function ( text ) {
32992 onLoad( scope.parse( JSON.parse( text ) ) );
32994 }, onProgress, onError );
32998 parse: function ( json ) {
33000 var geometry = new BufferGeometry();
33002 var index = json.data.index;
33004 if ( index !== undefined ) {
33006 var typedArray = new TYPED_ARRAYS[ index.type ]( index.array );
33007 geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
33011 var attributes = json.data.attributes;
33013 for ( var key in attributes ) {
33015 var attribute = attributes[ key ];
33016 var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );
33018 geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );
33022 var groups = json.data.groups || json.data.drawcalls || json.data.offsets;
33024 if ( groups !== undefined ) {
33026 for ( var i = 0, n = groups.length; i !== n; ++ i ) {
33028 var group = groups[ i ];
33030 geometry.addGroup( group.start, group.count, group.materialIndex );
33036 var boundingSphere = json.data.boundingSphere;
33038 if ( boundingSphere !== undefined ) {
33040 var center = new Vector3();
33042 if ( boundingSphere.center !== undefined ) {
33044 center.fromArray( boundingSphere.center );
33048 geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
33058 var TYPED_ARRAYS = {
33059 Int8Array: Int8Array,
33060 Uint8Array: Uint8Array,
33061 // Workaround for IE11 pre KB2929437. See #11440
33062 Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
33063 Int16Array: Int16Array,
33064 Uint16Array: Uint16Array,
33065 Int32Array: Int32Array,
33066 Uint32Array: Uint32Array,
33067 Float32Array: Float32Array,
33068 Float64Array: Float64Array
33072 * @author alteredq / http://alteredqualia.com/
33075 function Loader() {
33077 this.onLoadStart = function () {};
33078 this.onLoadProgress = function () {};
33079 this.onLoadComplete = function () {};
33083 Loader.Handlers = {
33087 add: function ( regex, loader ) {
33089 this.handlers.push( regex, loader );
33093 get: function ( file ) {
33095 var handlers = this.handlers;
33097 for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
33099 var regex = handlers[ i ];
33100 var loader = handlers[ i + 1 ];
33102 if ( regex.test( file ) ) {
33116 Object.assign( Loader.prototype, {
33118 crossOrigin: undefined,
33120 extractUrlBase: function ( url ) {
33122 var parts = url.split( '/' );
33124 if ( parts.length === 1 ) return './';
33128 return parts.join( '/' ) + '/';
33132 initMaterials: function ( materials, texturePath, crossOrigin ) {
33136 for ( var i = 0; i < materials.length; ++ i ) {
33138 array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );
33146 createMaterial: ( function () {
33148 var BlendingMode = {
33149 NoBlending: NoBlending,
33150 NormalBlending: NormalBlending,
33151 AdditiveBlending: AdditiveBlending,
33152 SubtractiveBlending: SubtractiveBlending,
33153 MultiplyBlending: MultiplyBlending,
33154 CustomBlending: CustomBlending
33157 var color = new Color();
33158 var textureLoader = new TextureLoader();
33159 var materialLoader = new MaterialLoader();
33161 return function createMaterial( m, texturePath, crossOrigin ) {
33163 // convert from old material format
33167 function loadTexture( path, repeat, offset, wrap, anisotropy ) {
33169 var fullPath = texturePath + path;
33170 var loader = Loader.Handlers.get( fullPath );
33174 if ( loader !== null ) {
33176 texture = loader.load( fullPath );
33180 textureLoader.setCrossOrigin( crossOrigin );
33181 texture = textureLoader.load( fullPath );
33185 if ( repeat !== undefined ) {
33187 texture.repeat.fromArray( repeat );
33189 if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
33190 if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;
33194 if ( offset !== undefined ) {
33196 texture.offset.fromArray( offset );
33200 if ( wrap !== undefined ) {
33202 if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
33203 if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;
33205 if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
33206 if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;
33210 if ( anisotropy !== undefined ) {
33212 texture.anisotropy = anisotropy;
33216 var uuid = _Math.generateUUID();
33218 textures[ uuid ] = texture;
33227 uuid: _Math.generateUUID(),
33228 type: 'MeshLambertMaterial'
33231 for ( var name in m ) {
33233 var value = m[ name ];
33239 case 'opticalDensity':
33240 case 'illumination':
33246 json.blending = BlendingMode[ value ];
33248 case 'colorAmbient':
33250 console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );
33252 case 'colorDiffuse':
33253 json.color = color.fromArray( value ).getHex();
33255 case 'colorSpecular':
33256 json.specular = color.fromArray( value ).getHex();
33258 case 'colorEmissive':
33259 json.emissive = color.fromArray( value ).getHex();
33261 case 'specularCoef':
33262 json.shininess = value;
33265 if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
33266 if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
33267 if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
33270 json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
33272 case 'mapDiffuseRepeat':
33273 case 'mapDiffuseOffset':
33274 case 'mapDiffuseWrap':
33275 case 'mapDiffuseAnisotropy':
33277 case 'mapEmissive':
33278 json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );
33280 case 'mapEmissiveRepeat':
33281 case 'mapEmissiveOffset':
33282 case 'mapEmissiveWrap':
33283 case 'mapEmissiveAnisotropy':
33286 json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
33288 case 'mapLightRepeat':
33289 case 'mapLightOffset':
33290 case 'mapLightWrap':
33291 case 'mapLightAnisotropy':
33294 json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );
33296 case 'mapAORepeat':
33297 case 'mapAOOffset':
33299 case 'mapAOAnisotropy':
33302 json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
33304 case 'mapBumpScale':
33305 json.bumpScale = value;
33307 case 'mapBumpRepeat':
33308 case 'mapBumpOffset':
33309 case 'mapBumpWrap':
33310 case 'mapBumpAnisotropy':
33313 json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
33315 case 'mapNormalFactor':
33316 json.normalScale = [ value, value ];
33318 case 'mapNormalRepeat':
33319 case 'mapNormalOffset':
33320 case 'mapNormalWrap':
33321 case 'mapNormalAnisotropy':
33323 case 'mapSpecular':
33324 json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
33326 case 'mapSpecularRepeat':
33327 case 'mapSpecularOffset':
33328 case 'mapSpecularWrap':
33329 case 'mapSpecularAnisotropy':
33331 case 'mapMetalness':
33332 json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );
33334 case 'mapMetalnessRepeat':
33335 case 'mapMetalnessOffset':
33336 case 'mapMetalnessWrap':
33337 case 'mapMetalnessAnisotropy':
33339 case 'mapRoughness':
33340 json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );
33342 case 'mapRoughnessRepeat':
33343 case 'mapRoughnessOffset':
33344 case 'mapRoughnessWrap':
33345 case 'mapRoughnessAnisotropy':
33348 json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
33350 case 'mapAlphaRepeat':
33351 case 'mapAlphaOffset':
33352 case 'mapAlphaWrap':
33353 case 'mapAlphaAnisotropy':
33356 json.side = BackSide;
33358 case 'doubleSided':
33359 json.side = DoubleSide;
33361 case 'transparency':
33362 console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );
33363 json.opacity = value;
33369 case 'reflectivity':
33370 case 'transparent':
33373 json[ name ] = value;
33375 case 'vertexColors':
33376 if ( value === true ) json.vertexColors = VertexColors;
33377 if ( value === 'face' ) json.vertexColors = FaceColors;
33380 console.error( 'THREE.Loader.createMaterial: Unsupported', name, value );
33387 if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
33388 if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
33390 if ( json.opacity < 1 ) json.transparent = true;
33392 materialLoader.setTextures( textures );
33394 return materialLoader.parse( json );
33403 * @author mrdoob / http://mrdoob.com/
33404 * @author alteredq / http://alteredqualia.com/
33407 function JSONLoader( manager ) {
33409 if ( typeof manager === 'boolean' ) {
33411 console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
33412 manager = undefined;
33416 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
33418 this.withCredentials = false;
33422 Object.assign( JSONLoader.prototype, {
33424 load: function ( url, onLoad, onProgress, onError ) {
33428 var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );
33430 var loader = new FileLoader( this.manager );
33431 loader.setWithCredentials( this.withCredentials );
33432 loader.load( url, function ( text ) {
33434 var json = JSON.parse( text );
33435 var metadata = json.metadata;
33437 if ( metadata !== undefined ) {
33439 var type = metadata.type;
33441 if ( type !== undefined ) {
33443 if ( type.toLowerCase() === 'object' ) {
33445 console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
33450 if ( type.toLowerCase() === 'scene' ) {
33452 console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );
33461 var object = scope.parse( json, texturePath );
33462 onLoad( object.geometry, object.materials );
33464 }, onProgress, onError );
33468 setTexturePath: function ( value ) {
33470 this.texturePath = value;
33474 parse: ( function () {
33476 function parseModel( json, geometry ) {
33478 function isBitSet( value, position ) {
33480 return value & ( 1 << position );
33488 colorIndex, normalIndex, uvIndex, materialIndex,
33494 hasFaceNormal, hasFaceVertexNormal,
33495 hasFaceColor, hasFaceVertexColor,
33497 vertex, face, faceA, faceB, hex, normal,
33501 faces = json.faces,
33502 vertices = json.vertices,
33503 normals = json.normals,
33504 colors = json.colors,
33506 scale = json.scale,
33511 if ( json.uvs !== undefined ) {
33513 // disregard empty arrays
33515 for ( i = 0; i < json.uvs.length; i ++ ) {
33517 if ( json.uvs[ i ].length ) nUvLayers ++;
33521 for ( i = 0; i < nUvLayers; i ++ ) {
33523 geometry.faceVertexUvs[ i ] = [];
33530 zLength = vertices.length;
33532 while ( offset < zLength ) {
33534 vertex = new Vector3();
33536 vertex.x = vertices[ offset ++ ] * scale;
33537 vertex.y = vertices[ offset ++ ] * scale;
33538 vertex.z = vertices[ offset ++ ] * scale;
33540 geometry.vertices.push( vertex );
33545 zLength = faces.length;
33547 while ( offset < zLength ) {
33549 type = faces[ offset ++ ];
33551 isQuad = isBitSet( type, 0 );
33552 hasMaterial = isBitSet( type, 1 );
33553 hasFaceVertexUv = isBitSet( type, 3 );
33554 hasFaceNormal = isBitSet( type, 4 );
33555 hasFaceVertexNormal = isBitSet( type, 5 );
33556 hasFaceColor = isBitSet( type, 6 );
33557 hasFaceVertexColor = isBitSet( type, 7 );
33559 // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
33563 faceA = new Face3();
33564 faceA.a = faces[ offset ];
33565 faceA.b = faces[ offset + 1 ];
33566 faceA.c = faces[ offset + 3 ];
33568 faceB = new Face3();
33569 faceB.a = faces[ offset + 1 ];
33570 faceB.b = faces[ offset + 2 ];
33571 faceB.c = faces[ offset + 3 ];
33575 if ( hasMaterial ) {
33577 materialIndex = faces[ offset ++ ];
33578 faceA.materialIndex = materialIndex;
33579 faceB.materialIndex = materialIndex;
33583 // to get face <=> uv index correspondence
33585 fi = geometry.faces.length;
33587 if ( hasFaceVertexUv ) {
33589 for ( i = 0; i < nUvLayers; i ++ ) {
33591 uvLayer = json.uvs[ i ];
33593 geometry.faceVertexUvs[ i ][ fi ] = [];
33594 geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
33596 for ( j = 0; j < 4; j ++ ) {
33598 uvIndex = faces[ offset ++ ];
33600 u = uvLayer[ uvIndex * 2 ];
33601 v = uvLayer[ uvIndex * 2 + 1 ];
33603 uv = new Vector2( u, v );
33605 if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
33606 if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
33614 if ( hasFaceNormal ) {
33616 normalIndex = faces[ offset ++ ] * 3;
33619 normals[ normalIndex ++ ],
33620 normals[ normalIndex ++ ],
33621 normals[ normalIndex ]
33624 faceB.normal.copy( faceA.normal );
33628 if ( hasFaceVertexNormal ) {
33630 for ( i = 0; i < 4; i ++ ) {
33632 normalIndex = faces[ offset ++ ] * 3;
33634 normal = new Vector3(
33635 normals[ normalIndex ++ ],
33636 normals[ normalIndex ++ ],
33637 normals[ normalIndex ]
33641 if ( i !== 2 ) faceA.vertexNormals.push( normal );
33642 if ( i !== 0 ) faceB.vertexNormals.push( normal );
33649 if ( hasFaceColor ) {
33651 colorIndex = faces[ offset ++ ];
33652 hex = colors[ colorIndex ];
33654 faceA.color.setHex( hex );
33655 faceB.color.setHex( hex );
33660 if ( hasFaceVertexColor ) {
33662 for ( i = 0; i < 4; i ++ ) {
33664 colorIndex = faces[ offset ++ ];
33665 hex = colors[ colorIndex ];
33667 if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );
33668 if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );
33674 geometry.faces.push( faceA );
33675 geometry.faces.push( faceB );
33679 face = new Face3();
33680 face.a = faces[ offset ++ ];
33681 face.b = faces[ offset ++ ];
33682 face.c = faces[ offset ++ ];
33684 if ( hasMaterial ) {
33686 materialIndex = faces[ offset ++ ];
33687 face.materialIndex = materialIndex;
33691 // to get face <=> uv index correspondence
33693 fi = geometry.faces.length;
33695 if ( hasFaceVertexUv ) {
33697 for ( i = 0; i < nUvLayers; i ++ ) {
33699 uvLayer = json.uvs[ i ];
33701 geometry.faceVertexUvs[ i ][ fi ] = [];
33703 for ( j = 0; j < 3; j ++ ) {
33705 uvIndex = faces[ offset ++ ];
33707 u = uvLayer[ uvIndex * 2 ];
33708 v = uvLayer[ uvIndex * 2 + 1 ];
33710 uv = new Vector2( u, v );
33712 geometry.faceVertexUvs[ i ][ fi ].push( uv );
33720 if ( hasFaceNormal ) {
33722 normalIndex = faces[ offset ++ ] * 3;
33725 normals[ normalIndex ++ ],
33726 normals[ normalIndex ++ ],
33727 normals[ normalIndex ]
33732 if ( hasFaceVertexNormal ) {
33734 for ( i = 0; i < 3; i ++ ) {
33736 normalIndex = faces[ offset ++ ] * 3;
33738 normal = new Vector3(
33739 normals[ normalIndex ++ ],
33740 normals[ normalIndex ++ ],
33741 normals[ normalIndex ]
33744 face.vertexNormals.push( normal );
33751 if ( hasFaceColor ) {
33753 colorIndex = faces[ offset ++ ];
33754 face.color.setHex( colors[ colorIndex ] );
33759 if ( hasFaceVertexColor ) {
33761 for ( i = 0; i < 3; i ++ ) {
33763 colorIndex = faces[ offset ++ ];
33764 face.vertexColors.push( new Color( colors[ colorIndex ] ) );
33770 geometry.faces.push( face );
33778 function parseSkin( json, geometry ) {
33780 var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
33782 if ( json.skinWeights ) {
33784 for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
33786 var x = json.skinWeights[ i ];
33787 var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
33788 var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
33789 var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
33791 geometry.skinWeights.push( new Vector4( x, y, z, w ) );
33797 if ( json.skinIndices ) {
33799 for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
33801 var a = json.skinIndices[ i ];
33802 var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
33803 var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
33804 var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
33806 geometry.skinIndices.push( new Vector4( a, b, c, d ) );
33812 geometry.bones = json.bones;
33814 if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
33816 console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
33817 geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
33823 function parseMorphing( json, geometry ) {
33825 var scale = json.scale;
33827 if ( json.morphTargets !== undefined ) {
33829 for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
33831 geometry.morphTargets[ i ] = {};
33832 geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
33833 geometry.morphTargets[ i ].vertices = [];
33835 var dstVertices = geometry.morphTargets[ i ].vertices;
33836 var srcVertices = json.morphTargets[ i ].vertices;
33838 for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
33840 var vertex = new Vector3();
33841 vertex.x = srcVertices[ v ] * scale;
33842 vertex.y = srcVertices[ v + 1 ] * scale;
33843 vertex.z = srcVertices[ v + 2 ] * scale;
33845 dstVertices.push( vertex );
33853 if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
33855 console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
33857 var faces = geometry.faces;
33858 var morphColors = json.morphColors[ 0 ].colors;
33860 for ( var i = 0, l = faces.length; i < l; i ++ ) {
33862 faces[ i ].color.fromArray( morphColors, i * 3 );
33870 function parseAnimations( json, geometry ) {
33872 var outputAnimations = [];
33874 // parse old style Bone/Hierarchy animations
33875 var animations = [];
33877 if ( json.animation !== undefined ) {
33879 animations.push( json.animation );
33883 if ( json.animations !== undefined ) {
33885 if ( json.animations.length ) {
33887 animations = animations.concat( json.animations );
33891 animations.push( json.animations );
33897 for ( var i = 0; i < animations.length; i ++ ) {
33899 var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
33900 if ( clip ) outputAnimations.push( clip );
33904 // parse implicit morph animations
33905 if ( geometry.morphTargets ) {
33907 // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
33908 var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
33909 outputAnimations = outputAnimations.concat( morphAnimationClips );
33913 if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
33917 return function ( json, texturePath ) {
33919 if ( json.data !== undefined ) {
33921 // Geometry 4.0 spec
33926 if ( json.scale !== undefined ) {
33928 json.scale = 1.0 / json.scale;
33936 var geometry = new Geometry();
33938 parseModel( json, geometry );
33939 parseSkin( json, geometry );
33940 parseMorphing( json, geometry );
33941 parseAnimations( json, geometry );
33943 geometry.computeFaceNormals();
33944 geometry.computeBoundingSphere();
33946 if ( json.materials === undefined || json.materials.length === 0 ) {
33948 return { geometry: geometry };
33952 var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );
33954 return { geometry: geometry, materials: materials };
33965 * @author mrdoob / http://mrdoob.com/
33968 function ObjectLoader( manager ) {
33970 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
33971 this.texturePath = '';
33975 Object.assign( ObjectLoader.prototype, {
33977 load: function ( url, onLoad, onProgress, onError ) {
33979 if ( this.texturePath === '' ) {
33981 this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );
33987 var loader = new FileLoader( scope.manager );
33988 loader.load( url, function ( text ) {
33994 json = JSON.parse( text );
33996 } catch ( error ) {
33998 if ( onError !== undefined ) onError( error );
34000 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
34006 var metadata = json.metadata;
34008 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
34010 console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' );
34015 scope.parse( json, onLoad );
34017 }, onProgress, onError );
34021 setTexturePath: function ( value ) {
34023 this.texturePath = value;
34027 setCrossOrigin: function ( value ) {
34029 this.crossOrigin = value;
34033 parse: function ( json, onLoad ) {
34035 var geometries = this.parseGeometries( json.geometries );
34037 var images = this.parseImages( json.images, function () {
34039 if ( onLoad !== undefined ) onLoad( object );
34043 var textures = this.parseTextures( json.textures, images );
34044 var materials = this.parseMaterials( json.materials, textures );
34046 var object = this.parseObject( json.object, geometries, materials );
34048 if ( json.animations ) {
34050 object.animations = this.parseAnimations( json.animations );
34054 if ( json.images === undefined || json.images.length === 0 ) {
34056 if ( onLoad !== undefined ) onLoad( object );
34064 parseGeometries: function ( json ) {
34066 var geometries = {};
34068 if ( json !== undefined ) {
34070 var geometryLoader = new JSONLoader();
34071 var bufferGeometryLoader = new BufferGeometryLoader();
34073 for ( var i = 0, l = json.length; i < l; i ++ ) {
34076 var data = json[ i ];
34078 switch ( data.type ) {
34080 case 'PlaneGeometry':
34081 case 'PlaneBufferGeometry':
34083 geometry = new Geometries[ data.type ](
34086 data.widthSegments,
34087 data.heightSegments
34092 case 'BoxGeometry':
34093 case 'BoxBufferGeometry':
34094 case 'CubeGeometry': // backwards compatible
34096 geometry = new Geometries[ data.type ](
34100 data.widthSegments,
34101 data.heightSegments,
34107 case 'CircleGeometry':
34108 case 'CircleBufferGeometry':
34110 geometry = new Geometries[ data.type ](
34119 case 'CylinderGeometry':
34120 case 'CylinderBufferGeometry':
34122 geometry = new Geometries[ data.type ](
34126 data.radialSegments,
34127 data.heightSegments,
34135 case 'ConeGeometry':
34136 case 'ConeBufferGeometry':
34138 geometry = new Geometries[ data.type ](
34141 data.radialSegments,
34142 data.heightSegments,
34150 case 'SphereGeometry':
34151 case 'SphereBufferGeometry':
34153 geometry = new Geometries[ data.type ](
34155 data.widthSegments,
34156 data.heightSegments,
34165 case 'DodecahedronGeometry':
34166 case 'IcosahedronGeometry':
34167 case 'OctahedronGeometry':
34168 case 'TetrahedronGeometry':
34170 geometry = new Geometries[ data.type ](
34177 case 'RingGeometry':
34178 case 'RingBufferGeometry':
34180 geometry = new Geometries[ data.type ](
34183 data.thetaSegments,
34191 case 'TorusGeometry':
34192 case 'TorusBufferGeometry':
34194 geometry = new Geometries[ data.type ](
34197 data.radialSegments,
34198 data.tubularSegments,
34204 case 'TorusKnotGeometry':
34205 case 'TorusKnotBufferGeometry':
34207 geometry = new Geometries[ data.type ](
34210 data.tubularSegments,
34211 data.radialSegments,
34218 case 'LatheGeometry':
34219 case 'LatheBufferGeometry':
34221 geometry = new Geometries[ data.type ](
34230 case 'BufferGeometry':
34232 geometry = bufferGeometryLoader.parse( data );
34238 geometry = geometryLoader.parse( data, this.texturePath ).geometry;
34244 console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
34250 geometry.uuid = data.uuid;
34252 if ( data.name !== undefined ) geometry.name = data.name;
34254 geometries[ data.uuid ] = geometry;
34264 parseMaterials: function ( json, textures ) {
34266 var materials = {};
34268 if ( json !== undefined ) {
34270 var loader = new MaterialLoader();
34271 loader.setTextures( textures );
34273 for ( var i = 0, l = json.length; i < l; i ++ ) {
34275 var data = json[ i ];
34277 if ( data.type === 'MultiMaterial' ) {
34283 for ( var j = 0; j < data.materials.length; j ++ ) {
34285 array.push( loader.parse( data.materials[ j ] ) );
34289 materials[ data.uuid ] = array;
34293 materials[ data.uuid ] = loader.parse( data );
34305 parseAnimations: function ( json ) {
34307 var animations = [];
34309 for ( var i = 0; i < json.length; i ++ ) {
34311 var clip = AnimationClip.parse( json[ i ] );
34313 animations.push( clip );
34321 parseImages: function ( json, onLoad ) {
34326 function loadImage( url ) {
34328 scope.manager.itemStart( url );
34330 return loader.load( url, function () {
34332 scope.manager.itemEnd( url );
34334 }, undefined, function () {
34336 scope.manager.itemEnd( url );
34337 scope.manager.itemError( url );
34343 if ( json !== undefined && json.length > 0 ) {
34345 var manager = new LoadingManager( onLoad );
34347 var loader = new ImageLoader( manager );
34348 loader.setCrossOrigin( this.crossOrigin );
34350 for ( var i = 0, l = json.length; i < l; i ++ ) {
34352 var image = json[ i ];
34353 var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;
34355 images[ image.uuid ] = loadImage( path );
34365 parseTextures: function ( json, images ) {
34367 function parseConstant( value, type ) {
34369 if ( typeof( value ) === 'number' ) return value;
34371 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
34373 return type[ value ];
34379 if ( json !== undefined ) {
34381 for ( var i = 0, l = json.length; i < l; i ++ ) {
34383 var data = json[ i ];
34385 if ( data.image === undefined ) {
34387 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
34391 if ( images[ data.image ] === undefined ) {
34393 console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
34397 var texture = new Texture( images[ data.image ] );
34398 texture.needsUpdate = true;
34400 texture.uuid = data.uuid;
34402 if ( data.name !== undefined ) texture.name = data.name;
34404 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
34406 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
34407 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
34408 if ( data.wrap !== undefined ) {
34410 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
34411 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
34415 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
34416 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
34417 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
34419 if ( data.flipY !== undefined ) texture.flipY = data.flipY;
34421 textures[ data.uuid ] = texture;
34431 parseObject: function () {
34433 var matrix = new Matrix4();
34435 return function parseObject( data, geometries, materials ) {
34439 function getGeometry( name ) {
34441 if ( geometries[ name ] === undefined ) {
34443 console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
34447 return geometries[ name ];
34451 function getMaterial( name ) {
34453 if ( name === undefined ) return undefined;
34455 if ( Array.isArray( name ) ) {
34459 for ( var i = 0, l = name.length; i < l; i ++ ) {
34461 var uuid = name[ i ];
34463 if ( materials[ uuid ] === undefined ) {
34465 console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
34469 array.push( materials[ uuid ] );
34477 if ( materials[ name ] === undefined ) {
34479 console.warn( 'THREE.ObjectLoader: Undefined material', name );
34483 return materials[ name ];
34487 switch ( data.type ) {
34491 object = new Scene();
34493 if ( data.background !== undefined ) {
34495 if ( Number.isInteger( data.background ) ) {
34497 object.background = new Color( data.background );
34503 if ( data.fog !== undefined ) {
34505 if ( data.fog.type === 'Fog' ) {
34507 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
34509 } else if ( data.fog.type === 'FogExp2' ) {
34511 object.fog = new FogExp2( data.fog.color, data.fog.density );
34519 case 'PerspectiveCamera':
34521 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
34523 if ( data.focus !== undefined ) object.focus = data.focus;
34524 if ( data.zoom !== undefined ) object.zoom = data.zoom;
34525 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
34526 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
34527 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
34531 case 'OrthographicCamera':
34533 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
34537 case 'AmbientLight':
34539 object = new AmbientLight( data.color, data.intensity );
34543 case 'DirectionalLight':
34545 object = new DirectionalLight( data.color, data.intensity );
34551 object = new PointLight( data.color, data.intensity, data.distance, data.decay );
34555 case 'RectAreaLight':
34557 object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
34563 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
34567 case 'HemisphereLight':
34569 object = new HemisphereLight( data.color, data.groundColor, data.intensity );
34573 case 'SkinnedMesh':
34575 console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' );
34579 var geometry = getGeometry( data.geometry );
34580 var material = getMaterial( data.material );
34582 if ( geometry.bones && geometry.bones.length > 0 ) {
34584 object = new SkinnedMesh( geometry, material );
34588 object = new Mesh( geometry, material );
34596 object = new LOD();
34602 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );
34608 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
34612 case 'LineSegments':
34614 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
34621 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
34627 object = new Sprite( getMaterial( data.material ) );
34633 object = new Group();
34639 object = new Object3D();
34643 object.uuid = data.uuid;
34645 if ( data.name !== undefined ) object.name = data.name;
34646 if ( data.matrix !== undefined ) {
34648 matrix.fromArray( data.matrix );
34649 matrix.decompose( object.position, object.quaternion, object.scale );
34653 if ( data.position !== undefined ) object.position.fromArray( data.position );
34654 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
34655 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
34656 if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
34660 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
34661 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
34663 if ( data.shadow ) {
34665 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
34666 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
34667 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
34668 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
34672 if ( data.visible !== undefined ) object.visible = data.visible;
34673 if ( data.userData !== undefined ) object.userData = data.userData;
34675 if ( data.children !== undefined ) {
34677 var children = data.children;
34679 for ( var i = 0; i < children.length; i ++ ) {
34681 object.add( this.parseObject( children[ i ], geometries, materials ) );
34687 if ( data.type === 'LOD' ) {
34689 var levels = data.levels;
34691 for ( var l = 0; l < levels.length; l ++ ) {
34693 var level = levels[ l ];
34694 var child = object.getObjectByProperty( 'uuid', level.object );
34696 if ( child !== undefined ) {
34698 object.addLevel( child, level.distance );
34714 var TEXTURE_MAPPING = {
34715 UVMapping: UVMapping,
34716 CubeReflectionMapping: CubeReflectionMapping,
34717 CubeRefractionMapping: CubeRefractionMapping,
34718 EquirectangularReflectionMapping: EquirectangularReflectionMapping,
34719 EquirectangularRefractionMapping: EquirectangularRefractionMapping,
34720 SphericalReflectionMapping: SphericalReflectionMapping,
34721 CubeUVReflectionMapping: CubeUVReflectionMapping,
34722 CubeUVRefractionMapping: CubeUVRefractionMapping
34725 var TEXTURE_WRAPPING = {
34726 RepeatWrapping: RepeatWrapping,
34727 ClampToEdgeWrapping: ClampToEdgeWrapping,
34728 MirroredRepeatWrapping: MirroredRepeatWrapping
34731 var TEXTURE_FILTER = {
34732 NearestFilter: NearestFilter,
34733 NearestMipMapNearestFilter: NearestMipMapNearestFilter,
34734 NearestMipMapLinearFilter: NearestMipMapLinearFilter,
34735 LinearFilter: LinearFilter,
34736 LinearMipMapNearestFilter: LinearMipMapNearestFilter,
34737 LinearMipMapLinearFilter: LinearMipMapLinearFilter
34741 * @author zz85 / http://www.lab4games.net/zz85/blog
34743 * Bezier Curves formulas obtained from
34744 * http://en.wikipedia.org/wiki/Bézier_curve
34747 function CatmullRom( t, p0, p1, p2, p3 ) {
34749 var v0 = ( p2 - p0 ) * 0.5;
34750 var v1 = ( p3 - p1 ) * 0.5;
34753 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
34759 function QuadraticBezierP0( t, p ) {
34766 function QuadraticBezierP1( t, p ) {
34768 return 2 * ( 1 - t ) * t * p;
34772 function QuadraticBezierP2( t, p ) {
34778 function QuadraticBezier( t, p0, p1, p2 ) {
34780 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
34781 QuadraticBezierP2( t, p2 );
34787 function CubicBezierP0( t, p ) {
34790 return k * k * k * p;
34794 function CubicBezierP1( t, p ) {
34797 return 3 * k * k * t * p;
34801 function CubicBezierP2( t, p ) {
34803 return 3 * ( 1 - t ) * t * t * p;
34807 function CubicBezierP3( t, p ) {
34809 return t * t * t * p;
34813 function CubicBezier( t, p0, p1, p2, p3 ) {
34815 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
34816 CubicBezierP3( t, p3 );
34821 * @author zz85 / http://www.lab4games.net/zz85/blog
34822 * Extensible curve object
34824 * Some common of curve methods:
34825 * .getPoint(t), getTangent(t)
34826 * .getPointAt(u), getTangentAt(u)
34827 * .getPoints(), .getSpacedPoints()
34829 * .updateArcLengths()
34831 * This following curves inherit from THREE.Curve:
34835 * THREE.CubicBezierCurve
34836 * THREE.EllipseCurve
34838 * THREE.QuadraticBezierCurve
34839 * THREE.SplineCurve
34842 * THREE.CatmullRomCurve3
34843 * THREE.CubicBezierCurve3
34845 * THREE.QuadraticBezierCurve3
34847 * A series of curves can be represented as a THREE.CurvePath.
34851 /**************************************************************
34852 * Abstract Curve base class
34853 **************************************************************/
34857 this.arcLengthDivisions = 200;
34861 Object.assign( Curve.prototype, {
34863 // Virtual base class method to overwrite and implement in subclasses
34866 getPoint: function () {
34868 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
34873 // Get point at relative position in curve according to arc length
34876 getPointAt: function ( u ) {
34878 var t = this.getUtoTmapping( u );
34879 return this.getPoint( t );
34883 // Get sequence of points using getPoint( t )
34885 getPoints: function ( divisions ) {
34887 if ( divisions === undefined ) divisions = 5;
34891 for ( var d = 0; d <= divisions; d ++ ) {
34893 points.push( this.getPoint( d / divisions ) );
34901 // Get sequence of points using getPointAt( u )
34903 getSpacedPoints: function ( divisions ) {
34905 if ( divisions === undefined ) divisions = 5;
34909 for ( var d = 0; d <= divisions; d ++ ) {
34911 points.push( this.getPointAt( d / divisions ) );
34919 // Get total curve arc length
34921 getLength: function () {
34923 var lengths = this.getLengths();
34924 return lengths[ lengths.length - 1 ];
34928 // Get list of cumulative segment lengths
34930 getLengths: function ( divisions ) {
34932 if ( divisions === undefined ) divisions = this.arcLengthDivisions;
34934 if ( this.cacheArcLengths &&
34935 ( this.cacheArcLengths.length === divisions + 1 ) &&
34936 ! this.needsUpdate ) {
34938 return this.cacheArcLengths;
34942 this.needsUpdate = false;
34945 var current, last = this.getPoint( 0 );
34950 for ( p = 1; p <= divisions; p ++ ) {
34952 current = this.getPoint( p / divisions );
34953 sum += current.distanceTo( last );
34959 this.cacheArcLengths = cache;
34961 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
34965 updateArcLengths: function () {
34967 this.needsUpdate = true;
34972 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
34974 getUtoTmapping: function ( u, distance ) {
34976 var arcLengths = this.getLengths();
34978 var i = 0, il = arcLengths.length;
34980 var targetArcLength; // The targeted u distance value to get
34984 targetArcLength = distance;
34988 targetArcLength = u * arcLengths[ il - 1 ];
34992 // binary search for the index with largest value smaller than target u distance
34994 var low = 0, high = il - 1, comparison;
34996 while ( low <= high ) {
34998 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
35000 comparison = arcLengths[ i ] - targetArcLength;
35002 if ( comparison < 0 ) {
35006 } else if ( comparison > 0 ) {
35023 if ( arcLengths[ i ] === targetArcLength ) {
35025 return i / ( il - 1 );
35029 // we could get finer grain at lengths, or use simple interpolation between two points
35031 var lengthBefore = arcLengths[ i ];
35032 var lengthAfter = arcLengths[ i + 1 ];
35034 var segmentLength = lengthAfter - lengthBefore;
35036 // determine where we are between the 'before' and 'after' points
35038 var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
35040 // add that fractional amount to t
35042 var t = ( i + segmentFraction ) / ( il - 1 );
35048 // Returns a unit vector tangent at t
35049 // In case any sub curve does not implement its tangent derivation,
35050 // 2 points a small delta apart will be used to find its gradient
35051 // which seems to give a reasonable approximation
35053 getTangent: function ( t ) {
35055 var delta = 0.0001;
35056 var t1 = t - delta;
35057 var t2 = t + delta;
35059 // Capping in case of danger
35061 if ( t1 < 0 ) t1 = 0;
35062 if ( t2 > 1 ) t2 = 1;
35064 var pt1 = this.getPoint( t1 );
35065 var pt2 = this.getPoint( t2 );
35067 var vec = pt2.clone().sub( pt1 );
35068 return vec.normalize();
35072 getTangentAt: function ( u ) {
35074 var t = this.getUtoTmapping( u );
35075 return this.getTangent( t );
35079 computeFrenetFrames: function ( segments, closed ) {
35081 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
35083 var normal = new Vector3();
35087 var binormals = [];
35089 var vec = new Vector3();
35090 var mat = new Matrix4();
35094 // compute the tangent vectors for each segment on the curve
35096 for ( i = 0; i <= segments; i ++ ) {
35100 tangents[ i ] = this.getTangentAt( u );
35101 tangents[ i ].normalize();
35105 // select an initial normal vector perpendicular to the first tangent vector,
35106 // and in the direction of the minimum tangent xyz component
35108 normals[ 0 ] = new Vector3();
35109 binormals[ 0 ] = new Vector3();
35110 var min = Number.MAX_VALUE;
35111 var tx = Math.abs( tangents[ 0 ].x );
35112 var ty = Math.abs( tangents[ 0 ].y );
35113 var tz = Math.abs( tangents[ 0 ].z );
35118 normal.set( 1, 0, 0 );
35125 normal.set( 0, 1, 0 );
35131 normal.set( 0, 0, 1 );
35135 vec.crossVectors( tangents[ 0 ], normal ).normalize();
35137 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
35138 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
35141 // compute the slowly-varying normal and binormal vectors for each segment on the curve
35143 for ( i = 1; i <= segments; i ++ ) {
35145 normals[ i ] = normals[ i - 1 ].clone();
35147 binormals[ i ] = binormals[ i - 1 ].clone();
35149 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
35151 if ( vec.length() > Number.EPSILON ) {
35155 theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
35157 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
35161 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35165 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
35167 if ( closed === true ) {
35169 theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
35172 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
35178 for ( i = 1; i <= segments; i ++ ) {
35180 // twist a little...
35181 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
35182 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35189 tangents: tangents,
35191 binormals: binormals
35198 function LineCurve( v1, v2 ) {
35200 Curve.call( this );
35207 LineCurve.prototype = Object.create( Curve.prototype );
35208 LineCurve.prototype.constructor = LineCurve;
35210 LineCurve.prototype.isLineCurve = true;
35212 LineCurve.prototype.getPoint = function ( t ) {
35216 return this.v2.clone();
35220 var point = this.v2.clone().sub( this.v1 );
35221 point.multiplyScalar( t ).add( this.v1 );
35227 // Line curve is linear, so we can overwrite default getPointAt
35229 LineCurve.prototype.getPointAt = function ( u ) {
35231 return this.getPoint( u );
35235 LineCurve.prototype.getTangent = function ( t ) {
35237 var tangent = this.v2.clone().sub( this.v1 );
35239 return tangent.normalize();
35244 * @author zz85 / http://www.lab4games.net/zz85/blog
35248 /**************************************************************
35249 * Curved Path - a curve path is simply a array of connected
35250 * curves, but retains the api of a curve
35251 **************************************************************/
35253 function CurvePath() {
35255 Curve.call( this );
35259 this.autoClose = false; // Automatically closes the path
35263 CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
35265 constructor: CurvePath,
35267 add: function ( curve ) {
35269 this.curves.push( curve );
35273 closePath: function () {
35275 // Add a line curve if start and end of lines are not connected
35276 var startPoint = this.curves[ 0 ].getPoint( 0 );
35277 var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
35279 if ( ! startPoint.equals( endPoint ) ) {
35281 this.curves.push( new LineCurve( endPoint, startPoint ) );
35287 // To get accurate point with reference to
35288 // entire path distance at time t,
35289 // following has to be done:
35291 // 1. Length of each sub path have to be known
35292 // 2. Locate and identify type of curve
35293 // 3. Get t for the curve
35294 // 4. Return curve.getPointAt(t')
35296 getPoint: function ( t ) {
35298 var d = t * this.getLength();
35299 var curveLengths = this.getCurveLengths();
35302 // To think about boundaries points.
35304 while ( i < curveLengths.length ) {
35306 if ( curveLengths[ i ] >= d ) {
35308 var diff = curveLengths[ i ] - d;
35309 var curve = this.curves[ i ];
35311 var segmentLength = curve.getLength();
35312 var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
35314 return curve.getPointAt( u );
35324 // loop where sum != 0, sum > d , sum+1 <d
35328 // We cannot use the default THREE.Curve getPoint() with getLength() because in
35329 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
35330 // getPoint() depends on getLength
35332 getLength: function () {
35334 var lens = this.getCurveLengths();
35335 return lens[ lens.length - 1 ];
35339 // cacheLengths must be recalculated.
35340 updateArcLengths: function () {
35342 this.needsUpdate = true;
35343 this.cacheLengths = null;
35344 this.getCurveLengths();
35348 // Compute lengths and cache them
35349 // We cannot overwrite getLengths() because UtoT mapping uses it.
35351 getCurveLengths: function () {
35353 // We use cache values if curves and cache array are same length
35355 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
35357 return this.cacheLengths;
35361 // Get length of sub-curve
35362 // Push sums into cached array
35364 var lengths = [], sums = 0;
35366 for ( var i = 0, l = this.curves.length; i < l; i ++ ) {
35368 sums += this.curves[ i ].getLength();
35369 lengths.push( sums );
35373 this.cacheLengths = lengths;
35379 getSpacedPoints: function ( divisions ) {
35381 if ( divisions === undefined ) divisions = 40;
35385 for ( var i = 0; i <= divisions; i ++ ) {
35387 points.push( this.getPoint( i / divisions ) );
35391 if ( this.autoClose ) {
35393 points.push( points[ 0 ] );
35401 getPoints: function ( divisions ) {
35403 divisions = divisions || 12;
35405 var points = [], last;
35407 for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {
35409 var curve = curves[ i ];
35410 var resolution = (curve && curve.isEllipseCurve) ? divisions * 2
35411 : (curve && curve.isLineCurve) ? 1
35412 : (curve && curve.isSplineCurve) ? divisions * curve.points.length
35415 var pts = curve.getPoints( resolution );
35417 for ( var j = 0; j < pts.length; j++ ) {
35419 var point = pts[ j ];
35421 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
35423 points.push( point );
35430 if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {
35432 points.push( points[ 0 ] );
35440 /**************************************************************
35441 * Create Geometries Helpers
35442 **************************************************************/
35444 /// Generate geometry from path points (for Line or Points objects)
35446 createPointsGeometry: function ( divisions ) {
35448 var pts = this.getPoints( divisions );
35449 return this.createGeometry( pts );
35453 // Generate geometry from equidistant sampling along the path
35455 createSpacedPointsGeometry: function ( divisions ) {
35457 var pts = this.getSpacedPoints( divisions );
35458 return this.createGeometry( pts );
35462 createGeometry: function ( points ) {
35464 var geometry = new Geometry();
35466 for ( var i = 0, l = points.length; i < l; i ++ ) {
35468 var point = points[ i ];
35469 geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
35479 function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
35481 Curve.call( this );
35486 this.xRadius = xRadius;
35487 this.yRadius = yRadius;
35489 this.aStartAngle = aStartAngle;
35490 this.aEndAngle = aEndAngle;
35492 this.aClockwise = aClockwise;
35494 this.aRotation = aRotation || 0;
35498 EllipseCurve.prototype = Object.create( Curve.prototype );
35499 EllipseCurve.prototype.constructor = EllipseCurve;
35501 EllipseCurve.prototype.isEllipseCurve = true;
35503 EllipseCurve.prototype.getPoint = function ( t ) {
35505 var twoPi = Math.PI * 2;
35506 var deltaAngle = this.aEndAngle - this.aStartAngle;
35507 var samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
35509 // ensures that deltaAngle is 0 .. 2 PI
35510 while ( deltaAngle < 0 ) deltaAngle += twoPi;
35511 while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
35513 if ( deltaAngle < Number.EPSILON ) {
35515 if ( samePoints ) {
35521 deltaAngle = twoPi;
35527 if ( this.aClockwise === true && ! samePoints ) {
35529 if ( deltaAngle === twoPi ) {
35531 deltaAngle = - twoPi;
35535 deltaAngle = deltaAngle - twoPi;
35541 var angle = this.aStartAngle + t * deltaAngle;
35542 var x = this.aX + this.xRadius * Math.cos( angle );
35543 var y = this.aY + this.yRadius * Math.sin( angle );
35545 if ( this.aRotation !== 0 ) {
35547 var cos = Math.cos( this.aRotation );
35548 var sin = Math.sin( this.aRotation );
35550 var tx = x - this.aX;
35551 var ty = y - this.aY;
35553 // Rotate the point about the center of the ellipse.
35554 x = tx * cos - ty * sin + this.aX;
35555 y = tx * sin + ty * cos + this.aY;
35559 return new Vector2( x, y );
35563 function SplineCurve( points /* array of Vector2 */ ) {
35565 Curve.call( this );
35567 this.points = ( points === undefined ) ? [] : points;
35571 SplineCurve.prototype = Object.create( Curve.prototype );
35572 SplineCurve.prototype.constructor = SplineCurve;
35574 SplineCurve.prototype.isSplineCurve = true;
35576 SplineCurve.prototype.getPoint = function ( t ) {
35578 var points = this.points;
35579 var point = ( points.length - 1 ) * t;
35581 var intPoint = Math.floor( point );
35582 var weight = point - intPoint;
35584 var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
35585 var point1 = points[ intPoint ];
35586 var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
35587 var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
35589 return new Vector2(
35590 CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ),
35591 CatmullRom( weight, point0.y, point1.y, point2.y, point3.y )
35596 function CubicBezierCurve( v0, v1, v2, v3 ) {
35598 Curve.call( this );
35607 CubicBezierCurve.prototype = Object.create( Curve.prototype );
35608 CubicBezierCurve.prototype.constructor = CubicBezierCurve;
35610 CubicBezierCurve.prototype.getPoint = function ( t ) {
35612 var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35614 return new Vector2(
35615 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35616 CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
35621 function QuadraticBezierCurve( v0, v1, v2 ) {
35623 Curve.call( this );
35631 QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
35632 QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
35634 QuadraticBezierCurve.prototype.getPoint = function ( t ) {
35636 var v0 = this.v0, v1 = this.v1, v2 = this.v2;
35638 return new Vector2(
35639 QuadraticBezier( t, v0.x, v1.x, v2.x ),
35640 QuadraticBezier( t, v0.y, v1.y, v2.y )
35645 var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {
35647 fromPoints: function ( vectors ) {
35649 this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
35651 for ( var i = 1, l = vectors.length; i < l; i ++ ) {
35653 this.lineTo( vectors[ i ].x, vectors[ i ].y );
35659 moveTo: function ( x, y ) {
35661 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
35665 lineTo: function ( x, y ) {
35667 var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
35668 this.curves.push( curve );
35670 this.currentPoint.set( x, y );
35674 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
35676 var curve = new QuadraticBezierCurve(
35677 this.currentPoint.clone(),
35678 new Vector2( aCPx, aCPy ),
35679 new Vector2( aX, aY )
35682 this.curves.push( curve );
35684 this.currentPoint.set( aX, aY );
35688 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
35690 var curve = new CubicBezierCurve(
35691 this.currentPoint.clone(),
35692 new Vector2( aCP1x, aCP1y ),
35693 new Vector2( aCP2x, aCP2y ),
35694 new Vector2( aX, aY )
35697 this.curves.push( curve );
35699 this.currentPoint.set( aX, aY );
35703 splineThru: function ( pts /*Array of Vector*/ ) {
35705 var npts = [ this.currentPoint.clone() ].concat( pts );
35707 var curve = new SplineCurve( npts );
35708 this.curves.push( curve );
35710 this.currentPoint.copy( pts[ pts.length - 1 ] );
35714 arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35716 var x0 = this.currentPoint.x;
35717 var y0 = this.currentPoint.y;
35719 this.absarc( aX + x0, aY + y0, aRadius,
35720 aStartAngle, aEndAngle, aClockwise );
35724 absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35726 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
35730 ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
35732 var x0 = this.currentPoint.x;
35733 var y0 = this.currentPoint.y;
35735 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
35739 absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
35741 var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
35743 if ( this.curves.length > 0 ) {
35745 // if a previous curve is present, attempt to join
35746 var firstPoint = curve.getPoint( 0 );
35748 if ( ! firstPoint.equals( this.currentPoint ) ) {
35750 this.lineTo( firstPoint.x, firstPoint.y );
35756 this.curves.push( curve );
35758 var lastPoint = curve.getPoint( 1 );
35759 this.currentPoint.copy( lastPoint );
35766 * @author zz85 / http://www.lab4games.net/zz85/blog
35767 * Creates free form 2d path using series of points, lines or curves.
35770 function Path( points ) {
35772 CurvePath.call( this );
35773 this.currentPoint = new Vector2();
35777 this.fromPoints( points );
35783 Path.prototype = PathPrototype;
35784 PathPrototype.constructor = Path;
35787 * @author zz85 / http://www.lab4games.net/zz85/blog
35788 * Defines a 2d shape plane using paths.
35791 // STEP 1 Create a path.
35792 // STEP 2 Turn path into shape.
35793 // STEP 3 ExtrudeGeometry takes in Shape/Shapes
35794 // STEP 3a - Extract points from each shape, turn to vertices
35795 // STEP 3b - Triangulate each shape, add faces.
35799 Path.apply( this, arguments );
35805 Shape.prototype = Object.assign( Object.create( PathPrototype ), {
35807 constructor: Shape,
35809 getPointsHoles: function ( divisions ) {
35813 for ( var i = 0, l = this.holes.length; i < l; i ++ ) {
35815 holesPts[ i ] = this.holes[ i ].getPoints( divisions );
35823 // Get points of shape and holes (keypoints based on segments parameter)
35825 extractAllPoints: function ( divisions ) {
35829 shape: this.getPoints( divisions ),
35830 holes: this.getPointsHoles( divisions )
35836 extractPoints: function ( divisions ) {
35838 return this.extractAllPoints( divisions );
35845 * @author zz85 / http://www.lab4games.net/zz85/blog
35846 * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
35849 function ShapePath() {
35851 this.subPaths = [];
35852 this.currentPath = null;
35856 Object.assign( ShapePath.prototype, {
35858 moveTo: function ( x, y ) {
35860 this.currentPath = new Path();
35861 this.subPaths.push( this.currentPath );
35862 this.currentPath.moveTo( x, y );
35866 lineTo: function ( x, y ) {
35868 this.currentPath.lineTo( x, y );
35872 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
35874 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
35878 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
35880 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
35884 splineThru: function ( pts ) {
35886 this.currentPath.splineThru( pts );
35890 toShapes: function ( isCCW, noHoles ) {
35892 function toShapesNoHoles( inSubpaths ) {
35896 for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {
35898 var tmpPath = inSubpaths[ i ];
35900 var tmpShape = new Shape();
35901 tmpShape.curves = tmpPath.curves;
35903 shapes.push( tmpShape );
35911 function isPointInsidePolygon( inPt, inPolygon ) {
35913 var polyLen = inPolygon.length;
35915 // inPt on polygon contour => immediate success or
35916 // toggling of inside/outside at every single! intersection point of an edge
35917 // with the horizontal line through inPt, left of inPt
35918 // not counting lowerY endpoints of edges and whole edges on that line
35919 var inside = false;
35920 for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
35922 var edgeLowPt = inPolygon[ p ];
35923 var edgeHighPt = inPolygon[ q ];
35925 var edgeDx = edgeHighPt.x - edgeLowPt.x;
35926 var edgeDy = edgeHighPt.y - edgeLowPt.y;
35928 if ( Math.abs( edgeDy ) > Number.EPSILON ) {
35931 if ( edgeDy < 0 ) {
35933 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
35934 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
35937 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
35939 if ( inPt.y === edgeLowPt.y ) {
35941 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
35942 // continue; // no intersection or edgeLowPt => doesn't count !!!
35946 var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
35947 if ( perpEdge === 0 ) return true; // inPt is on contour ?
35948 if ( perpEdge < 0 ) continue;
35949 inside = ! inside; // true intersection left of inPt
35955 // parallel or collinear
35956 if ( inPt.y !== edgeLowPt.y ) continue; // parallel
35957 // edge lies on the same horizontal line as inPt
35958 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
35959 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
35970 var isClockWise = ShapeUtils.isClockWise;
35972 var subPaths = this.subPaths;
35973 if ( subPaths.length === 0 ) return [];
35975 if ( noHoles === true ) return toShapesNoHoles( subPaths );
35978 var solid, tmpPath, tmpShape, shapes = [];
35980 if ( subPaths.length === 1 ) {
35982 tmpPath = subPaths[ 0 ];
35983 tmpShape = new Shape();
35984 tmpShape.curves = tmpPath.curves;
35985 shapes.push( tmpShape );
35990 var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
35991 holesFirst = isCCW ? ! holesFirst : holesFirst;
35993 // console.log("Holes first", holesFirst);
35995 var betterShapeHoles = [];
35996 var newShapes = [];
35997 var newShapeHoles = [];
36001 newShapes[ mainIdx ] = undefined;
36002 newShapeHoles[ mainIdx ] = [];
36004 for ( var i = 0, l = subPaths.length; i < l; i ++ ) {
36006 tmpPath = subPaths[ i ];
36007 tmpPoints = tmpPath.getPoints();
36008 solid = isClockWise( tmpPoints );
36009 solid = isCCW ? ! solid : solid;
36013 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
36015 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
36016 newShapes[ mainIdx ].s.curves = tmpPath.curves;
36018 if ( holesFirst ) mainIdx ++;
36019 newShapeHoles[ mainIdx ] = [];
36021 //console.log('cw', i);
36025 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
36027 //console.log('ccw', i);
36033 // only Holes? -> probably all Shapes with wrong orientation
36034 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
36037 if ( newShapes.length > 1 ) {
36039 var ambiguous = false;
36042 for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
36044 betterShapeHoles[ sIdx ] = [];
36048 for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
36050 var sho = newShapeHoles[ sIdx ];
36052 for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
36054 var ho = sho[ hIdx ];
36055 var hole_unassigned = true;
36057 for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
36059 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
36061 if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
36062 if ( hole_unassigned ) {
36064 hole_unassigned = false;
36065 betterShapeHoles[ s2Idx ].push( ho );
36076 if ( hole_unassigned ) {
36078 betterShapeHoles[ sIdx ].push( ho );
36085 // console.log("ambiguous: ", ambiguous);
36086 if ( toChange.length > 0 ) {
36088 // console.log("to change: ", toChange);
36089 if ( ! ambiguous ) newShapeHoles = betterShapeHoles;
36097 for ( var i = 0, il = newShapes.length; i < il; i ++ ) {
36099 tmpShape = newShapes[ i ].s;
36100 shapes.push( tmpShape );
36101 tmpHoles = newShapeHoles[ i ];
36103 for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
36105 tmpShape.holes.push( tmpHoles[ j ].h );
36111 //console.log("shape", shapes);
36120 * @author zz85 / http://www.lab4games.net/zz85/blog
36121 * @author mrdoob / http://mrdoob.com/
36124 function Font( data ) {
36130 Object.assign( Font.prototype, {
36134 generateShapes: function ( text, size, divisions ) {
36136 function createPaths( text ) {
36138 var chars = String( text ).split( '' );
36139 var scale = size / data.resolution;
36140 var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
36142 var offsetX = 0, offsetY = 0;
36146 for ( var i = 0; i < chars.length; i ++ ) {
36148 var char = chars[ i ];
36150 if ( char === '\n' ) {
36153 offsetY -= line_height;
36157 var ret = createPath( char, scale, offsetX, offsetY );
36158 offsetX += ret.offsetX;
36159 paths.push( ret.path );
36169 function createPath( c, scale, offsetX, offsetY ) {
36171 var glyph = data.glyphs[ c ] || data.glyphs[ '?' ];
36173 if ( ! glyph ) return;
36175 var path = new ShapePath();
36178 var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste;
36182 var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
36184 for ( var i = 0, l = outline.length; i < l; ) {
36186 var action = outline[ i ++ ];
36188 switch ( action ) {
36190 case 'm': // moveTo
36192 x = outline[ i ++ ] * scale + offsetX;
36193 y = outline[ i ++ ] * scale + offsetY;
36195 path.moveTo( x, y );
36199 case 'l': // lineTo
36201 x = outline[ i ++ ] * scale + offsetX;
36202 y = outline[ i ++ ] * scale + offsetY;
36204 path.lineTo( x, y );
36208 case 'q': // quadraticCurveTo
36210 cpx = outline[ i ++ ] * scale + offsetX;
36211 cpy = outline[ i ++ ] * scale + offsetY;
36212 cpx1 = outline[ i ++ ] * scale + offsetX;
36213 cpy1 = outline[ i ++ ] * scale + offsetY;
36215 path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
36217 laste = pts[ pts.length - 1 ];
36224 for ( var i2 = 1; i2 <= divisions; i2 ++ ) {
36226 var t = i2 / divisions;
36227 QuadraticBezier( t, cpx0, cpx1, cpx );
36228 QuadraticBezier( t, cpy0, cpy1, cpy );
36236 case 'b': // bezierCurveTo
36238 cpx = outline[ i ++ ] * scale + offsetX;
36239 cpy = outline[ i ++ ] * scale + offsetY;
36240 cpx1 = outline[ i ++ ] * scale + offsetX;
36241 cpy1 = outline[ i ++ ] * scale + offsetY;
36242 cpx2 = outline[ i ++ ] * scale + offsetX;
36243 cpy2 = outline[ i ++ ] * scale + offsetY;
36245 path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
36247 laste = pts[ pts.length - 1 ];
36254 for ( var i2 = 1; i2 <= divisions; i2 ++ ) {
36256 var t = i2 / divisions;
36257 CubicBezier( t, cpx0, cpx1, cpx2, cpx );
36258 CubicBezier( t, cpy0, cpy1, cpy2, cpy );
36272 return { offsetX: glyph.ha * scale, path: path };
36278 if ( size === undefined ) size = 100;
36279 if ( divisions === undefined ) divisions = 4;
36281 var data = this.data;
36283 var paths = createPaths( text );
36286 for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
36288 Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
36299 * @author mrdoob / http://mrdoob.com/
36302 function FontLoader( manager ) {
36304 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
36308 Object.assign( FontLoader.prototype, {
36310 load: function ( url, onLoad, onProgress, onError ) {
36314 var loader = new FileLoader( this.manager );
36315 loader.load( url, function ( text ) {
36321 json = JSON.parse( text );
36325 console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
36326 json = JSON.parse( text.substring( 65, text.length - 2 ) );
36330 var font = scope.parse( json );
36332 if ( onLoad ) onLoad( font );
36334 }, onProgress, onError );
36338 parse: function ( json ) {
36340 return new Font( json );
36348 var AudioContext = {
36350 getContext: function () {
36352 if ( context === undefined ) {
36354 context = new ( window.AudioContext || window.webkitAudioContext )();
36362 setContext: function ( value ) {
36371 * @author Reece Aaron Lecrivain / http://reecenotes.com/
36374 function AudioLoader( manager ) {
36376 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
36380 Object.assign( AudioLoader.prototype, {
36382 load: function ( url, onLoad, onProgress, onError ) {
36384 var loader = new FileLoader( this.manager );
36385 loader.setResponseType( 'arraybuffer' );
36386 loader.load( url, function ( buffer ) {
36388 var context = AudioContext.getContext();
36390 context.decodeAudioData( buffer, function ( audioBuffer ) {
36392 onLoad( audioBuffer );
36396 }, onProgress, onError );
36403 * @author mrdoob / http://mrdoob.com/
36406 function StereoCamera() {
36408 this.type = 'StereoCamera';
36412 this.eyeSep = 0.064;
36414 this.cameraL = new PerspectiveCamera();
36415 this.cameraL.layers.enable( 1 );
36416 this.cameraL.matrixAutoUpdate = false;
36418 this.cameraR = new PerspectiveCamera();
36419 this.cameraR.layers.enable( 2 );
36420 this.cameraR.matrixAutoUpdate = false;
36424 Object.assign( StereoCamera.prototype, {
36426 update: ( function () {
36428 var instance, focus, fov, aspect, near, far, zoom, eyeSep;
36430 var eyeRight = new Matrix4();
36431 var eyeLeft = new Matrix4();
36433 return function update( camera ) {
36435 var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||
36436 aspect !== camera.aspect * this.aspect || near !== camera.near ||
36437 far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep;
36439 if ( needsUpdate ) {
36442 focus = camera.focus;
36444 aspect = camera.aspect * this.aspect;
36445 near = camera.near;
36447 zoom = camera.zoom;
36449 // Off-axis stereoscopic effect based on
36450 // http://paulbourke.net/stereographics/stereorender/
36452 var projectionMatrix = camera.projectionMatrix.clone();
36453 eyeSep = this.eyeSep / 2;
36454 var eyeSepOnProjection = eyeSep * near / focus;
36455 var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;
36458 // translate xOffset
36460 eyeLeft.elements[ 12 ] = - eyeSep;
36461 eyeRight.elements[ 12 ] = eyeSep;
36465 xmin = - ymax * aspect + eyeSepOnProjection;
36466 xmax = ymax * aspect + eyeSepOnProjection;
36468 projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
36469 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
36471 this.cameraL.projectionMatrix.copy( projectionMatrix );
36475 xmin = - ymax * aspect - eyeSepOnProjection;
36476 xmax = ymax * aspect - eyeSepOnProjection;
36478 projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
36479 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
36481 this.cameraR.projectionMatrix.copy( projectionMatrix );
36485 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
36486 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );
36495 * Camera for rendering cube maps
36496 * - renders scene into axis-aligned cube
36498 * @author alteredq / http://alteredqualia.com/
36501 function CubeCamera( near, far, cubeResolution ) {
36503 Object3D.call( this );
36505 this.type = 'CubeCamera';
36507 var fov = 90, aspect = 1;
36509 var cameraPX = new PerspectiveCamera( fov, aspect, near, far );
36510 cameraPX.up.set( 0, - 1, 0 );
36511 cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
36512 this.add( cameraPX );
36514 var cameraNX = new PerspectiveCamera( fov, aspect, near, far );
36515 cameraNX.up.set( 0, - 1, 0 );
36516 cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
36517 this.add( cameraNX );
36519 var cameraPY = new PerspectiveCamera( fov, aspect, near, far );
36520 cameraPY.up.set( 0, 0, 1 );
36521 cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
36522 this.add( cameraPY );
36524 var cameraNY = new PerspectiveCamera( fov, aspect, near, far );
36525 cameraNY.up.set( 0, 0, - 1 );
36526 cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
36527 this.add( cameraNY );
36529 var cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
36530 cameraPZ.up.set( 0, - 1, 0 );
36531 cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
36532 this.add( cameraPZ );
36534 var cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
36535 cameraNZ.up.set( 0, - 1, 0 );
36536 cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
36537 this.add( cameraNZ );
36539 var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };
36541 this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );
36542 this.renderTarget.texture.name = "CubeCamera";
36544 this.update = function ( renderer, scene ) {
36546 if ( this.parent === null ) this.updateMatrixWorld();
36548 var renderTarget = this.renderTarget;
36549 var generateMipmaps = renderTarget.texture.generateMipmaps;
36551 renderTarget.texture.generateMipmaps = false;
36553 renderTarget.activeCubeFace = 0;
36554 renderer.render( scene, cameraPX, renderTarget );
36556 renderTarget.activeCubeFace = 1;
36557 renderer.render( scene, cameraNX, renderTarget );
36559 renderTarget.activeCubeFace = 2;
36560 renderer.render( scene, cameraPY, renderTarget );
36562 renderTarget.activeCubeFace = 3;
36563 renderer.render( scene, cameraNY, renderTarget );
36565 renderTarget.activeCubeFace = 4;
36566 renderer.render( scene, cameraPZ, renderTarget );
36568 renderTarget.texture.generateMipmaps = generateMipmaps;
36570 renderTarget.activeCubeFace = 5;
36571 renderer.render( scene, cameraNZ, renderTarget );
36573 renderer.setRenderTarget( null );
36577 this.clear = function ( renderer, color, depth, stencil ) {
36579 var renderTarget = this.renderTarget;
36581 for ( var i = 0; i < 6; i ++ ) {
36583 renderTarget.activeCubeFace = i;
36584 renderer.setRenderTarget( renderTarget );
36586 renderer.clear( color, depth, stencil );
36590 renderer.setRenderTarget( null );
36596 CubeCamera.prototype = Object.create( Object3D.prototype );
36597 CubeCamera.prototype.constructor = CubeCamera;
36600 * @author mrdoob / http://mrdoob.com/
36603 function AudioListener() {
36605 Object3D.call( this );
36607 this.type = 'AudioListener';
36609 this.context = AudioContext.getContext();
36611 this.gain = this.context.createGain();
36612 this.gain.connect( this.context.destination );
36614 this.filter = null;
36618 AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
36620 constructor: AudioListener,
36622 getInput: function () {
36628 removeFilter: function ( ) {
36630 if ( this.filter !== null ) {
36632 this.gain.disconnect( this.filter );
36633 this.filter.disconnect( this.context.destination );
36634 this.gain.connect( this.context.destination );
36635 this.filter = null;
36641 getFilter: function () {
36643 return this.filter;
36647 setFilter: function ( value ) {
36649 if ( this.filter !== null ) {
36651 this.gain.disconnect( this.filter );
36652 this.filter.disconnect( this.context.destination );
36656 this.gain.disconnect( this.context.destination );
36660 this.filter = value;
36661 this.gain.connect( this.filter );
36662 this.filter.connect( this.context.destination );
36666 getMasterVolume: function () {
36668 return this.gain.gain.value;
36672 setMasterVolume: function ( value ) {
36674 this.gain.gain.value = value;
36678 updateMatrixWorld: ( function () {
36680 var position = new Vector3();
36681 var quaternion = new Quaternion();
36682 var scale = new Vector3();
36684 var orientation = new Vector3();
36686 return function updateMatrixWorld( force ) {
36688 Object3D.prototype.updateMatrixWorld.call( this, force );
36690 var listener = this.context.listener;
36693 this.matrixWorld.decompose( position, quaternion, scale );
36695 orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion );
36697 if ( listener.positionX ) {
36699 listener.positionX.setValueAtTime( position.x, this.context.currentTime );
36700 listener.positionY.setValueAtTime( position.y, this.context.currentTime );
36701 listener.positionZ.setValueAtTime( position.z, this.context.currentTime );
36702 listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );
36703 listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );
36704 listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );
36705 listener.upX.setValueAtTime( up.x, this.context.currentTime );
36706 listener.upY.setValueAtTime( up.y, this.context.currentTime );
36707 listener.upZ.setValueAtTime( up.z, this.context.currentTime );
36711 listener.setPosition( position.x, position.y, position.z );
36712 listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );
36723 * @author mrdoob / http://mrdoob.com/
36724 * @author Reece Aaron Lecrivain / http://reecenotes.com/
36727 function Audio( listener ) {
36729 Object3D.call( this );
36731 this.type = 'Audio';
36733 this.context = listener.context;
36735 this.gain = this.context.createGain();
36736 this.gain.connect( listener.getInput() );
36738 this.autoplay = false;
36740 this.buffer = null;
36742 this.startTime = 0;
36743 this.playbackRate = 1;
36744 this.isPlaying = false;
36745 this.hasPlaybackControl = true;
36746 this.sourceType = 'empty';
36752 Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
36754 constructor: Audio,
36756 getOutput: function () {
36762 setNodeSource: function ( audioNode ) {
36764 this.hasPlaybackControl = false;
36765 this.sourceType = 'audioNode';
36766 this.source = audioNode;
36773 setBuffer: function ( audioBuffer ) {
36775 this.buffer = audioBuffer;
36776 this.sourceType = 'buffer';
36778 if ( this.autoplay ) this.play();
36784 play: function () {
36786 if ( this.isPlaying === true ) {
36788 console.warn( 'THREE.Audio: Audio is already playing.' );
36793 if ( this.hasPlaybackControl === false ) {
36795 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36800 var source = this.context.createBufferSource();
36802 source.buffer = this.buffer;
36803 source.loop = this.loop;
36804 source.onended = this.onEnded.bind( this );
36805 source.playbackRate.setValueAtTime( this.playbackRate, this.startTime );
36806 source.start( 0, this.startTime );
36808 this.isPlaying = true;
36810 this.source = source;
36812 return this.connect();
36816 pause: function () {
36818 if ( this.hasPlaybackControl === false ) {
36820 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36825 this.source.stop();
36826 this.startTime = this.context.currentTime;
36827 this.isPlaying = false;
36833 stop: function () {
36835 if ( this.hasPlaybackControl === false ) {
36837 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36842 this.source.stop();
36843 this.startTime = 0;
36844 this.isPlaying = false;
36850 connect: function () {
36852 if ( this.filters.length > 0 ) {
36854 this.source.connect( this.filters[ 0 ] );
36856 for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
36858 this.filters[ i - 1 ].connect( this.filters[ i ] );
36862 this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
36866 this.source.connect( this.getOutput() );
36874 disconnect: function () {
36876 if ( this.filters.length > 0 ) {
36878 this.source.disconnect( this.filters[ 0 ] );
36880 for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
36882 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
36886 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
36890 this.source.disconnect( this.getOutput() );
36898 getFilters: function () {
36900 return this.filters;
36904 setFilters: function ( value ) {
36906 if ( ! value ) value = [];
36908 if ( this.isPlaying === true ) {
36911 this.filters = value;
36916 this.filters = value;
36924 getFilter: function () {
36926 return this.getFilters()[ 0 ];
36930 setFilter: function ( filter ) {
36932 return this.setFilters( filter ? [ filter ] : [] );
36936 setPlaybackRate: function ( value ) {
36938 if ( this.hasPlaybackControl === false ) {
36940 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36945 this.playbackRate = value;
36947 if ( this.isPlaying === true ) {
36949 this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );
36957 getPlaybackRate: function () {
36959 return this.playbackRate;
36963 onEnded: function () {
36965 this.isPlaying = false;
36969 getLoop: function () {
36971 if ( this.hasPlaybackControl === false ) {
36973 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36982 setLoop: function ( value ) {
36984 if ( this.hasPlaybackControl === false ) {
36986 console.warn( 'THREE.Audio: this Audio has no playback control.' );
36993 if ( this.isPlaying === true ) {
36995 this.source.loop = this.loop;
37003 getVolume: function () {
37005 return this.gain.gain.value;
37009 setVolume: function ( value ) {
37011 this.gain.gain.value = value;
37020 * @author mrdoob / http://mrdoob.com/
37023 function PositionalAudio( listener ) {
37025 Audio.call( this, listener );
37027 this.panner = this.context.createPanner();
37028 this.panner.connect( this.gain );
37032 PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
37034 constructor: PositionalAudio,
37036 getOutput: function () {
37038 return this.panner;
37042 getRefDistance: function () {
37044 return this.panner.refDistance;
37048 setRefDistance: function ( value ) {
37050 this.panner.refDistance = value;
37054 getRolloffFactor: function () {
37056 return this.panner.rolloffFactor;
37060 setRolloffFactor: function ( value ) {
37062 this.panner.rolloffFactor = value;
37066 getDistanceModel: function () {
37068 return this.panner.distanceModel;
37072 setDistanceModel: function ( value ) {
37074 this.panner.distanceModel = value;
37078 getMaxDistance: function () {
37080 return this.panner.maxDistance;
37084 setMaxDistance: function ( value ) {
37086 this.panner.maxDistance = value;
37090 updateMatrixWorld: ( function () {
37092 var position = new Vector3();
37094 return function updateMatrixWorld( force ) {
37096 Object3D.prototype.updateMatrixWorld.call( this, force );
37098 position.setFromMatrixPosition( this.matrixWorld );
37100 this.panner.setPosition( position.x, position.y, position.z );
37110 * @author mrdoob / http://mrdoob.com/
37113 function AudioAnalyser( audio, fftSize ) {
37115 this.analyser = audio.context.createAnalyser();
37116 this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
37118 this.data = new Uint8Array( this.analyser.frequencyBinCount );
37120 audio.getOutput().connect( this.analyser );
37124 Object.assign( AudioAnalyser.prototype, {
37126 getFrequencyData: function () {
37128 this.analyser.getByteFrequencyData( this.data );
37134 getAverageFrequency: function () {
37136 var value = 0, data = this.getFrequencyData();
37138 for ( var i = 0; i < data.length; i ++ ) {
37140 value += data[ i ];
37144 return value / data.length;
37152 * Buffered scene graph property that allows weighted accumulation.
37155 * @author Ben Houston / http://clara.io/
37156 * @author David Sarno / http://lighthaus.us/
37160 function PropertyMixer( binding, typeName, valueSize ) {
37162 this.binding = binding;
37163 this.valueSize = valueSize;
37165 var bufferType = Float64Array,
37168 switch ( typeName ) {
37171 mixFunction = this._slerp;
37176 bufferType = Array;
37177 mixFunction = this._select;
37181 mixFunction = this._lerp;
37185 this.buffer = new bufferType( valueSize * 4 );
37186 // layout: [ incoming | accu0 | accu1 | orig ]
37188 // interpolators can use .buffer as their .result
37189 // the data then goes to 'incoming'
37191 // 'accu0' and 'accu1' are used frame-interleaved for
37192 // the cumulative result and are compared to detect
37195 // 'orig' stores the original state of the property
37197 this._mixBufferRegion = mixFunction;
37199 this.cumulativeWeight = 0;
37202 this.referenceCount = 0;
37206 Object.assign( PropertyMixer.prototype, {
37208 // accumulate data in the 'incoming' region into 'accu<i>'
37209 accumulate: function ( accuIndex, weight ) {
37211 // note: happily accumulating nothing when weight = 0, the caller knows
37212 // the weight and shouldn't have made the call in the first place
37214 var buffer = this.buffer,
37215 stride = this.valueSize,
37216 offset = accuIndex * stride + stride,
37218 currentWeight = this.cumulativeWeight;
37220 if ( currentWeight === 0 ) {
37222 // accuN := incoming * weight
37224 for ( var i = 0; i !== stride; ++ i ) {
37226 buffer[ offset + i ] = buffer[ i ];
37230 currentWeight = weight;
37234 // accuN := accuN + incoming * weight
37236 currentWeight += weight;
37237 var mix = weight / currentWeight;
37238 this._mixBufferRegion( buffer, offset, 0, mix, stride );
37242 this.cumulativeWeight = currentWeight;
37246 // apply the state of 'accu<i>' to the binding when accus differ
37247 apply: function ( accuIndex ) {
37249 var stride = this.valueSize,
37250 buffer = this.buffer,
37251 offset = accuIndex * stride + stride,
37253 weight = this.cumulativeWeight,
37255 binding = this.binding;
37257 this.cumulativeWeight = 0;
37259 if ( weight < 1 ) {
37261 // accuN := accuN + original * ( 1 - cumulativeWeight )
37263 var originalValueOffset = stride * 3;
37265 this._mixBufferRegion(
37266 buffer, offset, originalValueOffset, 1 - weight, stride );
37270 for ( var i = stride, e = stride + stride; i !== e; ++ i ) {
37272 if ( buffer[ i ] !== buffer[ i + stride ] ) {
37274 // value has changed -> update scene graph
37276 binding.setValue( buffer, offset );
37285 // remember the state of the bound property and copy it to both accus
37286 saveOriginalState: function () {
37288 var binding = this.binding;
37290 var buffer = this.buffer,
37291 stride = this.valueSize,
37293 originalValueOffset = stride * 3;
37295 binding.getValue( buffer, originalValueOffset );
37297 // accu[0..1] := orig -- initially detect changes against the original
37298 for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {
37300 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
37304 this.cumulativeWeight = 0;
37308 // apply the state previously taken via 'saveOriginalState' to the binding
37309 restoreOriginalState: function () {
37311 var originalValueOffset = this.valueSize * 3;
37312 this.binding.setValue( this.buffer, originalValueOffset );
37319 _select: function ( buffer, dstOffset, srcOffset, t, stride ) {
37323 for ( var i = 0; i !== stride; ++ i ) {
37325 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
37333 _slerp: function ( buffer, dstOffset, srcOffset, t ) {
37335 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
37339 _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
37343 for ( var i = 0; i !== stride; ++ i ) {
37345 var j = dstOffset + i;
37347 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
37357 * A reference to a real property in the scene graph.
37360 * @author Ben Houston / http://clara.io/
37361 * @author David Sarno / http://lighthaus.us/
37365 function Composite( targetGroup, path, optionalParsedPath ) {
37367 var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
37369 this._targetGroup = targetGroup;
37370 this._bindings = targetGroup.subscribe_( path, parsedPath );
37374 Object.assign( Composite.prototype, {
37376 getValue: function ( array, offset ) {
37378 this.bind(); // bind all binding
37380 var firstValidIndex = this._targetGroup.nCachedObjects_,
37381 binding = this._bindings[ firstValidIndex ];
37383 // and only call .getValue on the first
37384 if ( binding !== undefined ) binding.getValue( array, offset );
37388 setValue: function ( array, offset ) {
37390 var bindings = this._bindings;
37392 for ( var i = this._targetGroup.nCachedObjects_,
37393 n = bindings.length; i !== n; ++ i ) {
37395 bindings[ i ].setValue( array, offset );
37401 bind: function () {
37403 var bindings = this._bindings;
37405 for ( var i = this._targetGroup.nCachedObjects_,
37406 n = bindings.length; i !== n; ++ i ) {
37408 bindings[ i ].bind();
37414 unbind: function () {
37416 var bindings = this._bindings;
37418 for ( var i = this._targetGroup.nCachedObjects_,
37419 n = bindings.length; i !== n; ++ i ) {
37421 bindings[ i ].unbind();
37430 function PropertyBinding( rootNode, path, parsedPath ) {
37433 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
37435 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
37437 this.rootNode = rootNode;
37441 Object.assign( PropertyBinding, {
37443 Composite: Composite,
37445 create: function ( root, path, parsedPath ) {
37447 if ( ! ( root && root.isAnimationObjectGroup ) ) {
37449 return new PropertyBinding( root, path, parsedPath );
37453 return new PropertyBinding.Composite( root, path, parsedPath );
37460 * Replaces spaces with underscores and removes unsupported characters from
37461 * node names, to ensure compatibility with parseTrackName().
37463 * @param {string} name Node name to be sanitized.
37466 sanitizeNodeName: function ( name ) {
37468 return name.replace( /\s/g, '_' ).replace( /[^\w-]/g, '' );
37472 parseTrackName: function () {
37474 // Parent directories, delimited by '/' or ':'. Currently unused, but must
37475 // be matched to parse the rest of the track name.
37476 var directoryRe = /((?:[\w-]+[\/:])*)/;
37478 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
37479 var nodeRe = /([\w-\.]+)?/;
37481 // Object on target node, and accessor. Name may contain only word
37482 // characters. Accessor may contain any character except closing bracket.
37483 var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/;
37485 // Property and accessor. May contain only word characters. Accessor may
37486 // contain any non-bracket characters.
37487 var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/;
37489 var trackRe = new RegExp(''
37491 + directoryRe.source
37494 + propertyRe.source
37498 var supportedObjectNames = [ 'material', 'materials', 'bones' ];
37500 return function ( trackName ) {
37502 var matches = trackRe.exec( trackName );
37506 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
37511 // directoryName: matches[ 1 ], // (tschw) currently unused
37512 nodeName: matches[ 2 ],
37513 objectName: matches[ 3 ],
37514 objectIndex: matches[ 4 ],
37515 propertyName: matches[ 5 ], // required
37516 propertyIndex: matches[ 6 ]
37519 var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
37521 if ( lastDot !== undefined && lastDot !== -1 ) {
37523 var objectName = results.nodeName.substring( lastDot + 1 );
37525 // Object names must be checked against a whitelist. Otherwise, there
37526 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
37527 // 'bar' could be the objectName, or part of a nodeName (which can
37528 // include '.' characters).
37529 if ( supportedObjectNames.indexOf( objectName ) !== -1 ) {
37531 results.nodeName = results.nodeName.substring( 0, lastDot );
37532 results.objectName = objectName;
37538 if ( results.propertyName === null || results.propertyName.length === 0 ) {
37540 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
37550 findNode: function ( root, nodeName ) {
37552 if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
37558 // search into skeleton bones.
37559 if ( root.skeleton ) {
37561 var searchSkeleton = function ( skeleton ) {
37563 for ( var i = 0; i < skeleton.bones.length; i ++ ) {
37565 var bone = skeleton.bones[ i ];
37567 if ( bone.name === nodeName ) {
37579 var bone = searchSkeleton( root.skeleton );
37589 // search into node subtree.
37590 if ( root.children ) {
37592 var searchNodeSubtree = function ( children ) {
37594 for ( var i = 0; i < children.length; i ++ ) {
37596 var childNode = children[ i ];
37598 if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
37604 var result = searchNodeSubtree( childNode.children );
37606 if ( result ) return result;
37614 var subTreeNode = searchNodeSubtree( root.children );
37616 if ( subTreeNode ) {
37618 return subTreeNode;
37630 Object.assign( PropertyBinding.prototype, { // prototype, continued
37632 // these are used to "bind" a nonexistent property
37633 _getValue_unavailable: function () {},
37634 _setValue_unavailable: function () {},
37646 MatrixWorldNeedsUpdate: 2
37649 GetterByBindingType: [
37651 function getValue_direct( buffer, offset ) {
37653 buffer[ offset ] = this.node[ this.propertyName ];
37657 function getValue_array( buffer, offset ) {
37659 var source = this.resolvedProperty;
37661 for ( var i = 0, n = source.length; i !== n; ++ i ) {
37663 buffer[ offset ++ ] = source[ i ];
37669 function getValue_arrayElement( buffer, offset ) {
37671 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
37675 function getValue_toArray( buffer, offset ) {
37677 this.resolvedProperty.toArray( buffer, offset );
37683 SetterByBindingTypeAndVersioning: [
37688 function setValue_direct( buffer, offset ) {
37690 this.node[ this.propertyName ] = buffer[ offset ];
37694 function setValue_direct_setNeedsUpdate( buffer, offset ) {
37696 this.node[ this.propertyName ] = buffer[ offset ];
37697 this.targetObject.needsUpdate = true;
37701 function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
37703 this.node[ this.propertyName ] = buffer[ offset ];
37704 this.targetObject.matrixWorldNeedsUpdate = true;
37712 function setValue_array( buffer, offset ) {
37714 var dest = this.resolvedProperty;
37716 for ( var i = 0, n = dest.length; i !== n; ++ i ) {
37718 dest[ i ] = buffer[ offset ++ ];
37724 function setValue_array_setNeedsUpdate( buffer, offset ) {
37726 var dest = this.resolvedProperty;
37728 for ( var i = 0, n = dest.length; i !== n; ++ i ) {
37730 dest[ i ] = buffer[ offset ++ ];
37734 this.targetObject.needsUpdate = true;
37738 function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
37740 var dest = this.resolvedProperty;
37742 for ( var i = 0, n = dest.length; i !== n; ++ i ) {
37744 dest[ i ] = buffer[ offset ++ ];
37748 this.targetObject.matrixWorldNeedsUpdate = true;
37756 function setValue_arrayElement( buffer, offset ) {
37758 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
37762 function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
37764 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
37765 this.targetObject.needsUpdate = true;
37769 function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
37771 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
37772 this.targetObject.matrixWorldNeedsUpdate = true;
37780 function setValue_fromArray( buffer, offset ) {
37782 this.resolvedProperty.fromArray( buffer, offset );
37786 function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
37788 this.resolvedProperty.fromArray( buffer, offset );
37789 this.targetObject.needsUpdate = true;
37793 function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
37795 this.resolvedProperty.fromArray( buffer, offset );
37796 this.targetObject.matrixWorldNeedsUpdate = true;
37804 getValue: function getValue_unbound( targetArray, offset ) {
37807 this.getValue( targetArray, offset );
37809 // Note: This class uses a State pattern on a per-method basis:
37810 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
37811 // prototype version of these methods with one that represents
37812 // the bound state. When the property is not found, the methods
37817 setValue: function getValue_unbound( sourceArray, offset ) {
37820 this.setValue( sourceArray, offset );
37824 // create getter / setter pair for a property in the scene graph
37825 bind: function () {
37827 var targetObject = this.node,
37828 parsedPath = this.parsedPath,
37830 objectName = parsedPath.objectName,
37831 propertyName = parsedPath.propertyName,
37832 propertyIndex = parsedPath.propertyIndex;
37834 if ( ! targetObject ) {
37836 targetObject = PropertyBinding.findNode(
37837 this.rootNode, parsedPath.nodeName ) || this.rootNode;
37839 this.node = targetObject;
37843 // set fail state so we can just 'return' on error
37844 this.getValue = this._getValue_unavailable;
37845 this.setValue = this._setValue_unavailable;
37847 // ensure there is a value node
37848 if ( ! targetObject ) {
37850 console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
37855 if ( objectName ) {
37857 var objectIndex = parsedPath.objectIndex;
37859 // special cases were we need to reach deeper into the hierarchy to get the face materials....
37860 switch ( objectName ) {
37864 if ( ! targetObject.material ) {
37866 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
37871 if ( ! targetObject.material.materials ) {
37873 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
37878 targetObject = targetObject.material.materials;
37884 if ( ! targetObject.skeleton ) {
37886 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
37891 // potential future optimization: skip this if propertyIndex is already an integer
37892 // and convert the integer string to a true integer.
37894 targetObject = targetObject.skeleton.bones;
37896 // support resolving morphTarget names into indices.
37897 for ( var i = 0; i < targetObject.length; i ++ ) {
37899 if ( targetObject[ i ].name === objectIndex ) {
37912 if ( targetObject[ objectName ] === undefined ) {
37914 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
37919 targetObject = targetObject[ objectName ];
37924 if ( objectIndex !== undefined ) {
37926 if ( targetObject[ objectIndex ] === undefined ) {
37928 console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
37933 targetObject = targetObject[ objectIndex ];
37939 // resolve property
37940 var nodeProperty = targetObject[ propertyName ];
37942 if ( nodeProperty === undefined ) {
37944 var nodeName = parsedPath.nodeName;
37946 console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
37947 '.' + propertyName + ' but it wasn\'t found.', targetObject );
37952 // determine versioning scheme
37953 var versioning = this.Versioning.None;
37955 if ( targetObject.needsUpdate !== undefined ) { // material
37957 versioning = this.Versioning.NeedsUpdate;
37958 this.targetObject = targetObject;
37960 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
37962 versioning = this.Versioning.MatrixWorldNeedsUpdate;
37963 this.targetObject = targetObject;
37967 // determine how the property gets bound
37968 var bindingType = this.BindingType.Direct;
37970 if ( propertyIndex !== undefined ) {
37972 // access a sub element of the property array (only primitives are supported right now)
37974 if ( propertyName === "morphTargetInfluences" ) {
37976 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
37978 // support resolving morphTarget names into indices.
37979 if ( ! targetObject.geometry ) {
37981 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
37986 if ( targetObject.geometry.isBufferGeometry ) {
37988 if ( ! targetObject.geometry.morphAttributes ) {
37990 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
37995 for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {
37997 if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {
38009 if ( ! targetObject.geometry.morphTargets ) {
38011 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
38016 for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
38018 if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
38031 bindingType = this.BindingType.ArrayElement;
38033 this.resolvedProperty = nodeProperty;
38034 this.propertyIndex = propertyIndex;
38036 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
38038 // must use copy for Object3D.Euler/Quaternion
38040 bindingType = this.BindingType.HasFromToArray;
38042 this.resolvedProperty = nodeProperty;
38044 } else if ( Array.isArray( nodeProperty ) ) {
38046 bindingType = this.BindingType.EntireArray;
38048 this.resolvedProperty = nodeProperty;
38052 this.propertyName = propertyName;
38056 // select getter / setter
38057 this.getValue = this.GetterByBindingType[ bindingType ];
38058 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
38062 unbind: function () {
38066 // back to the prototype version of getValue / setValue
38067 // note: avoiding to mutate the shape of 'this' via 'delete'
38068 this.getValue = this._getValue_unbound;
38069 this.setValue = this._setValue_unbound;
38075 //!\ DECLARE ALIAS AFTER assign prototype !
38076 Object.assign( PropertyBinding.prototype, {
38078 // initial state of these methods that calls 'bind'
38079 _getValue_unbound: PropertyBinding.prototype.getValue,
38080 _setValue_unbound: PropertyBinding.prototype.setValue,
38086 * A group of objects that receives a shared animation state.
38090 * - Add objects you would otherwise pass as 'root' to the
38091 * constructor or the .clipAction method of AnimationMixer.
38093 * - Instead pass this object as 'root'.
38095 * - You can also add and remove objects later when the mixer
38100 * Objects of this class appear as one object to the mixer,
38101 * so cache control of the individual objects must be done
38106 * - The animated properties must be compatible among the
38107 * all objects in the group.
38109 * - A single property can either be controlled through a
38110 * target group or directly, but not both.
38115 function AnimationObjectGroup( var_args ) {
38117 this.uuid = _Math.generateUUID();
38119 // cached objects followed by the active ones
38120 this._objects = Array.prototype.slice.call( arguments );
38122 this.nCachedObjects_ = 0; // threshold
38123 // note: read by PropertyBinding.Composite
38126 this._indicesByUUID = indices; // for bookkeeping
38128 for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
38130 indices[ arguments[ i ].uuid ] = i;
38134 this._paths = []; // inside: string
38135 this._parsedPaths = []; // inside: { we don't care, here }
38136 this._bindings = []; // inside: Array< PropertyBinding >
38137 this._bindingsIndicesByPath = {}; // inside: indices in these arrays
38144 get total() { return scope._objects.length; },
38145 get inUse() { return this.total - scope.nCachedObjects_; }
38148 get bindingsPerObject() { return scope._bindings.length; }
38154 Object.assign( AnimationObjectGroup.prototype, {
38156 isAnimationObjectGroup: true,
38158 add: function( var_args ) {
38160 var objects = this._objects,
38161 nObjects = objects.length,
38162 nCachedObjects = this.nCachedObjects_,
38163 indicesByUUID = this._indicesByUUID,
38164 paths = this._paths,
38165 parsedPaths = this._parsedPaths,
38166 bindings = this._bindings,
38167 nBindings = bindings.length;
38169 for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
38171 var object = arguments[ i ],
38172 uuid = object.uuid,
38173 index = indicesByUUID[ uuid ],
38174 knownObject = undefined;
38176 if ( index === undefined ) {
38178 // unknown object -> add it to the ACTIVE region
38180 index = nObjects ++;
38181 indicesByUUID[ uuid ] = index;
38182 objects.push( object );
38184 // accounting is done, now do the same for all bindings
38186 for ( var j = 0, m = nBindings; j !== m; ++ j ) {
38188 bindings[ j ].push(
38189 new PropertyBinding(
38190 object, paths[ j ], parsedPaths[ j ] ) );
38194 } else if ( index < nCachedObjects ) {
38196 knownObject = objects[ index ];
38198 // move existing object to the ACTIVE region
38200 var firstActiveIndex = -- nCachedObjects,
38201 lastCachedObject = objects[ firstActiveIndex ];
38203 indicesByUUID[ lastCachedObject.uuid ] = index;
38204 objects[ index ] = lastCachedObject;
38206 indicesByUUID[ uuid ] = firstActiveIndex;
38207 objects[ firstActiveIndex ] = object;
38209 // accounting is done, now do the same for all bindings
38211 for ( var j = 0, m = nBindings; j !== m; ++ j ) {
38213 var bindingsForPath = bindings[ j ],
38214 lastCached = bindingsForPath[ firstActiveIndex ],
38215 binding = bindingsForPath[ index ];
38217 bindingsForPath[ index ] = lastCached;
38219 if ( binding === undefined ) {
38221 // since we do not bother to create new bindings
38222 // for objects that are cached, the binding may
38223 // or may not exist
38225 binding = new PropertyBinding(
38226 object, paths[ j ], parsedPaths[ j ] );
38230 bindingsForPath[ firstActiveIndex ] = binding;
38234 } else if ( objects[ index ] !== knownObject ) {
38236 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
38237 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
38239 } // else the object is already where we want it to be
38243 this.nCachedObjects_ = nCachedObjects;
38247 remove: function( var_args ) {
38249 var objects = this._objects,
38250 nCachedObjects = this.nCachedObjects_,
38251 indicesByUUID = this._indicesByUUID,
38252 bindings = this._bindings,
38253 nBindings = bindings.length;
38255 for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
38257 var object = arguments[ i ],
38258 uuid = object.uuid,
38259 index = indicesByUUID[ uuid ];
38261 if ( index !== undefined && index >= nCachedObjects ) {
38263 // move existing object into the CACHED region
38265 var lastCachedIndex = nCachedObjects ++,
38266 firstActiveObject = objects[ lastCachedIndex ];
38268 indicesByUUID[ firstActiveObject.uuid ] = index;
38269 objects[ index ] = firstActiveObject;
38271 indicesByUUID[ uuid ] = lastCachedIndex;
38272 objects[ lastCachedIndex ] = object;
38274 // accounting is done, now do the same for all bindings
38276 for ( var j = 0, m = nBindings; j !== m; ++ j ) {
38278 var bindingsForPath = bindings[ j ],
38279 firstActive = bindingsForPath[ lastCachedIndex ],
38280 binding = bindingsForPath[ index ];
38282 bindingsForPath[ index ] = firstActive;
38283 bindingsForPath[ lastCachedIndex ] = binding;
38291 this.nCachedObjects_ = nCachedObjects;
38296 uncache: function( var_args ) {
38298 var objects = this._objects,
38299 nObjects = objects.length,
38300 nCachedObjects = this.nCachedObjects_,
38301 indicesByUUID = this._indicesByUUID,
38302 bindings = this._bindings,
38303 nBindings = bindings.length;
38305 for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
38307 var object = arguments[ i ],
38308 uuid = object.uuid,
38309 index = indicesByUUID[ uuid ];
38311 if ( index !== undefined ) {
38313 delete indicesByUUID[ uuid ];
38315 if ( index < nCachedObjects ) {
38317 // object is cached, shrink the CACHED region
38319 var firstActiveIndex = -- nCachedObjects,
38320 lastCachedObject = objects[ firstActiveIndex ],
38321 lastIndex = -- nObjects,
38322 lastObject = objects[ lastIndex ];
38324 // last cached object takes this object's place
38325 indicesByUUID[ lastCachedObject.uuid ] = index;
38326 objects[ index ] = lastCachedObject;
38328 // last object goes to the activated slot and pop
38329 indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
38330 objects[ firstActiveIndex ] = lastObject;
38333 // accounting is done, now do the same for all bindings
38335 for ( var j = 0, m = nBindings; j !== m; ++ j ) {
38337 var bindingsForPath = bindings[ j ],
38338 lastCached = bindingsForPath[ firstActiveIndex ],
38339 last = bindingsForPath[ lastIndex ];
38341 bindingsForPath[ index ] = lastCached;
38342 bindingsForPath[ firstActiveIndex ] = last;
38343 bindingsForPath.pop();
38349 // object is active, just swap with the last and pop
38351 var lastIndex = -- nObjects,
38352 lastObject = objects[ lastIndex ];
38354 indicesByUUID[ lastObject.uuid ] = index;
38355 objects[ index ] = lastObject;
38358 // accounting is done, now do the same for all bindings
38360 for ( var j = 0, m = nBindings; j !== m; ++ j ) {
38362 var bindingsForPath = bindings[ j ];
38364 bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
38365 bindingsForPath.pop();
38369 } // cached or active
38371 } // if object is known
38375 this.nCachedObjects_ = nCachedObjects;
38379 // Internal interface used by befriended PropertyBinding.Composite:
38381 subscribe_: function ( path, parsedPath ) {
38383 // returns an array of bindings for the given path that is changed
38384 // according to the contained objects in the group
38386 var indicesByPath = this._bindingsIndicesByPath,
38387 index = indicesByPath[ path ],
38388 bindings = this._bindings;
38390 if ( index !== undefined ) return bindings[ index ];
38392 var paths = this._paths,
38393 parsedPaths = this._parsedPaths,
38394 objects = this._objects,
38395 nObjects = objects.length,
38396 nCachedObjects = this.nCachedObjects_,
38397 bindingsForPath = new Array( nObjects );
38399 index = bindings.length;
38401 indicesByPath[ path ] = index;
38403 paths.push( path );
38404 parsedPaths.push( parsedPath );
38405 bindings.push( bindingsForPath );
38407 for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
38409 var object = objects[ i ];
38410 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
38414 return bindingsForPath;
38418 unsubscribe_: function ( path ) {
38420 // tells the group to forget about a property path and no longer
38421 // update the array previously obtained with 'subscribe_'
38423 var indicesByPath = this._bindingsIndicesByPath,
38424 index = indicesByPath[ path ];
38426 if ( index !== undefined ) {
38428 var paths = this._paths,
38429 parsedPaths = this._parsedPaths,
38430 bindings = this._bindings,
38431 lastBindingsIndex = bindings.length - 1,
38432 lastBindings = bindings[ lastBindingsIndex ],
38433 lastBindingsPath = path[ lastBindingsIndex ];
38435 indicesByPath[ lastBindingsPath ] = index;
38437 bindings[ index ] = lastBindings;
38440 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
38443 paths[ index ] = paths[ lastBindingsIndex ];
38454 * Action provided by AnimationMixer for scheduling clip playback on specific
38457 * @author Ben Houston / http://clara.io/
38458 * @author David Sarno / http://lighthaus.us/
38463 function AnimationAction( mixer, clip, localRoot ) {
38465 this._mixer = mixer;
38467 this._localRoot = localRoot || null;
38469 var tracks = clip.tracks,
38470 nTracks = tracks.length,
38471 interpolants = new Array( nTracks );
38473 var interpolantSettings = {
38474 endingStart: ZeroCurvatureEnding,
38475 endingEnd: ZeroCurvatureEnding
38478 for ( var i = 0; i !== nTracks; ++ i ) {
38480 var interpolant = tracks[ i ].createInterpolant( null );
38481 interpolants[ i ] = interpolant;
38482 interpolant.settings = interpolantSettings;
38486 this._interpolantSettings = interpolantSettings;
38488 this._interpolants = interpolants; // bound by the mixer
38490 // inside: PropertyMixer (managed by the mixer)
38491 this._propertyBindings = new Array( nTracks );
38493 this._cacheIndex = null; // for the memory manager
38494 this._byClipCacheIndex = null; // for the memory manager
38496 this._timeScaleInterpolant = null;
38497 this._weightInterpolant = null;
38499 this.loop = LoopRepeat;
38500 this._loopCount = -1;
38502 // global mixer time when the action is to be started
38503 // it's set back to 'null' upon start of the action
38504 this._startTime = null;
38506 // scaled local time of the action
38507 // gets clamped or wrapped to 0..clip.duration according to loop
38510 this.timeScale = 1;
38511 this._effectiveTimeScale = 1;
38514 this._effectiveWeight = 1;
38516 this.repetitions = Infinity; // no. of repetitions when looping
38518 this.paused = false; // true -> zero effective time scale
38519 this.enabled = true; // false -> zero effective weight
38521 this.clampWhenFinished = false; // keep feeding the last frame?
38523 this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate
38524 this.zeroSlopeAtEnd = true; // clips for start, loop and end
38528 Object.assign( AnimationAction.prototype, {
38530 // State & Scheduling
38534 this._mixer._activateAction( this );
38542 this._mixer._deactivateAction( this );
38544 return this.reset();
38548 reset: function() {
38550 this.paused = false;
38551 this.enabled = true;
38553 this.time = 0; // restart clip
38554 this._loopCount = -1; // forget previous loops
38555 this._startTime = null; // forget scheduling
38557 return this.stopFading().stopWarping();
38561 isRunning: function() {
38563 return this.enabled && ! this.paused && this.timeScale !== 0 &&
38564 this._startTime === null && this._mixer._isActiveAction( this );
38568 // return true when play has been called
38569 isScheduled: function() {
38571 return this._mixer._isActiveAction( this );
38575 startAt: function( time ) {
38577 this._startTime = time;
38583 setLoop: function( mode, repetitions ) {
38586 this.repetitions = repetitions;
38594 // set the weight stopping any scheduled fading
38595 // although .enabled = false yields an effective weight of zero, this
38596 // method does *not* change .enabled, because it would be confusing
38597 setEffectiveWeight: function( weight ) {
38599 this.weight = weight;
38601 // note: same logic as when updated at runtime
38602 this._effectiveWeight = this.enabled ? weight : 0;
38604 return this.stopFading();
38608 // return the weight considering fading and .enabled
38609 getEffectiveWeight: function() {
38611 return this._effectiveWeight;
38615 fadeIn: function( duration ) {
38617 return this._scheduleFading( duration, 0, 1 );
38621 fadeOut: function( duration ) {
38623 return this._scheduleFading( duration, 1, 0 );
38627 crossFadeFrom: function( fadeOutAction, duration, warp ) {
38629 fadeOutAction.fadeOut( duration );
38630 this.fadeIn( duration );
38634 var fadeInDuration = this._clip.duration,
38635 fadeOutDuration = fadeOutAction._clip.duration,
38637 startEndRatio = fadeOutDuration / fadeInDuration,
38638 endStartRatio = fadeInDuration / fadeOutDuration;
38640 fadeOutAction.warp( 1.0, startEndRatio, duration );
38641 this.warp( endStartRatio, 1.0, duration );
38649 crossFadeTo: function( fadeInAction, duration, warp ) {
38651 return fadeInAction.crossFadeFrom( this, duration, warp );
38655 stopFading: function() {
38657 var weightInterpolant = this._weightInterpolant;
38659 if ( weightInterpolant !== null ) {
38661 this._weightInterpolant = null;
38662 this._mixer._takeBackControlInterpolant( weightInterpolant );
38670 // Time Scale Control
38672 // set the time scale stopping any scheduled warping
38673 // although .paused = true yields an effective time scale of zero, this
38674 // method does *not* change .paused, because it would be confusing
38675 setEffectiveTimeScale: function( timeScale ) {
38677 this.timeScale = timeScale;
38678 this._effectiveTimeScale = this.paused ? 0 :timeScale;
38680 return this.stopWarping();
38684 // return the time scale considering warping and .paused
38685 getEffectiveTimeScale: function() {
38687 return this._effectiveTimeScale;
38691 setDuration: function( duration ) {
38693 this.timeScale = this._clip.duration / duration;
38695 return this.stopWarping();
38699 syncWith: function( action ) {
38701 this.time = action.time;
38702 this.timeScale = action.timeScale;
38704 return this.stopWarping();
38708 halt: function( duration ) {
38710 return this.warp( this._effectiveTimeScale, 0, duration );
38714 warp: function( startTimeScale, endTimeScale, duration ) {
38716 var mixer = this._mixer, now = mixer.time,
38717 interpolant = this._timeScaleInterpolant,
38719 timeScale = this.timeScale;
38721 if ( interpolant === null ) {
38723 interpolant = mixer._lendControlInterpolant();
38724 this._timeScaleInterpolant = interpolant;
38728 var times = interpolant.parameterPositions,
38729 values = interpolant.sampleValues;
38732 times[ 1 ] = now + duration;
38734 values[ 0 ] = startTimeScale / timeScale;
38735 values[ 1 ] = endTimeScale / timeScale;
38741 stopWarping: function() {
38743 var timeScaleInterpolant = this._timeScaleInterpolant;
38745 if ( timeScaleInterpolant !== null ) {
38747 this._timeScaleInterpolant = null;
38748 this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
38756 // Object Accessors
38758 getMixer: function() {
38760 return this._mixer;
38764 getClip: function() {
38770 getRoot: function() {
38772 return this._localRoot || this._mixer._root;
38778 _update: function( time, deltaTime, timeDirection, accuIndex ) {
38780 // called by the mixer
38782 if ( ! this.enabled ) {
38784 // call ._updateWeight() to update ._effectiveWeight
38786 this._updateWeight( time );
38791 var startTime = this._startTime;
38793 if ( startTime !== null ) {
38795 // check for scheduled start of action
38797 var timeRunning = ( time - startTime ) * timeDirection;
38798 if ( timeRunning < 0 || timeDirection === 0 ) {
38800 return; // yet to come / don't decide when delta = 0
38806 this._startTime = null; // unschedule
38807 deltaTime = timeDirection * timeRunning;
38811 // apply time scale and advance time
38813 deltaTime *= this._updateTimeScale( time );
38814 var clipTime = this._updateTime( deltaTime );
38816 // note: _updateTime may disable the action resulting in
38817 // an effective weight of 0
38819 var weight = this._updateWeight( time );
38821 if ( weight > 0 ) {
38823 var interpolants = this._interpolants;
38824 var propertyMixers = this._propertyBindings;
38826 for ( var j = 0, m = interpolants.length; j !== m; ++ j ) {
38828 interpolants[ j ].evaluate( clipTime );
38829 propertyMixers[ j ].accumulate( accuIndex, weight );
38837 _updateWeight: function( time ) {
38841 if ( this.enabled ) {
38843 weight = this.weight;
38844 var interpolant = this._weightInterpolant;
38846 if ( interpolant !== null ) {
38848 var interpolantValue = interpolant.evaluate( time )[ 0 ];
38850 weight *= interpolantValue;
38852 if ( time > interpolant.parameterPositions[ 1 ] ) {
38856 if ( interpolantValue === 0 ) {
38858 // faded out, disable
38859 this.enabled = false;
38869 this._effectiveWeight = weight;
38874 _updateTimeScale: function( time ) {
38878 if ( ! this.paused ) {
38880 timeScale = this.timeScale;
38882 var interpolant = this._timeScaleInterpolant;
38884 if ( interpolant !== null ) {
38886 var interpolantValue = interpolant.evaluate( time )[ 0 ];
38888 timeScale *= interpolantValue;
38890 if ( time > interpolant.parameterPositions[ 1 ] ) {
38892 this.stopWarping();
38894 if ( timeScale === 0 ) {
38896 // motion has halted, pause
38897 this.paused = true;
38901 // warp done - apply final time scale
38902 this.timeScale = timeScale;
38912 this._effectiveTimeScale = timeScale;
38917 _updateTime: function( deltaTime ) {
38919 var time = this.time + deltaTime;
38921 if ( deltaTime === 0 ) return time;
38923 var duration = this._clip.duration,
38926 loopCount = this._loopCount;
38928 if ( loop === LoopOnce ) {
38930 if ( loopCount === -1 ) {
38933 this._loopCount = 0;
38934 this._setEndings( true, true, false );
38940 if ( time >= duration ) {
38944 } else if ( time < 0 ) {
38948 } else break handle_stop;
38950 if ( this.clampWhenFinished ) this.paused = true;
38951 else this.enabled = false;
38953 this._mixer.dispatchEvent( {
38954 type: 'finished', action: this,
38955 direction: deltaTime < 0 ? -1 : 1
38960 } else { // repetitive Repeat or PingPong
38962 var pingPong = ( loop === LoopPingPong );
38964 if ( loopCount === -1 ) {
38967 if ( deltaTime >= 0 ) {
38972 true, this.repetitions === 0, pingPong );
38976 // when looping in reverse direction, the initial
38977 // transition through zero counts as a repetition,
38978 // so leave loopCount at -1
38981 this.repetitions === 0, true, pingPong );
38987 if ( time >= duration || time < 0 ) {
38990 var loopDelta = Math.floor( time / duration ); // signed
38991 time -= duration * loopDelta;
38993 loopCount += Math.abs( loopDelta );
38995 var pending = this.repetitions - loopCount;
38997 if ( pending < 0 ) {
38998 // have to stop (switch state, clamp time, fire event)
39000 if ( this.clampWhenFinished ) this.paused = true;
39001 else this.enabled = false;
39003 time = deltaTime > 0 ? duration : 0;
39005 this._mixer.dispatchEvent( {
39006 type: 'finished', action: this,
39007 direction: deltaTime > 0 ? 1 : -1
39013 if ( pending === 0 ) {
39014 // entering the last round
39016 var atStart = deltaTime < 0;
39017 this._setEndings( atStart, ! atStart, pingPong );
39021 this._setEndings( false, false, pingPong );
39025 this._loopCount = loopCount;
39027 this._mixer.dispatchEvent( {
39028 type: 'loop', action: this, loopDelta: loopDelta
39035 if ( pingPong && ( loopCount & 1 ) === 1 ) {
39036 // invert time for the "pong round"
39039 return duration - time;
39050 _setEndings: function( atStart, atEnd, pingPong ) {
39052 var settings = this._interpolantSettings;
39056 settings.endingStart = ZeroSlopeEnding;
39057 settings.endingEnd = ZeroSlopeEnding;
39061 // assuming for LoopOnce atStart == atEnd == true
39065 settings.endingStart = this.zeroSlopeAtStart ?
39066 ZeroSlopeEnding : ZeroCurvatureEnding;
39070 settings.endingStart = WrapAroundEnding;
39076 settings.endingEnd = this.zeroSlopeAtEnd ?
39077 ZeroSlopeEnding : ZeroCurvatureEnding;
39081 settings.endingEnd = WrapAroundEnding;
39089 _scheduleFading: function( duration, weightNow, weightThen ) {
39091 var mixer = this._mixer, now = mixer.time,
39092 interpolant = this._weightInterpolant;
39094 if ( interpolant === null ) {
39096 interpolant = mixer._lendControlInterpolant();
39097 this._weightInterpolant = interpolant;
39101 var times = interpolant.parameterPositions,
39102 values = interpolant.sampleValues;
39104 times[ 0 ] = now; values[ 0 ] = weightNow;
39105 times[ 1 ] = now + duration; values[ 1 ] = weightThen;
39115 * Player for AnimationClips.
39118 * @author Ben Houston / http://clara.io/
39119 * @author David Sarno / http://lighthaus.us/
39123 function AnimationMixer( root ) {
39126 this._initMemoryManager();
39127 this._accuIndex = 0;
39131 this.timeScale = 1.0;
39135 Object.assign( AnimationMixer.prototype, EventDispatcher.prototype, {
39137 _bindAction: function ( action, prototypeAction ) {
39139 var root = action._localRoot || this._root,
39140 tracks = action._clip.tracks,
39141 nTracks = tracks.length,
39142 bindings = action._propertyBindings,
39143 interpolants = action._interpolants,
39144 rootUuid = root.uuid,
39145 bindingsByRoot = this._bindingsByRootAndName,
39146 bindingsByName = bindingsByRoot[ rootUuid ];
39148 if ( bindingsByName === undefined ) {
39150 bindingsByName = {};
39151 bindingsByRoot[ rootUuid ] = bindingsByName;
39155 for ( var i = 0; i !== nTracks; ++ i ) {
39157 var track = tracks[ i ],
39158 trackName = track.name,
39159 binding = bindingsByName[ trackName ];
39161 if ( binding !== undefined ) {
39163 bindings[ i ] = binding;
39167 binding = bindings[ i ];
39169 if ( binding !== undefined ) {
39171 // existing binding, make sure the cache knows
39173 if ( binding._cacheIndex === null ) {
39175 ++ binding.referenceCount;
39176 this._addInactiveBinding( binding, rootUuid, trackName );
39184 var path = prototypeAction && prototypeAction.
39185 _propertyBindings[ i ].binding.parsedPath;
39187 binding = new PropertyMixer(
39188 PropertyBinding.create( root, trackName, path ),
39189 track.ValueTypeName, track.getValueSize() );
39191 ++ binding.referenceCount;
39192 this._addInactiveBinding( binding, rootUuid, trackName );
39194 bindings[ i ] = binding;
39198 interpolants[ i ].resultBuffer = binding.buffer;
39204 _activateAction: function ( action ) {
39206 if ( ! this._isActiveAction( action ) ) {
39208 if ( action._cacheIndex === null ) {
39210 // this action has been forgotten by the cache, but the user
39211 // appears to be still using it -> rebind
39213 var rootUuid = ( action._localRoot || this._root ).uuid,
39214 clipUuid = action._clip.uuid,
39215 actionsForClip = this._actionsByClip[ clipUuid ];
39217 this._bindAction( action,
39218 actionsForClip && actionsForClip.knownActions[ 0 ] );
39220 this._addInactiveAction( action, clipUuid, rootUuid );
39224 var bindings = action._propertyBindings;
39226 // increment reference counts / sort out state
39227 for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
39229 var binding = bindings[ i ];
39231 if ( binding.useCount ++ === 0 ) {
39233 this._lendBinding( binding );
39234 binding.saveOriginalState();
39240 this._lendAction( action );
39246 _deactivateAction: function ( action ) {
39248 if ( this._isActiveAction( action ) ) {
39250 var bindings = action._propertyBindings;
39252 // decrement reference counts / sort out state
39253 for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
39255 var binding = bindings[ i ];
39257 if ( -- binding.useCount === 0 ) {
39259 binding.restoreOriginalState();
39260 this._takeBackBinding( binding );
39266 this._takeBackAction( action );
39274 _initMemoryManager: function () {
39276 this._actions = []; // 'nActiveActions' followed by inactive ones
39277 this._nActiveActions = 0;
39279 this._actionsByClip = {};
39282 // knownActions: Array< AnimationAction > - used as prototypes
39283 // actionByRoot: AnimationAction - lookup
39287 this._bindings = []; // 'nActiveBindings' followed by inactive ones
39288 this._nActiveBindings = 0;
39290 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
39293 this._controlInterpolants = []; // same game as above
39294 this._nActiveControlInterpolants = 0;
39301 get total() { return scope._actions.length; },
39302 get inUse() { return scope._nActiveActions; }
39305 get total() { return scope._bindings.length; },
39306 get inUse() { return scope._nActiveBindings; }
39308 controlInterpolants: {
39309 get total() { return scope._controlInterpolants.length; },
39310 get inUse() { return scope._nActiveControlInterpolants; }
39317 // Memory management for AnimationAction objects
39319 _isActiveAction: function ( action ) {
39321 var index = action._cacheIndex;
39322 return index !== null && index < this._nActiveActions;
39326 _addInactiveAction: function ( action, clipUuid, rootUuid ) {
39328 var actions = this._actions,
39329 actionsByClip = this._actionsByClip,
39330 actionsForClip = actionsByClip[ clipUuid ];
39332 if ( actionsForClip === undefined ) {
39336 knownActions: [ action ],
39341 action._byClipCacheIndex = 0;
39343 actionsByClip[ clipUuid ] = actionsForClip;
39347 var knownActions = actionsForClip.knownActions;
39349 action._byClipCacheIndex = knownActions.length;
39350 knownActions.push( action );
39354 action._cacheIndex = actions.length;
39355 actions.push( action );
39357 actionsForClip.actionByRoot[ rootUuid ] = action;
39361 _removeInactiveAction: function ( action ) {
39363 var actions = this._actions,
39364 lastInactiveAction = actions[ actions.length - 1 ],
39365 cacheIndex = action._cacheIndex;
39367 lastInactiveAction._cacheIndex = cacheIndex;
39368 actions[ cacheIndex ] = lastInactiveAction;
39371 action._cacheIndex = null;
39374 var clipUuid = action._clip.uuid,
39375 actionsByClip = this._actionsByClip,
39376 actionsForClip = actionsByClip[ clipUuid ],
39377 knownActionsForClip = actionsForClip.knownActions,
39380 knownActionsForClip[ knownActionsForClip.length - 1 ],
39382 byClipCacheIndex = action._byClipCacheIndex;
39384 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
39385 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
39386 knownActionsForClip.pop();
39388 action._byClipCacheIndex = null;
39391 var actionByRoot = actionsForClip.actionByRoot,
39392 rootUuid = ( action._localRoot || this._root ).uuid;
39394 delete actionByRoot[ rootUuid ];
39396 if ( knownActionsForClip.length === 0 ) {
39398 delete actionsByClip[ clipUuid ];
39402 this._removeInactiveBindingsForAction( action );
39406 _removeInactiveBindingsForAction: function ( action ) {
39408 var bindings = action._propertyBindings;
39409 for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
39411 var binding = bindings[ i ];
39413 if ( -- binding.referenceCount === 0 ) {
39415 this._removeInactiveBinding( binding );
39423 _lendAction: function ( action ) {
39425 // [ active actions | inactive actions ]
39426 // [ active actions >| inactive actions ]
39431 var actions = this._actions,
39432 prevIndex = action._cacheIndex,
39434 lastActiveIndex = this._nActiveActions ++,
39436 firstInactiveAction = actions[ lastActiveIndex ];
39438 action._cacheIndex = lastActiveIndex;
39439 actions[ lastActiveIndex ] = action;
39441 firstInactiveAction._cacheIndex = prevIndex;
39442 actions[ prevIndex ] = firstInactiveAction;
39446 _takeBackAction: function ( action ) {
39448 // [ active actions | inactive actions ]
39449 // [ active actions |< inactive actions ]
39454 var actions = this._actions,
39455 prevIndex = action._cacheIndex,
39457 firstInactiveIndex = -- this._nActiveActions,
39459 lastActiveAction = actions[ firstInactiveIndex ];
39461 action._cacheIndex = firstInactiveIndex;
39462 actions[ firstInactiveIndex ] = action;
39464 lastActiveAction._cacheIndex = prevIndex;
39465 actions[ prevIndex ] = lastActiveAction;
39469 // Memory management for PropertyMixer objects
39471 _addInactiveBinding: function ( binding, rootUuid, trackName ) {
39473 var bindingsByRoot = this._bindingsByRootAndName,
39474 bindingByName = bindingsByRoot[ rootUuid ],
39476 bindings = this._bindings;
39478 if ( bindingByName === undefined ) {
39480 bindingByName = {};
39481 bindingsByRoot[ rootUuid ] = bindingByName;
39485 bindingByName[ trackName ] = binding;
39487 binding._cacheIndex = bindings.length;
39488 bindings.push( binding );
39492 _removeInactiveBinding: function ( binding ) {
39494 var bindings = this._bindings,
39495 propBinding = binding.binding,
39496 rootUuid = propBinding.rootNode.uuid,
39497 trackName = propBinding.path,
39498 bindingsByRoot = this._bindingsByRootAndName,
39499 bindingByName = bindingsByRoot[ rootUuid ],
39501 lastInactiveBinding = bindings[ bindings.length - 1 ],
39502 cacheIndex = binding._cacheIndex;
39504 lastInactiveBinding._cacheIndex = cacheIndex;
39505 bindings[ cacheIndex ] = lastInactiveBinding;
39508 delete bindingByName[ trackName ];
39510 remove_empty_map: {
39512 for ( var _ in bindingByName ) break remove_empty_map;
39514 delete bindingsByRoot[ rootUuid ];
39520 _lendBinding: function ( binding ) {
39522 var bindings = this._bindings,
39523 prevIndex = binding._cacheIndex,
39525 lastActiveIndex = this._nActiveBindings ++,
39527 firstInactiveBinding = bindings[ lastActiveIndex ];
39529 binding._cacheIndex = lastActiveIndex;
39530 bindings[ lastActiveIndex ] = binding;
39532 firstInactiveBinding._cacheIndex = prevIndex;
39533 bindings[ prevIndex ] = firstInactiveBinding;
39537 _takeBackBinding: function ( binding ) {
39539 var bindings = this._bindings,
39540 prevIndex = binding._cacheIndex,
39542 firstInactiveIndex = -- this._nActiveBindings,
39544 lastActiveBinding = bindings[ firstInactiveIndex ];
39546 binding._cacheIndex = firstInactiveIndex;
39547 bindings[ firstInactiveIndex ] = binding;
39549 lastActiveBinding._cacheIndex = prevIndex;
39550 bindings[ prevIndex ] = lastActiveBinding;
39555 // Memory management of Interpolants for weight and time scale
39557 _lendControlInterpolant: function () {
39559 var interpolants = this._controlInterpolants,
39560 lastActiveIndex = this._nActiveControlInterpolants ++,
39561 interpolant = interpolants[ lastActiveIndex ];
39563 if ( interpolant === undefined ) {
39565 interpolant = new LinearInterpolant(
39566 new Float32Array( 2 ), new Float32Array( 2 ),
39567 1, this._controlInterpolantsResultBuffer );
39569 interpolant.__cacheIndex = lastActiveIndex;
39570 interpolants[ lastActiveIndex ] = interpolant;
39574 return interpolant;
39578 _takeBackControlInterpolant: function ( interpolant ) {
39580 var interpolants = this._controlInterpolants,
39581 prevIndex = interpolant.__cacheIndex,
39583 firstInactiveIndex = -- this._nActiveControlInterpolants,
39585 lastActiveInterpolant = interpolants[ firstInactiveIndex ];
39587 interpolant.__cacheIndex = firstInactiveIndex;
39588 interpolants[ firstInactiveIndex ] = interpolant;
39590 lastActiveInterpolant.__cacheIndex = prevIndex;
39591 interpolants[ prevIndex ] = lastActiveInterpolant;
39595 _controlInterpolantsResultBuffer: new Float32Array( 1 ),
39597 // return an action for a clip optionally using a custom root target
39598 // object (this method allocates a lot of dynamic memory in case a
39599 // previously unknown clip/root combination is specified)
39600 clipAction: function ( clip, optionalRoot ) {
39602 var root = optionalRoot || this._root,
39603 rootUuid = root.uuid,
39605 clipObject = typeof clip === 'string' ?
39606 AnimationClip.findByName( root, clip ) : clip,
39608 clipUuid = clipObject !== null ? clipObject.uuid : clip,
39610 actionsForClip = this._actionsByClip[ clipUuid ],
39611 prototypeAction = null;
39613 if ( actionsForClip !== undefined ) {
39615 var existingAction =
39616 actionsForClip.actionByRoot[ rootUuid ];
39618 if ( existingAction !== undefined ) {
39620 return existingAction;
39624 // we know the clip, so we don't have to parse all
39625 // the bindings again but can just copy
39626 prototypeAction = actionsForClip.knownActions[ 0 ];
39628 // also, take the clip from the prototype action
39629 if ( clipObject === null )
39630 clipObject = prototypeAction._clip;
39634 // clip must be known when specified via string
39635 if ( clipObject === null ) return null;
39637 // allocate all resources required to run it
39638 var newAction = new AnimationAction( this, clipObject, optionalRoot );
39640 this._bindAction( newAction, prototypeAction );
39642 // and make the action known to the memory manager
39643 this._addInactiveAction( newAction, clipUuid, rootUuid );
39649 // get an existing action
39650 existingAction: function ( clip, optionalRoot ) {
39652 var root = optionalRoot || this._root,
39653 rootUuid = root.uuid,
39655 clipObject = typeof clip === 'string' ?
39656 AnimationClip.findByName( root, clip ) : clip,
39658 clipUuid = clipObject ? clipObject.uuid : clip,
39660 actionsForClip = this._actionsByClip[ clipUuid ];
39662 if ( actionsForClip !== undefined ) {
39664 return actionsForClip.actionByRoot[ rootUuid ] || null;
39672 // deactivates all previously scheduled actions
39673 stopAllAction: function () {
39675 var actions = this._actions,
39676 nActions = this._nActiveActions,
39677 bindings = this._bindings,
39678 nBindings = this._nActiveBindings;
39680 this._nActiveActions = 0;
39681 this._nActiveBindings = 0;
39683 for ( var i = 0; i !== nActions; ++ i ) {
39685 actions[ i ].reset();
39689 for ( var i = 0; i !== nBindings; ++ i ) {
39691 bindings[ i ].useCount = 0;
39699 // advance the time and update apply the animation
39700 update: function ( deltaTime ) {
39702 deltaTime *= this.timeScale;
39704 var actions = this._actions,
39705 nActions = this._nActiveActions,
39707 time = this.time += deltaTime,
39708 timeDirection = Math.sign( deltaTime ),
39710 accuIndex = this._accuIndex ^= 1;
39712 // run active actions
39714 for ( var i = 0; i !== nActions; ++ i ) {
39716 var action = actions[ i ];
39718 action._update( time, deltaTime, timeDirection, accuIndex );
39722 // update scene graph
39724 var bindings = this._bindings,
39725 nBindings = this._nActiveBindings;
39727 for ( var i = 0; i !== nBindings; ++ i ) {
39729 bindings[ i ].apply( accuIndex );
39737 // return this mixer's root target object
39738 getRoot: function () {
39744 // free all resources specific to a particular clip
39745 uncacheClip: function ( clip ) {
39747 var actions = this._actions,
39748 clipUuid = clip.uuid,
39749 actionsByClip = this._actionsByClip,
39750 actionsForClip = actionsByClip[ clipUuid ];
39752 if ( actionsForClip !== undefined ) {
39754 // note: just calling _removeInactiveAction would mess up the
39755 // iteration state and also require updating the state we can
39758 var actionsToRemove = actionsForClip.knownActions;
39760 for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
39762 var action = actionsToRemove[ i ];
39764 this._deactivateAction( action );
39766 var cacheIndex = action._cacheIndex,
39767 lastInactiveAction = actions[ actions.length - 1 ];
39769 action._cacheIndex = null;
39770 action._byClipCacheIndex = null;
39772 lastInactiveAction._cacheIndex = cacheIndex;
39773 actions[ cacheIndex ] = lastInactiveAction;
39776 this._removeInactiveBindingsForAction( action );
39780 delete actionsByClip[ clipUuid ];
39786 // free all resources specific to a particular root target object
39787 uncacheRoot: function ( root ) {
39789 var rootUuid = root.uuid,
39790 actionsByClip = this._actionsByClip;
39792 for ( var clipUuid in actionsByClip ) {
39794 var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
39795 action = actionByRoot[ rootUuid ];
39797 if ( action !== undefined ) {
39799 this._deactivateAction( action );
39800 this._removeInactiveAction( action );
39806 var bindingsByRoot = this._bindingsByRootAndName,
39807 bindingByName = bindingsByRoot[ rootUuid ];
39809 if ( bindingByName !== undefined ) {
39811 for ( var trackName in bindingByName ) {
39813 var binding = bindingByName[ trackName ];
39814 binding.restoreOriginalState();
39815 this._removeInactiveBinding( binding );
39823 // remove a targeted clip from the cache
39824 uncacheAction: function ( clip, optionalRoot ) {
39826 var action = this.existingAction( clip, optionalRoot );
39828 if ( action !== null ) {
39830 this._deactivateAction( action );
39831 this._removeInactiveAction( action );
39840 * @author mrdoob / http://mrdoob.com/
39843 function Uniform( value ) {
39845 if ( typeof value === 'string' ) {
39847 console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
39848 value = arguments[ 1 ];
39852 this.value = value;
39856 Uniform.prototype.clone = function () {
39858 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
39863 * @author benaadams / https://twitter.com/ben_a_adams
39866 function InstancedBufferGeometry() {
39868 BufferGeometry.call( this );
39870 this.type = 'InstancedBufferGeometry';
39871 this.maxInstancedCount = undefined;
39875 InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
39877 constructor: InstancedBufferGeometry,
39879 isInstancedBufferGeometry: true,
39881 addGroup: function ( start, count, materialIndex ) {
39883 this.groups.push( {
39887 materialIndex: materialIndex
39893 copy: function ( source ) {
39895 var index = source.index;
39897 if ( index !== null ) {
39899 this.setIndex( index.clone() );
39903 var attributes = source.attributes;
39905 for ( var name in attributes ) {
39907 var attribute = attributes[ name ];
39908 this.addAttribute( name, attribute.clone() );
39912 var groups = source.groups;
39914 for ( var i = 0, l = groups.length; i < l; i ++ ) {
39916 var group = groups[ i ];
39917 this.addGroup( group.start, group.count, group.materialIndex );
39928 * @author benaadams / https://twitter.com/ben_a_adams
39931 function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
39933 this.uuid = _Math.generateUUID();
39935 this.data = interleavedBuffer;
39936 this.itemSize = itemSize;
39937 this.offset = offset;
39939 this.normalized = normalized === true;
39943 Object.defineProperties( InterleavedBufferAttribute.prototype, {
39949 return this.data.count;
39959 return this.data.array;
39967 Object.assign( InterleavedBufferAttribute.prototype, {
39969 isInterleavedBufferAttribute: true,
39971 setX: function ( index, x ) {
39973 this.data.array[ index * this.data.stride + this.offset ] = x;
39979 setY: function ( index, y ) {
39981 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
39987 setZ: function ( index, z ) {
39989 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
39995 setW: function ( index, w ) {
39997 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
40003 getX: function ( index ) {
40005 return this.data.array[ index * this.data.stride + this.offset ];
40009 getY: function ( index ) {
40011 return this.data.array[ index * this.data.stride + this.offset + 1 ];
40015 getZ: function ( index ) {
40017 return this.data.array[ index * this.data.stride + this.offset + 2 ];
40021 getW: function ( index ) {
40023 return this.data.array[ index * this.data.stride + this.offset + 3 ];
40027 setXY: function ( index, x, y ) {
40029 index = index * this.data.stride + this.offset;
40031 this.data.array[ index + 0 ] = x;
40032 this.data.array[ index + 1 ] = y;
40038 setXYZ: function ( index, x, y, z ) {
40040 index = index * this.data.stride + this.offset;
40042 this.data.array[ index + 0 ] = x;
40043 this.data.array[ index + 1 ] = y;
40044 this.data.array[ index + 2 ] = z;
40050 setXYZW: function ( index, x, y, z, w ) {
40052 index = index * this.data.stride + this.offset;
40054 this.data.array[ index + 0 ] = x;
40055 this.data.array[ index + 1 ] = y;
40056 this.data.array[ index + 2 ] = z;
40057 this.data.array[ index + 3 ] = w;
40066 * @author benaadams / https://twitter.com/ben_a_adams
40069 function InterleavedBuffer( array, stride ) {
40071 this.uuid = _Math.generateUUID();
40073 this.array = array;
40074 this.stride = stride;
40075 this.count = array !== undefined ? array.length / stride : 0;
40077 this.dynamic = false;
40078 this.updateRange = { offset: 0, count: - 1 };
40080 this.onUploadCallback = function () {};
40086 Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
40088 set: function ( value ) {
40090 if ( value === true ) this.version ++;
40096 Object.assign( InterleavedBuffer.prototype, {
40098 isInterleavedBuffer: true,
40100 setArray: function ( array ) {
40102 if ( Array.isArray( array ) ) {
40104 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
40108 this.count = array !== undefined ? array.length / this.stride : 0;
40109 this.array = array;
40113 setDynamic: function ( value ) {
40115 this.dynamic = value;
40121 copy: function ( source ) {
40123 this.array = new source.array.constructor( source.array );
40124 this.count = source.count;
40125 this.stride = source.stride;
40126 this.dynamic = source.dynamic;
40132 copyAt: function ( index1, attribute, index2 ) {
40134 index1 *= this.stride;
40135 index2 *= attribute.stride;
40137 for ( var i = 0, l = this.stride; i < l; i ++ ) {
40139 this.array[ index1 + i ] = attribute.array[ index2 + i ];
40147 set: function ( value, offset ) {
40149 if ( offset === undefined ) offset = 0;
40151 this.array.set( value, offset );
40157 clone: function () {
40159 return new this.constructor().copy( this );
40163 onUpload: function ( callback ) {
40165 this.onUploadCallback = callback;
40174 * @author benaadams / https://twitter.com/ben_a_adams
40177 function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
40179 InterleavedBuffer.call( this, array, stride );
40181 this.meshPerAttribute = meshPerAttribute || 1;
40185 InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
40187 constructor: InstancedInterleavedBuffer,
40189 isInstancedInterleavedBuffer: true,
40191 copy: function ( source ) {
40193 InterleavedBuffer.prototype.copy.call( this, source );
40195 this.meshPerAttribute = source.meshPerAttribute;
40204 * @author benaadams / https://twitter.com/ben_a_adams
40207 function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {
40209 BufferAttribute.call( this, array, itemSize );
40211 this.meshPerAttribute = meshPerAttribute || 1;
40215 InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
40217 constructor: InstancedBufferAttribute,
40219 isInstancedBufferAttribute: true,
40221 copy: function ( source ) {
40223 BufferAttribute.prototype.copy.call( this, source );
40225 this.meshPerAttribute = source.meshPerAttribute;
40234 * @author mrdoob / http://mrdoob.com/
40235 * @author bhouston / http://clara.io/
40236 * @author stephomi / http://stephaneginier.com/
40239 function Raycaster( origin, direction, near, far ) {
40241 this.ray = new Ray( origin, direction );
40242 // direction is assumed to be normalized (for accurate distance calculations)
40244 this.near = near || 0;
40245 this.far = far || Infinity;
40251 Points: { threshold: 1 },
40255 Object.defineProperties( this.params, {
40258 console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
40259 return this.Points;
40266 function ascSort( a, b ) {
40268 return a.distance - b.distance;
40272 function intersectObject( object, raycaster, intersects, recursive ) {
40274 if ( object.visible === false ) return;
40276 object.raycast( raycaster, intersects );
40278 if ( recursive === true ) {
40280 var children = object.children;
40282 for ( var i = 0, l = children.length; i < l; i ++ ) {
40284 intersectObject( children[ i ], raycaster, intersects, true );
40292 Object.assign( Raycaster.prototype, {
40296 set: function ( origin, direction ) {
40298 // direction is assumed to be normalized (for accurate distance calculations)
40300 this.ray.set( origin, direction );
40304 setFromCamera: function ( coords, camera ) {
40306 if ( ( camera && camera.isPerspectiveCamera ) ) {
40308 this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
40309 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
40311 } else if ( ( camera && camera.isOrthographicCamera ) ) {
40313 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
40314 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
40318 console.error( 'THREE.Raycaster: Unsupported camera type.' );
40324 intersectObject: function ( object, recursive ) {
40326 var intersects = [];
40328 intersectObject( object, this, intersects, recursive );
40330 intersects.sort( ascSort );
40336 intersectObjects: function ( objects, recursive ) {
40338 var intersects = [];
40340 if ( Array.isArray( objects ) === false ) {
40342 console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
40347 for ( var i = 0, l = objects.length; i < l; i ++ ) {
40349 intersectObject( objects[ i ], this, intersects, recursive );
40353 intersects.sort( ascSort );
40362 * @author alteredq / http://alteredqualia.com/
40365 function Clock( autoStart ) {
40367 this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
40369 this.startTime = 0;
40371 this.elapsedTime = 0;
40373 this.running = false;
40377 Object.assign( Clock.prototype, {
40379 start: function () {
40381 this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
40383 this.oldTime = this.startTime;
40384 this.elapsedTime = 0;
40385 this.running = true;
40389 stop: function () {
40391 this.getElapsedTime();
40392 this.running = false;
40393 this.autoStart = false;
40397 getElapsedTime: function () {
40400 return this.elapsedTime;
40404 getDelta: function () {
40408 if ( this.autoStart && ! this.running ) {
40415 if ( this.running ) {
40417 var newTime = ( typeof performance === 'undefined' ? Date : performance ).now();
40419 diff = ( newTime - this.oldTime ) / 1000;
40420 this.oldTime = newTime;
40422 this.elapsedTime += diff;
40433 * @author bhouston / http://clara.io
40434 * @author WestLangley / http://github.com/WestLangley
40436 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
40438 * The poles (phi) are at the positive and negative y axis.
40439 * The equator starts at positive z.
40442 function Spherical( radius, phi, theta ) {
40444 this.radius = ( radius !== undefined ) ? radius : 1.0;
40445 this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole
40446 this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere
40452 Object.assign( Spherical.prototype, {
40454 set: function ( radius, phi, theta ) {
40456 this.radius = radius;
40458 this.theta = theta;
40464 clone: function () {
40466 return new this.constructor().copy( this );
40470 copy: function ( other ) {
40472 this.radius = other.radius;
40473 this.phi = other.phi;
40474 this.theta = other.theta;
40480 // restrict phi to be betwee EPS and PI-EPS
40481 makeSafe: function() {
40483 var EPS = 0.000001;
40484 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
40490 setFromVector3: function( vec3 ) {
40492 this.radius = vec3.length();
40494 if ( this.radius === 0 ) {
40501 this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis
40502 this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle
40513 * @author Mugen87 / https://github.com/Mugen87
40515 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
40519 function Cylindrical( radius, theta, y ) {
40521 this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
40522 this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
40523 this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
40529 Object.assign( Cylindrical.prototype, {
40531 set: function ( radius, theta, y ) {
40533 this.radius = radius;
40534 this.theta = theta;
40541 clone: function () {
40543 return new this.constructor().copy( this );
40547 copy: function ( other ) {
40549 this.radius = other.radius;
40550 this.theta = other.theta;
40557 setFromVector3: function( vec3 ) {
40559 this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );
40560 this.theta = Math.atan2( vec3.x, vec3.z );
40570 * @author alteredq / http://alteredqualia.com/
40573 function ImmediateRenderObject( material ) {
40575 Object3D.call( this );
40577 this.material = material;
40578 this.render = function ( renderCallback ) {};
40582 ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
40583 ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
40585 ImmediateRenderObject.prototype.isImmediateRenderObject = true;
40588 * @author mrdoob / http://mrdoob.com/
40589 * @author WestLangley / http://github.com/WestLangley
40592 function VertexNormalsHelper( object, size, hex, linewidth ) {
40594 this.object = object;
40596 this.size = ( size !== undefined ) ? size : 1;
40598 var color = ( hex !== undefined ) ? hex : 0xff0000;
40600 var width = ( linewidth !== undefined ) ? linewidth : 1;
40606 var objGeometry = this.object.geometry;
40608 if ( objGeometry && objGeometry.isGeometry ) {
40610 nNormals = objGeometry.faces.length * 3;
40612 } else if ( objGeometry && objGeometry.isBufferGeometry ) {
40614 nNormals = objGeometry.attributes.normal.count;
40620 var geometry = new BufferGeometry();
40622 var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
40624 geometry.addAttribute( 'position', positions );
40626 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
40630 this.matrixAutoUpdate = false;
40636 VertexNormalsHelper.prototype = Object.create( LineSegments.prototype );
40637 VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;
40639 VertexNormalsHelper.prototype.update = ( function () {
40641 var v1 = new Vector3();
40642 var v2 = new Vector3();
40643 var normalMatrix = new Matrix3();
40645 return function update() {
40647 var keys = [ 'a', 'b', 'c' ];
40649 this.object.updateMatrixWorld( true );
40651 normalMatrix.getNormalMatrix( this.object.matrixWorld );
40653 var matrixWorld = this.object.matrixWorld;
40655 var position = this.geometry.attributes.position;
40659 var objGeometry = this.object.geometry;
40661 if ( objGeometry && objGeometry.isGeometry ) {
40663 var vertices = objGeometry.vertices;
40665 var faces = objGeometry.faces;
40669 for ( var i = 0, l = faces.length; i < l; i ++ ) {
40671 var face = faces[ i ];
40673 for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
40675 var vertex = vertices[ face[ keys[ j ] ] ];
40677 var normal = face.vertexNormals[ j ];
40679 v1.copy( vertex ).applyMatrix4( matrixWorld );
40681 v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
40683 position.setXYZ( idx, v1.x, v1.y, v1.z );
40687 position.setXYZ( idx, v2.x, v2.y, v2.z );
40695 } else if ( objGeometry && objGeometry.isBufferGeometry ) {
40697 var objPos = objGeometry.attributes.position;
40699 var objNorm = objGeometry.attributes.normal;
40703 // for simplicity, ignore index and drawcalls, and render every normal
40705 for ( var j = 0, jl = objPos.count; j < jl; j ++ ) {
40707 v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );
40709 v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );
40711 v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
40713 position.setXYZ( idx, v1.x, v1.y, v1.z );
40717 position.setXYZ( idx, v2.x, v2.y, v2.z );
40725 position.needsUpdate = true;
40732 * @author alteredq / http://alteredqualia.com/
40733 * @author mrdoob / http://mrdoob.com/
40734 * @author WestLangley / http://github.com/WestLangley
40737 function SpotLightHelper( light, color ) {
40739 Object3D.call( this );
40741 this.light = light;
40742 this.light.updateMatrixWorld();
40744 this.matrix = light.matrixWorld;
40745 this.matrixAutoUpdate = false;
40747 this.color = color;
40749 var geometry = new BufferGeometry();
40754 0, 0, 0, - 1, 0, 1,
40759 for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
40761 var p1 = ( i / l ) * Math.PI * 2;
40762 var p2 = ( j / l ) * Math.PI * 2;
40765 Math.cos( p1 ), Math.sin( p1 ), 1,
40766 Math.cos( p2 ), Math.sin( p2 ), 1
40771 geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
40773 var material = new LineBasicMaterial( { fog: false } );
40775 this.cone = new LineSegments( geometry, material );
40776 this.add( this.cone );
40782 SpotLightHelper.prototype = Object.create( Object3D.prototype );
40783 SpotLightHelper.prototype.constructor = SpotLightHelper;
40785 SpotLightHelper.prototype.dispose = function () {
40787 this.cone.geometry.dispose();
40788 this.cone.material.dispose();
40792 SpotLightHelper.prototype.update = function () {
40794 var vector = new Vector3();
40795 var vector2 = new Vector3();
40797 return function update() {
40799 this.light.updateMatrixWorld();
40801 var coneLength = this.light.distance ? this.light.distance : 1000;
40802 var coneWidth = coneLength * Math.tan( this.light.angle );
40804 this.cone.scale.set( coneWidth, coneWidth, coneLength );
40806 vector.setFromMatrixPosition( this.light.matrixWorld );
40807 vector2.setFromMatrixPosition( this.light.target.matrixWorld );
40809 this.cone.lookAt( vector2.sub( vector ) );
40811 if ( this.color !== undefined ) {
40813 this.cone.material.color.set( this.color );
40817 this.cone.material.color.copy( this.light.color );
40826 * @author Sean Griffin / http://twitter.com/sgrif
40827 * @author Michael Guerrero / http://realitymeltdown.com
40828 * @author mrdoob / http://mrdoob.com/
40829 * @author ikerr / http://verold.com
40830 * @author Mugen87 / https://github.com/Mugen87
40833 function getBoneList( object ) {
40837 if ( object && object.isBone ) {
40839 boneList.push( object );
40843 for ( var i = 0; i < object.children.length; i ++ ) {
40845 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
40853 function SkeletonHelper( object ) {
40855 var bones = getBoneList( object );
40857 var geometry = new BufferGeometry();
40862 var color1 = new Color( 0, 0, 1 );
40863 var color2 = new Color( 0, 1, 0 );
40865 for ( var i = 0; i < bones.length; i ++ ) {
40867 var bone = bones[ i ];
40869 if ( bone.parent && bone.parent.isBone ) {
40871 vertices.push( 0, 0, 0 );
40872 vertices.push( 0, 0, 0 );
40873 colors.push( color1.r, color1.g, color1.b );
40874 colors.push( color2.r, color2.g, color2.b );
40880 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40881 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
40883 var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );
40885 LineSegments.call( this, geometry, material );
40887 this.root = object;
40888 this.bones = bones;
40890 this.matrix = object.matrixWorld;
40891 this.matrixAutoUpdate = false;
40893 this.onBeforeRender();
40897 SkeletonHelper.prototype = Object.create( LineSegments.prototype );
40898 SkeletonHelper.prototype.constructor = SkeletonHelper;
40900 SkeletonHelper.prototype.onBeforeRender = function () {
40902 var vector = new Vector3();
40904 var boneMatrix = new Matrix4();
40905 var matrixWorldInv = new Matrix4();
40907 return function onBeforeRender() {
40909 var bones = this.bones;
40911 var geometry = this.geometry;
40912 var position = geometry.getAttribute( 'position' );
40914 matrixWorldInv.getInverse( this.root.matrixWorld );
40916 for ( var i = 0, j = 0; i < bones.length; i ++ ) {
40918 var bone = bones[ i ];
40920 if ( bone.parent && bone.parent.isBone ) {
40922 boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
40923 vector.setFromMatrixPosition( boneMatrix );
40924 position.setXYZ( j, vector.x, vector.y, vector.z );
40926 boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
40927 vector.setFromMatrixPosition( boneMatrix );
40928 position.setXYZ( j + 1, vector.x, vector.y, vector.z );
40936 geometry.getAttribute( 'position' ).needsUpdate = true;
40943 * @author alteredq / http://alteredqualia.com/
40944 * @author mrdoob / http://mrdoob.com/
40947 function PointLightHelper( light, sphereSize, color ) {
40949 this.light = light;
40950 this.light.updateMatrixWorld();
40952 this.color = color;
40954 var geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
40955 var material = new MeshBasicMaterial( { wireframe: true, fog: false } );
40957 Mesh.call( this, geometry, material );
40959 this.matrix = this.light.matrixWorld;
40960 this.matrixAutoUpdate = false;
40966 var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
40967 var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
40969 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
40970 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
40972 var d = light.distance;
40976 this.lightDistance.visible = false;
40980 this.lightDistance.scale.set( d, d, d );
40984 this.add( this.lightDistance );
40989 PointLightHelper.prototype = Object.create( Mesh.prototype );
40990 PointLightHelper.prototype.constructor = PointLightHelper;
40992 PointLightHelper.prototype.dispose = function () {
40994 this.geometry.dispose();
40995 this.material.dispose();
40999 PointLightHelper.prototype.update = function () {
41001 if ( this.color !== undefined ) {
41003 this.material.color.set( this.color );
41007 this.material.color.copy( this.light.color );
41012 var d = this.light.distance;
41016 this.lightDistance.visible = false;
41020 this.lightDistance.visible = true;
41021 this.lightDistance.scale.set( d, d, d );
41029 * @author abelnation / http://github.com/abelnation
41030 * @author Mugen87 / http://github.com/Mugen87
41031 * @author WestLangley / http://github.com/WestLangley
41034 function RectAreaLightHelper( light, color ) {
41036 Object3D.call( this );
41038 this.light = light;
41039 this.light.updateMatrixWorld();
41041 this.matrix = light.matrixWorld;
41042 this.matrixAutoUpdate = false;
41044 this.color = color;
41046 var material = new LineBasicMaterial( { fog: false } );
41048 var geometry = new BufferGeometry();
41050 geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) );
41052 this.line = new Line( geometry, material );
41053 this.add( this.line );
41060 RectAreaLightHelper.prototype = Object.create( Object3D.prototype );
41061 RectAreaLightHelper.prototype.constructor = RectAreaLightHelper;
41063 RectAreaLightHelper.prototype.dispose = function () {
41065 this.children[ 0 ].geometry.dispose();
41066 this.children[ 0 ].material.dispose();
41070 RectAreaLightHelper.prototype.update = function () {
41072 // calculate new dimensions of the helper
41074 var hx = this.light.width * 0.5;
41075 var hy = this.light.height * 0.5;
41077 var position = this.line.geometry.attributes.position;
41078 var array = position.array;
41082 array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0;
41083 array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0;
41084 array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0;
41085 array[ 9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0;
41086 array[ 12 ] = hx; array[ 13 ] = - hy; array[ 14 ] = 0;
41088 position.needsUpdate = true;
41090 if ( this.color !== undefined ) {
41092 this.line.material.color.set( this.color );
41096 this.line.material.color.copy( this.light.color );
41103 * @author alteredq / http://alteredqualia.com/
41104 * @author mrdoob / http://mrdoob.com/
41105 * @author Mugen87 / https://github.com/Mugen87
41108 function HemisphereLightHelper( light, size, color ) {
41110 Object3D.call( this );
41112 this.light = light;
41113 this.light.updateMatrixWorld();
41115 this.matrix = light.matrixWorld;
41116 this.matrixAutoUpdate = false;
41118 this.color = color;
41120 var geometry = new OctahedronBufferGeometry( size );
41121 geometry.rotateY( Math.PI * 0.5 );
41123 this.material = new MeshBasicMaterial( { wireframe: true, fog: false } );
41124 if ( this.color === undefined ) this.material.vertexColors = VertexColors;
41126 var position = geometry.getAttribute( 'position' );
41127 var colors = new Float32Array( position.count * 3 );
41129 geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );
41131 this.add( new Mesh( geometry, this.material ) );
41137 HemisphereLightHelper.prototype = Object.create( Object3D.prototype );
41138 HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;
41140 HemisphereLightHelper.prototype.dispose = function () {
41142 this.children[ 0 ].geometry.dispose();
41143 this.children[ 0 ].material.dispose();
41147 HemisphereLightHelper.prototype.update = function () {
41149 var vector = new Vector3();
41151 var color1 = new Color();
41152 var color2 = new Color();
41154 return function update() {
41156 var mesh = this.children[ 0 ];
41158 if ( this.color !== undefined ) {
41160 this.material.color.set( this.color );
41164 var colors = mesh.geometry.getAttribute( 'color' );
41166 color1.copy( this.light.color );
41167 color2.copy( this.light.groundColor );
41169 for ( var i = 0, l = colors.count; i < l; i ++ ) {
41171 var color = ( i < ( l / 2 ) ) ? color1 : color2;
41173 colors.setXYZ( i, color.r, color.g, color.b );
41177 colors.needsUpdate = true;
41181 mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
41188 * @author mrdoob / http://mrdoob.com/
41191 function GridHelper( size, divisions, color1, color2 ) {
41194 divisions = divisions || 10;
41195 color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
41196 color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
41198 var center = divisions / 2;
41199 var step = size / divisions;
41200 var halfSize = size / 2;
41202 var vertices = [], colors = [];
41204 for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
41206 vertices.push( - halfSize, 0, k, halfSize, 0, k );
41207 vertices.push( k, 0, - halfSize, k, 0, halfSize );
41209 var color = i === center ? color1 : color2;
41211 color.toArray( colors, j ); j += 3;
41212 color.toArray( colors, j ); j += 3;
41213 color.toArray( colors, j ); j += 3;
41214 color.toArray( colors, j ); j += 3;
41218 var geometry = new BufferGeometry();
41219 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
41220 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
41222 var material = new LineBasicMaterial( { vertexColors: VertexColors } );
41224 LineSegments.call( this, geometry, material );
41228 GridHelper.prototype = Object.create( LineSegments.prototype );
41229 GridHelper.prototype.constructor = GridHelper;
41232 * @author mrdoob / http://mrdoob.com/
41233 * @author Mugen87 / http://github.com/Mugen87
41234 * @author Hectate / http://www.github.com/Hectate
41237 function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {
41239 radius = radius || 10;
41240 radials = radials || 16;
41241 circles = circles || 8;
41242 divisions = divisions || 64;
41243 color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
41244 color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
41250 var v, i, j, r, color;
41252 // create the radials
41254 for ( i = 0; i <= radials; i ++ ) {
41256 v = ( i / radials ) * ( Math.PI * 2 );
41258 x = Math.sin( v ) * radius;
41259 z = Math.cos( v ) * radius;
41261 vertices.push( 0, 0, 0 );
41262 vertices.push( x, 0, z );
41264 color = ( i & 1 ) ? color1 : color2;
41266 colors.push( color.r, color.g, color.b );
41267 colors.push( color.r, color.g, color.b );
41271 // create the circles
41273 for ( i = 0; i <= circles; i ++ ) {
41275 color = ( i & 1 ) ? color1 : color2;
41277 r = radius - ( radius / circles * i );
41279 for ( j = 0; j < divisions; j ++ ) {
41283 v = ( j / divisions ) * ( Math.PI * 2 );
41285 x = Math.sin( v ) * r;
41286 z = Math.cos( v ) * r;
41288 vertices.push( x, 0, z );
41289 colors.push( color.r, color.g, color.b );
41293 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
41295 x = Math.sin( v ) * r;
41296 z = Math.cos( v ) * r;
41298 vertices.push( x, 0, z );
41299 colors.push( color.r, color.g, color.b );
41305 var geometry = new BufferGeometry();
41306 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
41307 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
41309 var material = new LineBasicMaterial( { vertexColors: VertexColors } );
41311 LineSegments.call( this, geometry, material );
41315 PolarGridHelper.prototype = Object.create( LineSegments.prototype );
41316 PolarGridHelper.prototype.constructor = PolarGridHelper;
41319 * @author mrdoob / http://mrdoob.com/
41320 * @author WestLangley / http://github.com/WestLangley
41323 function FaceNormalsHelper( object, size, hex, linewidth ) {
41325 // FaceNormalsHelper only supports THREE.Geometry
41327 this.object = object;
41329 this.size = ( size !== undefined ) ? size : 1;
41331 var color = ( hex !== undefined ) ? hex : 0xffff00;
41333 var width = ( linewidth !== undefined ) ? linewidth : 1;
41339 var objGeometry = this.object.geometry;
41341 if ( objGeometry && objGeometry.isGeometry ) {
41343 nNormals = objGeometry.faces.length;
41347 console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );
41353 var geometry = new BufferGeometry();
41355 var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
41357 geometry.addAttribute( 'position', positions );
41359 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
41363 this.matrixAutoUpdate = false;
41368 FaceNormalsHelper.prototype = Object.create( LineSegments.prototype );
41369 FaceNormalsHelper.prototype.constructor = FaceNormalsHelper;
41371 FaceNormalsHelper.prototype.update = ( function () {
41373 var v1 = new Vector3();
41374 var v2 = new Vector3();
41375 var normalMatrix = new Matrix3();
41377 return function update() {
41379 this.object.updateMatrixWorld( true );
41381 normalMatrix.getNormalMatrix( this.object.matrixWorld );
41383 var matrixWorld = this.object.matrixWorld;
41385 var position = this.geometry.attributes.position;
41389 var objGeometry = this.object.geometry;
41391 var vertices = objGeometry.vertices;
41393 var faces = objGeometry.faces;
41397 for ( var i = 0, l = faces.length; i < l; i ++ ) {
41399 var face = faces[ i ];
41401 var normal = face.normal;
41403 v1.copy( vertices[ face.a ] )
41404 .add( vertices[ face.b ] )
41405 .add( vertices[ face.c ] )
41407 .applyMatrix4( matrixWorld );
41409 v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
41411 position.setXYZ( idx, v1.x, v1.y, v1.z );
41415 position.setXYZ( idx, v2.x, v2.y, v2.z );
41421 position.needsUpdate = true;
41428 * @author alteredq / http://alteredqualia.com/
41429 * @author mrdoob / http://mrdoob.com/
41430 * @author WestLangley / http://github.com/WestLangley
41433 function DirectionalLightHelper( light, size, color ) {
41435 Object3D.call( this );
41437 this.light = light;
41438 this.light.updateMatrixWorld();
41440 this.matrix = light.matrixWorld;
41441 this.matrixAutoUpdate = false;
41443 this.color = color;
41445 if ( size === undefined ) size = 1;
41447 var geometry = new BufferGeometry();
41448 geometry.addAttribute( 'position', new Float32BufferAttribute( [
41456 var material = new LineBasicMaterial( { fog: false } );
41458 this.lightPlane = new Line( geometry, material );
41459 this.add( this.lightPlane );
41461 geometry = new BufferGeometry();
41462 geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
41464 this.targetLine = new Line( geometry, material );
41465 this.add( this.targetLine );
41471 DirectionalLightHelper.prototype = Object.create( Object3D.prototype );
41472 DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;
41474 DirectionalLightHelper.prototype.dispose = function () {
41476 this.lightPlane.geometry.dispose();
41477 this.lightPlane.material.dispose();
41478 this.targetLine.geometry.dispose();
41479 this.targetLine.material.dispose();
41483 DirectionalLightHelper.prototype.update = function () {
41485 var v1 = new Vector3();
41486 var v2 = new Vector3();
41487 var v3 = new Vector3();
41489 return function update() {
41491 v1.setFromMatrixPosition( this.light.matrixWorld );
41492 v2.setFromMatrixPosition( this.light.target.matrixWorld );
41493 v3.subVectors( v2, v1 );
41495 this.lightPlane.lookAt( v3 );
41497 if ( this.color !== undefined ) {
41499 this.lightPlane.material.color.set( this.color );
41500 this.targetLine.material.color.set( this.color );
41504 this.lightPlane.material.color.copy( this.light.color );
41505 this.targetLine.material.color.copy( this.light.color );
41509 this.targetLine.lookAt( v3 );
41510 this.targetLine.scale.z = v3.length();
41517 * @author alteredq / http://alteredqualia.com/
41518 * @author Mugen87 / https://github.com/Mugen87
41520 * - shows frustum, line of sight and up of the camera
41521 * - suitable for fast updates
41522 * - based on frustum visualization in lightgl.js shadowmap example
41523 * http://evanw.github.com/lightgl.js/tests/shadowmap.html
41526 function CameraHelper( camera ) {
41528 var geometry = new BufferGeometry();
41529 var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );
41538 var colorFrustum = new Color( 0xffaa00 );
41539 var colorCone = new Color( 0xff0000 );
41540 var colorUp = new Color( 0x00aaff );
41541 var colorTarget = new Color( 0xffffff );
41542 var colorCross = new Color( 0x333333 );
41546 addLine( "n1", "n2", colorFrustum );
41547 addLine( "n2", "n4", colorFrustum );
41548 addLine( "n4", "n3", colorFrustum );
41549 addLine( "n3", "n1", colorFrustum );
41553 addLine( "f1", "f2", colorFrustum );
41554 addLine( "f2", "f4", colorFrustum );
41555 addLine( "f4", "f3", colorFrustum );
41556 addLine( "f3", "f1", colorFrustum );
41560 addLine( "n1", "f1", colorFrustum );
41561 addLine( "n2", "f2", colorFrustum );
41562 addLine( "n3", "f3", colorFrustum );
41563 addLine( "n4", "f4", colorFrustum );
41567 addLine( "p", "n1", colorCone );
41568 addLine( "p", "n2", colorCone );
41569 addLine( "p", "n3", colorCone );
41570 addLine( "p", "n4", colorCone );
41574 addLine( "u1", "u2", colorUp );
41575 addLine( "u2", "u3", colorUp );
41576 addLine( "u3", "u1", colorUp );
41580 addLine( "c", "t", colorTarget );
41581 addLine( "p", "c", colorCross );
41585 addLine( "cn1", "cn2", colorCross );
41586 addLine( "cn3", "cn4", colorCross );
41588 addLine( "cf1", "cf2", colorCross );
41589 addLine( "cf3", "cf4", colorCross );
41591 function addLine( a, b, color ) {
41593 addPoint( a, color );
41594 addPoint( b, color );
41598 function addPoint( id, color ) {
41600 vertices.push( 0, 0, 0 );
41601 colors.push( color.r, color.g, color.b );
41603 if ( pointMap[ id ] === undefined ) {
41605 pointMap[ id ] = [];
41609 pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
41613 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
41614 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
41616 LineSegments.call( this, geometry, material );
41618 this.camera = camera;
41619 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
41621 this.matrix = camera.matrixWorld;
41622 this.matrixAutoUpdate = false;
41624 this.pointMap = pointMap;
41630 CameraHelper.prototype = Object.create( LineSegments.prototype );
41631 CameraHelper.prototype.constructor = CameraHelper;
41633 CameraHelper.prototype.update = function () {
41635 var geometry, pointMap;
41637 var vector = new Vector3();
41638 var camera = new Camera();
41640 function setPoint( point, x, y, z ) {
41642 vector.set( x, y, z ).unproject( camera );
41644 var points = pointMap[ point ];
41646 if ( points !== undefined ) {
41648 var position = geometry.getAttribute( 'position' );
41650 for ( var i = 0, l = points.length; i < l; i ++ ) {
41652 position.setXYZ( points[ i ], vector.x, vector.y, vector.z );
41660 return function update() {
41662 geometry = this.geometry;
41663 pointMap = this.pointMap;
41667 // we need just camera projection matrix
41668 // world matrix must be identity
41670 camera.projectionMatrix.copy( this.camera.projectionMatrix );
41674 setPoint( "c", 0, 0, - 1 );
41675 setPoint( "t", 0, 0, 1 );
41679 setPoint( "n1", - w, - h, - 1 );
41680 setPoint( "n2", w, - h, - 1 );
41681 setPoint( "n3", - w, h, - 1 );
41682 setPoint( "n4", w, h, - 1 );
41686 setPoint( "f1", - w, - h, 1 );
41687 setPoint( "f2", w, - h, 1 );
41688 setPoint( "f3", - w, h, 1 );
41689 setPoint( "f4", w, h, 1 );
41693 setPoint( "u1", w * 0.7, h * 1.1, - 1 );
41694 setPoint( "u2", - w * 0.7, h * 1.1, - 1 );
41695 setPoint( "u3", 0, h * 2, - 1 );
41699 setPoint( "cf1", - w, 0, 1 );
41700 setPoint( "cf2", w, 0, 1 );
41701 setPoint( "cf3", 0, - h, 1 );
41702 setPoint( "cf4", 0, h, 1 );
41704 setPoint( "cn1", - w, 0, - 1 );
41705 setPoint( "cn2", w, 0, - 1 );
41706 setPoint( "cn3", 0, - h, - 1 );
41707 setPoint( "cn4", 0, h, - 1 );
41709 geometry.getAttribute( 'position' ).needsUpdate = true;
41716 * @author mrdoob / http://mrdoob.com/
41717 * @author Mugen87 / http://github.com/Mugen87
41720 function BoxHelper( object, color ) {
41722 this.object = object;
41724 if ( color === undefined ) color = 0xffff00;
41726 var 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 ] );
41727 var positions = new Float32Array( 8 * 3 );
41729 var geometry = new BufferGeometry();
41730 geometry.setIndex( new BufferAttribute( indices, 1 ) );
41731 geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );
41733 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
41735 this.matrixAutoUpdate = false;
41741 BoxHelper.prototype = Object.create( LineSegments.prototype );
41742 BoxHelper.prototype.constructor = BoxHelper;
41744 BoxHelper.prototype.update = ( function () {
41746 var box = new Box3();
41748 return function update( object ) {
41750 if ( object !== undefined ) {
41752 console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
41756 if ( this.object !== undefined ) {
41758 box.setFromObject( this.object );
41762 if ( box.isEmpty() ) return;
41773 0: max.x, max.y, max.z
41774 1: min.x, max.y, max.z
41775 2: min.x, min.y, max.z
41776 3: max.x, min.y, max.z
41777 4: max.x, max.y, min.z
41778 5: min.x, max.y, min.z
41779 6: min.x, min.y, min.z
41780 7: max.x, min.y, min.z
41783 var position = this.geometry.attributes.position;
41784 var array = position.array;
41786 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
41787 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
41788 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
41789 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
41790 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
41791 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
41792 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
41793 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
41795 position.needsUpdate = true;
41797 this.geometry.computeBoundingSphere();
41803 BoxHelper.prototype.setFromObject = function ( object ) {
41805 this.object = object;
41813 * @author WestLangley / http://github.com/WestLangley
41816 function Box3Helper( box, hex ) {
41818 this.type = 'Box3Helper';
41822 var color = ( hex !== undefined ) ? hex : 0xffff00;
41824 var 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 ] );
41826 var 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 ];
41828 var geometry = new BufferGeometry();
41830 geometry.setIndex( new BufferAttribute( indices, 1 ) );
41832 geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
41834 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
41836 this.geometry.computeBoundingSphere();
41838 this.onBeforeRender();
41842 Box3Helper.prototype = Object.create( LineSegments.prototype );
41843 Box3Helper.prototype.constructor = Box3Helper;
41845 Box3Helper.prototype.onBeforeRender = function () {
41847 var box = this.box;
41849 if ( box.isEmpty() ) return;
41851 box.getCenter( this.position );
41853 box.getSize( this.scale );
41855 this.scale.multiplyScalar( 0.5 );
41860 * @author WestLangley / http://github.com/WestLangley
41863 function PlaneHelper( plane, size, hex ) {
41865 this.type = 'PlaneHelper';
41867 this.plane = plane;
41869 this.size = ( size === undefined ) ? 1 : size;
41871 var color = ( hex !== undefined ) ? hex : 0xffff00;
41873 var 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 ];
41875 var geometry = new BufferGeometry();
41876 geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
41877 geometry.computeBoundingSphere();
41879 Line.call( this, geometry, new LineBasicMaterial( { color: color } ) );
41883 var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
41885 var geometry2 = new BufferGeometry();
41886 geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
41887 geometry2.computeBoundingSphere();
41889 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) );
41893 this.onBeforeRender();
41897 PlaneHelper.prototype = Object.create( Line.prototype );
41898 PlaneHelper.prototype.constructor = PlaneHelper;
41900 PlaneHelper.prototype.onBeforeRender = function () {
41902 var scale = - this.plane.constant;
41904 if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
41906 this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
41908 this.lookAt( this.plane.normal );
41910 this.updateMatrixWorld();
41915 * @author WestLangley / http://github.com/WestLangley
41916 * @author zz85 / http://github.com/zz85
41917 * @author bhouston / http://clara.io
41919 * Creates an arrow for visualizing directions
41925 * color - color in hex value
41926 * headLength - Number
41927 * headWidth - Number
41933 function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {
41935 // dir is assumed to be normalized
41937 Object3D.call( this );
41939 if ( color === undefined ) color = 0xffff00;
41940 if ( length === undefined ) length = 1;
41941 if ( headLength === undefined ) headLength = 0.2 * length;
41942 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
41944 if ( lineGeometry === undefined ) {
41946 lineGeometry = new BufferGeometry();
41947 lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
41949 coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
41950 coneGeometry.translate( 0, - 0.5, 0 );
41954 this.position.copy( origin );
41956 this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );
41957 this.line.matrixAutoUpdate = false;
41958 this.add( this.line );
41960 this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );
41961 this.cone.matrixAutoUpdate = false;
41962 this.add( this.cone );
41964 this.setDirection( dir );
41965 this.setLength( length, headLength, headWidth );
41969 ArrowHelper.prototype = Object.create( Object3D.prototype );
41970 ArrowHelper.prototype.constructor = ArrowHelper;
41972 ArrowHelper.prototype.setDirection = ( function () {
41974 var axis = new Vector3();
41977 return function setDirection( dir ) {
41979 // dir is assumed to be normalized
41981 if ( dir.y > 0.99999 ) {
41983 this.quaternion.set( 0, 0, 0, 1 );
41985 } else if ( dir.y < - 0.99999 ) {
41987 this.quaternion.set( 1, 0, 0, 0 );
41991 axis.set( dir.z, 0, - dir.x ).normalize();
41993 radians = Math.acos( dir.y );
41995 this.quaternion.setFromAxisAngle( axis, radians );
42003 ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {
42005 if ( headLength === undefined ) headLength = 0.2 * length;
42006 if ( headWidth === undefined ) headWidth = 0.2 * headLength;
42008 this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 );
42009 this.line.updateMatrix();
42011 this.cone.scale.set( headWidth, headLength, headWidth );
42012 this.cone.position.y = length;
42013 this.cone.updateMatrix();
42017 ArrowHelper.prototype.setColor = function ( color ) {
42019 this.line.material.color.copy( color );
42020 this.cone.material.color.copy( color );
42025 * @author sroucheray / http://sroucheray.org/
42026 * @author mrdoob / http://mrdoob.com/
42029 function AxisHelper( size ) {
42034 0, 0, 0, size, 0, 0,
42035 0, 0, 0, 0, size, 0,
42036 0, 0, 0, 0, 0, size
42040 1, 0, 0, 1, 0.6, 0,
42041 0, 1, 0, 0.6, 1, 0,
42045 var geometry = new BufferGeometry();
42046 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
42047 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
42049 var material = new LineBasicMaterial( { vertexColors: VertexColors } );
42051 LineSegments.call( this, geometry, material );
42055 AxisHelper.prototype = Object.create( LineSegments.prototype );
42056 AxisHelper.prototype.constructor = AxisHelper;
42059 * @author zz85 https://github.com/zz85
42061 * Centripetal CatmullRom Curve - which is useful for avoiding
42062 * cusps and self-intersections in non-uniform catmull rom curves.
42063 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
42065 * curve.type accepts centripetal(default), chordal and catmullrom
42066 * curve.tension is used for catmullrom which defaults to 0.5
42071 Based on an optimized c++ solution in
42072 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
42073 - http://ideone.com/NoEbVM
42075 This CubicPoly class could be used for reusing some variables and calculations,
42076 but for three.js curve use, it could be possible inlined and flatten into a single function call
42077 which can be placed in CurveUtils.
42080 function CubicPoly() {
42082 var c0 = 0, c1 = 0, c2 = 0, c3 = 0;
42085 * Compute coefficients for a cubic polynomial
42086 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
42088 * p(0) = x0, p(1) = x1
42090 * p'(0) = t0, p'(1) = t1.
42092 function init( x0, x1, t0, t1 ) {
42096 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
42097 c3 = 2 * x0 - 2 * x1 + t0 + t1;
42103 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
42105 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
42109 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
42111 // compute tangents when parameterized in [t1,t2]
42112 var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
42113 var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
42115 // rescale tangents for parametrization in [0,1]
42119 init( x1, x2, t1, t2 );
42123 calc: function ( t ) {
42127 return c0 + c1 * t + c2 * t2 + c3 * t3;
42137 var tmp = new Vector3();
42138 var px = new CubicPoly();
42139 var py = new CubicPoly();
42140 var pz = new CubicPoly();
42142 function CatmullRomCurve3( points ) {
42144 Curve.call( this );
42146 if ( points.length < 2 ) console.warn( 'THREE.CatmullRomCurve3: Points array needs at least two entries.' );
42148 this.points = points || [];
42149 this.closed = false;
42153 CatmullRomCurve3.prototype = Object.create( Curve.prototype );
42154 CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
42156 CatmullRomCurve3.prototype.getPoint = function ( t ) {
42158 var points = this.points;
42159 var l = points.length;
42161 var point = ( l - ( this.closed ? 0 : 1 ) ) * t;
42162 var intPoint = Math.floor( point );
42163 var weight = point - intPoint;
42165 if ( this.closed ) {
42167 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
42169 } else if ( weight === 0 && intPoint === l - 1 ) {
42176 var p0, p1, p2, p3; // 4 points
42178 if ( this.closed || intPoint > 0 ) {
42180 p0 = points[ ( intPoint - 1 ) % l ];
42184 // extrapolate first point
42185 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
42190 p1 = points[ intPoint % l ];
42191 p2 = points[ ( intPoint + 1 ) % l ];
42193 if ( this.closed || intPoint + 2 < l ) {
42195 p3 = points[ ( intPoint + 2 ) % l ];
42199 // extrapolate last point
42200 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
42205 if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {
42207 // init Centripetal / Chordal Catmull-Rom
42208 var pow = this.type === 'chordal' ? 0.5 : 0.25;
42209 var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
42210 var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
42211 var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
42213 // safety check for repeated points
42214 if ( dt1 < 1e-4 ) dt1 = 1.0;
42215 if ( dt0 < 1e-4 ) dt0 = dt1;
42216 if ( dt2 < 1e-4 ) dt2 = dt1;
42218 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
42219 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
42220 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
42222 } else if ( this.type === 'catmullrom' ) {
42224 var tension = this.tension !== undefined ? this.tension : 0.5;
42225 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );
42226 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );
42227 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );
42231 return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) );
42235 function CubicBezierCurve3( v0, v1, v2, v3 ) {
42237 Curve.call( this );
42246 CubicBezierCurve3.prototype = Object.create( Curve.prototype );
42247 CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
42249 CubicBezierCurve3.prototype.getPoint = function ( t ) {
42251 var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
42253 return new Vector3(
42254 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
42255 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
42256 CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
42261 function QuadraticBezierCurve3( v0, v1, v2 ) {
42263 Curve.call( this );
42271 QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
42272 QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
42274 QuadraticBezierCurve3.prototype.getPoint = function ( t ) {
42276 var v0 = this.v0, v1 = this.v1, v2 = this.v2;
42278 return new Vector3(
42279 QuadraticBezier( t, v0.x, v1.x, v2.x ),
42280 QuadraticBezier( t, v0.y, v1.y, v2.y ),
42281 QuadraticBezier( t, v0.z, v1.z, v2.z )
42286 function LineCurve3( v1, v2 ) {
42288 Curve.call( this );
42295 LineCurve3.prototype = Object.create( Curve.prototype );
42296 LineCurve3.prototype.constructor = LineCurve3;
42298 LineCurve3.prototype.getPoint = function ( t ) {
42302 return this.v2.clone();
42306 var vector = new Vector3();
42308 vector.subVectors( this.v2, this.v1 ); // diff
42309 vector.multiplyScalar( t );
42310 vector.add( this.v1 );
42316 function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
42318 EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
42322 ArcCurve.prototype = Object.create( EllipseCurve.prototype );
42323 ArcCurve.prototype.constructor = ArcCurve;
42326 * @author alteredq / http://alteredqualia.com/
42331 createMultiMaterialObject: function ( geometry, materials ) {
42333 var group = new Group();
42335 for ( var i = 0, l = materials.length; i < l; i ++ ) {
42337 group.add( new Mesh( geometry, materials[ i ] ) );
42345 detach: function ( child, parent, scene ) {
42347 child.applyMatrix( parent.matrixWorld );
42348 parent.remove( child );
42349 scene.add( child );
42353 attach: function ( child, scene, parent ) {
42355 child.applyMatrix( new Matrix4().getInverse( parent.matrixWorld ) );
42357 scene.remove( child );
42358 parent.add( child );
42365 * @author mrdoob / http://mrdoob.com/
42368 function Face4( a, b, c, d, normal, color, materialIndex ) {
42370 console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
42371 return new Face3( a, b, c, normal, color, materialIndex );
42377 var LinePieces = 1;
42379 function MeshFaceMaterial( materials ) {
42381 console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );
42386 function MultiMaterial( materials ) {
42388 if ( materials === undefined ) materials = [];
42390 console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );
42391 materials.isMultiMaterial = true;
42392 materials.materials = materials;
42393 materials.clone = function () {
42395 return materials.slice();
42402 function PointCloud( geometry, material ) {
42404 console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
42405 return new Points( geometry, material );
42409 function Particle( material ) {
42411 console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
42412 return new Sprite( material );
42416 function ParticleSystem( geometry, material ) {
42418 console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
42419 return new Points( geometry, material );
42423 function PointCloudMaterial( parameters ) {
42425 console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
42426 return new PointsMaterial( parameters );
42430 function ParticleBasicMaterial( parameters ) {
42432 console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
42433 return new PointsMaterial( parameters );
42437 function ParticleSystemMaterial( parameters ) {
42439 console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
42440 return new PointsMaterial( parameters );
42444 function Vertex( x, y, z ) {
42446 console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
42447 return new Vector3( x, y, z );
42453 function DynamicBufferAttribute( array, itemSize ) {
42455 console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' );
42456 return new BufferAttribute( array, itemSize ).setDynamic( true );
42460 function Int8Attribute( array, itemSize ) {
42462 console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
42463 return new Int8BufferAttribute( array, itemSize );
42467 function Uint8Attribute( array, itemSize ) {
42469 console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
42470 return new Uint8BufferAttribute( array, itemSize );
42474 function Uint8ClampedAttribute( array, itemSize ) {
42476 console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
42477 return new Uint8ClampedBufferAttribute( array, itemSize );
42481 function Int16Attribute( array, itemSize ) {
42483 console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
42484 return new Int16BufferAttribute( array, itemSize );
42488 function Uint16Attribute( array, itemSize ) {
42490 console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
42491 return new Uint16BufferAttribute( array, itemSize );
42495 function Int32Attribute( array, itemSize ) {
42497 console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
42498 return new Int32BufferAttribute( array, itemSize );
42502 function Uint32Attribute( array, itemSize ) {
42504 console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
42505 return new Uint32BufferAttribute( array, itemSize );
42509 function Float32Attribute( array, itemSize ) {
42511 console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
42512 return new Float32BufferAttribute( array, itemSize );
42516 function Float64Attribute( array, itemSize ) {
42518 console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
42519 return new Float64BufferAttribute( array, itemSize );
42525 Curve.create = function ( construct, getPoint ) {
42527 console.log( 'THREE.Curve.create() has been deprecated' );
42529 construct.prototype = Object.create( Curve.prototype );
42530 construct.prototype.constructor = construct;
42531 construct.prototype.getPoint = getPoint;
42539 function ClosedSplineCurve3( points ) {
42541 console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
42543 CatmullRomCurve3.call( this, points );
42544 this.type = 'catmullrom';
42545 this.closed = true;
42549 ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
42553 function SplineCurve3( points ) {
42555 console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
42557 CatmullRomCurve3.call( this, points );
42558 this.type = 'catmullrom';
42562 SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
42566 function Spline( points ) {
42568 console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
42570 CatmullRomCurve3.call( this, points );
42571 this.type = 'catmullrom';
42575 Spline.prototype = Object.create( CatmullRomCurve3.prototype );
42577 Object.assign( Spline.prototype, {
42579 initFromArray: function ( a ) {
42581 console.error( 'THREE.Spline: .initFromArray() has been removed.' );
42584 getControlPointsArray: function ( optionalTarget ) {
42586 console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
42589 reparametrizeByArcLength: function ( samplingCoef ) {
42591 console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
42598 function BoundingBoxHelper( object, color ) {
42600 console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
42601 return new BoxHelper( object, color );
42605 function EdgesHelper( object, hex ) {
42607 console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
42608 return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
42612 GridHelper.prototype.setColors = function () {
42614 console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
42618 SkeletonHelper.prototype.update = function () {
42620 console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
42624 function WireframeHelper( object, hex ) {
42626 console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
42627 return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
42633 function XHRLoader( manager ) {
42635 console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
42636 return new FileLoader( manager );
42640 function BinaryTextureLoader( manager ) {
42642 console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
42643 return new DataTextureLoader( manager );
42649 Object.assign( Box2.prototype, {
42651 center: function ( optionalTarget ) {
42653 console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
42654 return this.getCenter( optionalTarget );
42657 empty: function () {
42659 console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
42660 return this.isEmpty();
42663 isIntersectionBox: function ( box ) {
42665 console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
42666 return this.intersectsBox( box );
42669 size: function ( optionalTarget ) {
42671 console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
42672 return this.getSize( optionalTarget );
42677 Object.assign( Box3.prototype, {
42679 center: function ( optionalTarget ) {
42681 console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
42682 return this.getCenter( optionalTarget );
42685 empty: function () {
42687 console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
42688 return this.isEmpty();
42691 isIntersectionBox: function ( box ) {
42693 console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
42694 return this.intersectsBox( box );
42697 isIntersectionSphere: function ( sphere ) {
42699 console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
42700 return this.intersectsSphere( sphere );
42703 size: function ( optionalTarget ) {
42705 console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
42706 return this.getSize( optionalTarget );
42711 Line3.prototype.center = function ( optionalTarget ) {
42713 console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
42714 return this.getCenter( optionalTarget );
42718 _Math.random16 = function () {
42720 console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );
42721 return Math.random();
42725 Object.assign( Matrix3.prototype, {
42727 flattenToArrayOffset: function ( array, offset ) {
42729 console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
42730 return this.toArray( array, offset );
42733 multiplyVector3: function ( vector ) {
42735 console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
42736 return vector.applyMatrix3( this );
42739 multiplyVector3Array: function ( a ) {
42741 console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
42744 applyToBuffer: function( buffer, offset, length ) {
42746 console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
42747 return this.applyToBufferAttribute( buffer );
42750 applyToVector3Array: function( array, offset, length ) {
42752 console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
42758 Object.assign( Matrix4.prototype, {
42760 extractPosition: function ( m ) {
42762 console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
42763 return this.copyPosition( m );
42766 flattenToArrayOffset: function ( array, offset ) {
42768 console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
42769 return this.toArray( array, offset );
42772 getPosition: function () {
42776 return function getPosition() {
42778 if ( v1 === undefined ) v1 = new Vector3();
42779 console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
42780 return v1.setFromMatrixColumn( this, 3 );
42785 setRotationFromQuaternion: function ( q ) {
42787 console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
42788 return this.makeRotationFromQuaternion( q );
42791 multiplyToArray: function () {
42793 console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
42796 multiplyVector3: function ( vector ) {
42798 console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
42799 return vector.applyMatrix4( this );
42802 multiplyVector4: function ( vector ) {
42804 console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
42805 return vector.applyMatrix4( this );
42808 multiplyVector3Array: function ( a ) {
42810 console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
42813 rotateAxis: function ( v ) {
42815 console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
42816 v.transformDirection( this );
42819 crossVector: function ( vector ) {
42821 console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
42822 return vector.applyMatrix4( this );
42825 translate: function () {
42827 console.error( 'THREE.Matrix4: .translate() has been removed.' );
42830 rotateX: function () {
42832 console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
42835 rotateY: function () {
42837 console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
42840 rotateZ: function () {
42842 console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
42845 rotateByAxis: function () {
42847 console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
42850 applyToBuffer: function( buffer, offset, length ) {
42852 console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
42853 return this.applyToBufferAttribute( buffer );
42856 applyToVector3Array: function( array, offset, length ) {
42858 console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
42861 makeFrustum: function( left, right, bottom, top, near, far ) {
42863 console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
42864 return this.makePerspective( left, right, top, bottom, near, far );
42870 Plane.prototype.isIntersectionLine = function ( line ) {
42872 console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
42873 return this.intersectsLine( line );
42877 Quaternion.prototype.multiplyVector3 = function ( vector ) {
42879 console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
42880 return vector.applyQuaternion( this );
42884 Object.assign( Ray.prototype, {
42886 isIntersectionBox: function ( box ) {
42888 console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
42889 return this.intersectsBox( box );
42892 isIntersectionPlane: function ( plane ) {
42894 console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
42895 return this.intersectsPlane( plane );
42898 isIntersectionSphere: function ( sphere ) {
42900 console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
42901 return this.intersectsSphere( sphere );
42907 Object.assign( Shape.prototype, {
42909 extrude: function ( options ) {
42911 console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
42912 return new ExtrudeGeometry( this, options );
42915 makeGeometry: function ( options ) {
42917 console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
42918 return new ShapeGeometry( this, options );
42924 Object.assign( Vector2.prototype, {
42926 fromAttribute: function ( attribute, index, offset ) {
42928 console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
42929 return this.fromBufferAttribute( attribute, index, offset );
42935 Object.assign( Vector3.prototype, {
42937 setEulerFromRotationMatrix: function () {
42939 console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
42942 setEulerFromQuaternion: function () {
42944 console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
42947 getPositionFromMatrix: function ( m ) {
42949 console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
42950 return this.setFromMatrixPosition( m );
42953 getScaleFromMatrix: function ( m ) {
42955 console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
42956 return this.setFromMatrixScale( m );
42959 getColumnFromMatrix: function ( index, matrix ) {
42961 console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
42962 return this.setFromMatrixColumn( matrix, index );
42965 applyProjection: function ( m ) {
42967 console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
42968 return this.applyMatrix4( m );
42971 fromAttribute: function ( attribute, index, offset ) {
42973 console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
42974 return this.fromBufferAttribute( attribute, index, offset );
42980 Object.assign( Vector4.prototype, {
42982 fromAttribute: function ( attribute, index, offset ) {
42984 console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
42985 return this.fromBufferAttribute( attribute, index, offset );
42993 Geometry.prototype.computeTangents = function () {
42995 console.warn( 'THREE.Geometry: .computeTangents() has been removed.' );
42999 Object.assign( Object3D.prototype, {
43001 getChildByName: function ( name ) {
43003 console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
43004 return this.getObjectByName( name );
43007 renderDepth: function () {
43009 console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
43012 translate: function ( distance, axis ) {
43014 console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
43015 return this.translateOnAxis( axis, distance );
43021 Object.defineProperties( Object3D.prototype, {
43026 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
43027 return this.rotation.order;
43030 set: function ( value ) {
43032 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
43033 this.rotation.order = value;
43040 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
43045 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
43052 Object.defineProperties( LOD.prototype, {
43057 console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
43058 return this.levels;
43065 Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
43069 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
43074 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
43080 Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
43084 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
43085 return this.arcLengthDivisions;
43088 set: function ( value ) {
43090 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
43091 this.arcLengthDivisions = value;
43099 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
43101 console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
43102 "Use .setFocalLength and .filmGauge for a photographic setup." );
43104 if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
43105 this.setFocalLength( focalLength );
43111 Object.defineProperties( Light.prototype, {
43115 console.warn( 'THREE.Light: .onlyShadow has been removed.' );
43120 set: function ( value ) {
43122 console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
43123 this.shadow.camera.fov = value;
43127 shadowCameraLeft: {
43128 set: function ( value ) {
43130 console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
43131 this.shadow.camera.left = value;
43135 shadowCameraRight: {
43136 set: function ( value ) {
43138 console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
43139 this.shadow.camera.right = value;
43144 set: function ( value ) {
43146 console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
43147 this.shadow.camera.top = value;
43151 shadowCameraBottom: {
43152 set: function ( value ) {
43154 console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
43155 this.shadow.camera.bottom = value;
43159 shadowCameraNear: {
43160 set: function ( value ) {
43162 console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
43163 this.shadow.camera.near = value;
43168 set: function ( value ) {
43170 console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
43171 this.shadow.camera.far = value;
43175 shadowCameraVisible: {
43178 console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
43183 set: function ( value ) {
43185 console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
43186 this.shadow.bias = value;
43193 console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
43198 set: function ( value ) {
43200 console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
43201 this.shadow.mapSize.width = value;
43206 set: function ( value ) {
43208 console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
43209 this.shadow.mapSize.height = value;
43217 Object.defineProperties( BufferAttribute.prototype, {
43222 console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
43223 return this.array.length;
43230 Object.assign( BufferGeometry.prototype, {
43232 addIndex: function ( index ) {
43234 console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
43235 this.setIndex( index );
43238 addDrawCall: function ( start, count, indexOffset ) {
43240 if ( indexOffset !== undefined ) {
43242 console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
43245 console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
43246 this.addGroup( start, count );
43249 clearDrawCalls: function () {
43251 console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
43252 this.clearGroups();
43255 computeTangents: function () {
43257 console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );
43260 computeOffsets: function () {
43262 console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
43268 Object.defineProperties( BufferGeometry.prototype, {
43273 console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
43274 return this.groups;
43281 console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
43282 return this.groups;
43291 Object.defineProperties( Uniform.prototype, {
43296 console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
43301 value: function () {
43303 console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
43313 Object.defineProperties( Material.prototype, {
43318 console.warn( 'THREE.Material: .wrapAround has been removed.' );
43323 console.warn( 'THREE.Material: .wrapAround has been removed.' );
43330 console.warn( 'THREE.Material: .wrapRGB has been removed.' );
43331 return new Color();
43339 console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
43342 set: function ( value ) {
43344 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
43345 this.flatShading = ( value === FlatShading );
43352 Object.defineProperties( MeshPhongMaterial.prototype, {
43357 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
43363 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
43370 Object.defineProperties( ShaderMaterial.prototype, {
43375 console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
43376 return this.extensions.derivatives;
43379 set: function ( value ) {
43381 console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
43382 this.extensions.derivatives = value;
43391 Object.assign( WebGLRenderer.prototype, {
43393 getCurrentRenderTarget: function () {
43395 console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
43396 return this.getRenderTarget();
43400 getMaxAnisotropy: function () {
43402 console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
43403 return this.capabilities.getMaxAnisotropy();
43407 getPrecision: function () {
43409 console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
43410 return this.capabilities.precision;
43414 supportsFloatTextures: function () {
43416 console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
43417 return this.extensions.get( 'OES_texture_float' );
43420 supportsHalfFloatTextures: function () {
43422 console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
43423 return this.extensions.get( 'OES_texture_half_float' );
43426 supportsStandardDerivatives: function () {
43428 console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
43429 return this.extensions.get( 'OES_standard_derivatives' );
43432 supportsCompressedTextureS3TC: function () {
43434 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
43435 return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
43438 supportsCompressedTexturePVRTC: function () {
43440 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
43441 return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
43444 supportsBlendMinMax: function () {
43446 console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
43447 return this.extensions.get( 'EXT_blend_minmax' );
43450 supportsVertexTextures: function () {
43452 console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
43453 return this.capabilities.vertexTextures;
43456 supportsInstancedArrays: function () {
43458 console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
43459 return this.extensions.get( 'ANGLE_instanced_arrays' );
43462 enableScissorTest: function ( boolean ) {
43464 console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
43465 this.setScissorTest( boolean );
43468 initMaterial: function () {
43470 console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
43473 addPrePlugin: function () {
43475 console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
43478 addPostPlugin: function () {
43480 console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
43483 updateShadowMap: function () {
43485 console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
43491 Object.defineProperties( WebGLRenderer.prototype, {
43493 shadowMapEnabled: {
43496 return this.shadowMap.enabled;
43499 set: function ( value ) {
43501 console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
43502 this.shadowMap.enabled = value;
43509 return this.shadowMap.type;
43512 set: function ( value ) {
43514 console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
43515 this.shadowMap.type = value;
43519 shadowMapCullFace: {
43522 return this.shadowMap.cullFace;
43525 set: function ( value ) {
43527 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' );
43528 this.shadowMap.cullFace = value;
43534 Object.defineProperties( WebGLShadowMap.prototype, {
43539 return this.renderReverseSided ? CullFaceFront : CullFaceBack;
43542 set: function ( cullFace ) {
43544 var value = ( cullFace !== CullFaceBack );
43545 console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." );
43546 this.renderReverseSided = value;
43555 Object.defineProperties( WebGLRenderTarget.prototype, {
43560 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
43561 return this.texture.wrapS;
43564 set: function ( value ) {
43566 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
43567 this.texture.wrapS = value;
43574 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
43575 return this.texture.wrapT;
43578 set: function ( value ) {
43580 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
43581 this.texture.wrapT = value;
43588 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
43589 return this.texture.magFilter;
43592 set: function ( value ) {
43594 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
43595 this.texture.magFilter = value;
43602 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
43603 return this.texture.minFilter;
43606 set: function ( value ) {
43608 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
43609 this.texture.minFilter = value;
43616 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
43617 return this.texture.anisotropy;
43620 set: function ( value ) {
43622 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
43623 this.texture.anisotropy = value;
43630 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
43631 return this.texture.offset;
43634 set: function ( value ) {
43636 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
43637 this.texture.offset = value;
43644 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
43645 return this.texture.repeat;
43648 set: function ( value ) {
43650 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
43651 this.texture.repeat = value;
43658 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
43659 return this.texture.format;
43662 set: function ( value ) {
43664 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
43665 this.texture.format = value;
43672 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
43673 return this.texture.type;
43676 set: function ( value ) {
43678 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
43679 this.texture.type = value;
43686 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
43687 return this.texture.generateMipmaps;
43690 set: function ( value ) {
43692 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
43693 this.texture.generateMipmaps = value;
43702 Audio.prototype.load = function ( file ) {
43704 console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
43706 var audioLoader = new AudioLoader();
43707 audioLoader.load( file, function ( buffer ) {
43709 scope.setBuffer( buffer );
43716 AudioAnalyser.prototype.getData = function () {
43718 console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
43719 return this.getFrequencyData();
43725 CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
43727 console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
43728 return this.update( renderer, scene );
43734 var GeometryUtils = {
43736 merge: function ( geometry1, geometry2, materialIndexOffset ) {
43738 console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
43741 if ( geometry2.isMesh ) {
43743 geometry2.matrixAutoUpdate && geometry2.updateMatrix();
43745 matrix = geometry2.matrix;
43746 geometry2 = geometry2.geometry;
43750 geometry1.merge( geometry2, matrix, materialIndexOffset );
43754 center: function ( geometry ) {
43756 console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
43757 return geometry.center();
43765 crossOrigin: undefined,
43767 loadTexture: function ( url, mapping, onLoad, onError ) {
43769 console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
43771 var loader = new TextureLoader();
43772 loader.setCrossOrigin( this.crossOrigin );
43774 var texture = loader.load( url, onLoad, undefined, onError );
43776 if ( mapping ) texture.mapping = mapping;
43782 loadTextureCube: function ( urls, mapping, onLoad, onError ) {
43784 console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
43786 var loader = new CubeTextureLoader();
43787 loader.setCrossOrigin( this.crossOrigin );
43789 var texture = loader.load( urls, onLoad, undefined, onError );
43791 if ( mapping ) texture.mapping = mapping;
43797 loadCompressedTexture: function () {
43799 console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
43803 loadCompressedTextureCube: function () {
43805 console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
43813 function Projector() {
43815 console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );
43817 this.projectVector = function ( vector, camera ) {
43819 console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
43820 vector.project( camera );
43824 this.unprojectVector = function ( vector, camera ) {
43826 console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
43827 vector.unproject( camera );
43831 this.pickingRay = function () {
43833 console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
43841 function CanvasRenderer() {
43843 console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );
43845 this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
43846 this.clear = function () {};
43847 this.render = function () {};
43848 this.setClearColor = function () {};
43849 this.setSize = function () {};
43853 exports.WebGLRenderTargetCube = WebGLRenderTargetCube;
43854 exports.WebGLRenderTarget = WebGLRenderTarget;
43855 exports.WebGLRenderer = WebGLRenderer;
43856 exports.ShaderLib = ShaderLib;
43857 exports.UniformsLib = UniformsLib;
43858 exports.UniformsUtils = UniformsUtils;
43859 exports.ShaderChunk = ShaderChunk;
43860 exports.FogExp2 = FogExp2;
43862 exports.Scene = Scene;
43863 exports.LensFlare = LensFlare;
43864 exports.Sprite = Sprite;
43866 exports.SkinnedMesh = SkinnedMesh;
43867 exports.Skeleton = Skeleton;
43868 exports.Bone = Bone;
43869 exports.Mesh = Mesh;
43870 exports.LineSegments = LineSegments;
43871 exports.LineLoop = LineLoop;
43872 exports.Line = Line;
43873 exports.Points = Points;
43874 exports.Group = Group;
43875 exports.VideoTexture = VideoTexture;
43876 exports.DataTexture = DataTexture;
43877 exports.CompressedTexture = CompressedTexture;
43878 exports.CubeTexture = CubeTexture;
43879 exports.CanvasTexture = CanvasTexture;
43880 exports.DepthTexture = DepthTexture;
43881 exports.Texture = Texture;
43882 exports.CompressedTextureLoader = CompressedTextureLoader;
43883 exports.DataTextureLoader = DataTextureLoader;
43884 exports.CubeTextureLoader = CubeTextureLoader;
43885 exports.TextureLoader = TextureLoader;
43886 exports.ObjectLoader = ObjectLoader;
43887 exports.MaterialLoader = MaterialLoader;
43888 exports.BufferGeometryLoader = BufferGeometryLoader;
43889 exports.DefaultLoadingManager = DefaultLoadingManager;
43890 exports.LoadingManager = LoadingManager;
43891 exports.JSONLoader = JSONLoader;
43892 exports.ImageLoader = ImageLoader;
43893 exports.FontLoader = FontLoader;
43894 exports.FileLoader = FileLoader;
43895 exports.Loader = Loader;
43896 exports.Cache = Cache;
43897 exports.AudioLoader = AudioLoader;
43898 exports.SpotLightShadow = SpotLightShadow;
43899 exports.SpotLight = SpotLight;
43900 exports.PointLight = PointLight;
43901 exports.RectAreaLight = RectAreaLight;
43902 exports.HemisphereLight = HemisphereLight;
43903 exports.DirectionalLightShadow = DirectionalLightShadow;
43904 exports.DirectionalLight = DirectionalLight;
43905 exports.AmbientLight = AmbientLight;
43906 exports.LightShadow = LightShadow;
43907 exports.Light = Light;
43908 exports.StereoCamera = StereoCamera;
43909 exports.PerspectiveCamera = PerspectiveCamera;
43910 exports.OrthographicCamera = OrthographicCamera;
43911 exports.CubeCamera = CubeCamera;
43912 exports.ArrayCamera = ArrayCamera;
43913 exports.Camera = Camera;
43914 exports.AudioListener = AudioListener;
43915 exports.PositionalAudio = PositionalAudio;
43916 exports.AudioContext = AudioContext;
43917 exports.AudioAnalyser = AudioAnalyser;
43918 exports.Audio = Audio;
43919 exports.VectorKeyframeTrack = VectorKeyframeTrack;
43920 exports.StringKeyframeTrack = StringKeyframeTrack;
43921 exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;
43922 exports.NumberKeyframeTrack = NumberKeyframeTrack;
43923 exports.ColorKeyframeTrack = ColorKeyframeTrack;
43924 exports.BooleanKeyframeTrack = BooleanKeyframeTrack;
43925 exports.PropertyMixer = PropertyMixer;
43926 exports.PropertyBinding = PropertyBinding;
43927 exports.KeyframeTrack = KeyframeTrack;
43928 exports.AnimationUtils = AnimationUtils;
43929 exports.AnimationObjectGroup = AnimationObjectGroup;
43930 exports.AnimationMixer = AnimationMixer;
43931 exports.AnimationClip = AnimationClip;
43932 exports.Uniform = Uniform;
43933 exports.InstancedBufferGeometry = InstancedBufferGeometry;
43934 exports.BufferGeometry = BufferGeometry;
43935 exports.GeometryIdCount = GeometryIdCount;
43936 exports.Geometry = Geometry;
43937 exports.InterleavedBufferAttribute = InterleavedBufferAttribute;
43938 exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;
43939 exports.InterleavedBuffer = InterleavedBuffer;
43940 exports.InstancedBufferAttribute = InstancedBufferAttribute;
43941 exports.Face3 = Face3;
43942 exports.Object3D = Object3D;
43943 exports.Raycaster = Raycaster;
43944 exports.Layers = Layers;
43945 exports.EventDispatcher = EventDispatcher;
43946 exports.Clock = Clock;
43947 exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;
43948 exports.LinearInterpolant = LinearInterpolant;
43949 exports.DiscreteInterpolant = DiscreteInterpolant;
43950 exports.CubicInterpolant = CubicInterpolant;
43951 exports.Interpolant = Interpolant;
43952 exports.Triangle = Triangle;
43953 exports.Math = _Math;
43954 exports.Spherical = Spherical;
43955 exports.Cylindrical = Cylindrical;
43956 exports.Plane = Plane;
43957 exports.Frustum = Frustum;
43958 exports.Sphere = Sphere;
43960 exports.Matrix4 = Matrix4;
43961 exports.Matrix3 = Matrix3;
43962 exports.Box3 = Box3;
43963 exports.Box2 = Box2;
43964 exports.Line3 = Line3;
43965 exports.Euler = Euler;
43966 exports.Vector4 = Vector4;
43967 exports.Vector3 = Vector3;
43968 exports.Vector2 = Vector2;
43969 exports.Quaternion = Quaternion;
43970 exports.Color = Color;
43971 exports.ImmediateRenderObject = ImmediateRenderObject;
43972 exports.VertexNormalsHelper = VertexNormalsHelper;
43973 exports.SpotLightHelper = SpotLightHelper;
43974 exports.SkeletonHelper = SkeletonHelper;
43975 exports.PointLightHelper = PointLightHelper;
43976 exports.RectAreaLightHelper = RectAreaLightHelper;
43977 exports.HemisphereLightHelper = HemisphereLightHelper;
43978 exports.GridHelper = GridHelper;
43979 exports.PolarGridHelper = PolarGridHelper;
43980 exports.FaceNormalsHelper = FaceNormalsHelper;
43981 exports.DirectionalLightHelper = DirectionalLightHelper;
43982 exports.CameraHelper = CameraHelper;
43983 exports.BoxHelper = BoxHelper;
43984 exports.Box3Helper = Box3Helper;
43985 exports.PlaneHelper = PlaneHelper;
43986 exports.ArrowHelper = ArrowHelper;
43987 exports.AxisHelper = AxisHelper;
43988 exports.CatmullRomCurve3 = CatmullRomCurve3;
43989 exports.CubicBezierCurve3 = CubicBezierCurve3;
43990 exports.QuadraticBezierCurve3 = QuadraticBezierCurve3;
43991 exports.LineCurve3 = LineCurve3;
43992 exports.ArcCurve = ArcCurve;
43993 exports.EllipseCurve = EllipseCurve;
43994 exports.SplineCurve = SplineCurve;
43995 exports.CubicBezierCurve = CubicBezierCurve;
43996 exports.QuadraticBezierCurve = QuadraticBezierCurve;
43997 exports.LineCurve = LineCurve;
43998 exports.Shape = Shape;
43999 exports.Path = Path;
44000 exports.ShapePath = ShapePath;
44001 exports.Font = Font;
44002 exports.CurvePath = CurvePath;
44003 exports.Curve = Curve;
44004 exports.ShapeUtils = ShapeUtils;
44005 exports.SceneUtils = SceneUtils;
44006 exports.WebGLUtils = WebGLUtils;
44007 exports.WireframeGeometry = WireframeGeometry;
44008 exports.ParametricGeometry = ParametricGeometry;
44009 exports.ParametricBufferGeometry = ParametricBufferGeometry;
44010 exports.TetrahedronGeometry = TetrahedronGeometry;
44011 exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry;
44012 exports.OctahedronGeometry = OctahedronGeometry;
44013 exports.OctahedronBufferGeometry = OctahedronBufferGeometry;
44014 exports.IcosahedronGeometry = IcosahedronGeometry;
44015 exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry;
44016 exports.DodecahedronGeometry = DodecahedronGeometry;
44017 exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry;
44018 exports.PolyhedronGeometry = PolyhedronGeometry;
44019 exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry;
44020 exports.TubeGeometry = TubeGeometry;
44021 exports.TubeBufferGeometry = TubeBufferGeometry;
44022 exports.TorusKnotGeometry = TorusKnotGeometry;
44023 exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry;
44024 exports.TorusGeometry = TorusGeometry;
44025 exports.TorusBufferGeometry = TorusBufferGeometry;
44026 exports.TextGeometry = TextGeometry;
44027 exports.TextBufferGeometry = TextBufferGeometry;
44028 exports.SphereGeometry = SphereGeometry;
44029 exports.SphereBufferGeometry = SphereBufferGeometry;
44030 exports.RingGeometry = RingGeometry;
44031 exports.RingBufferGeometry = RingBufferGeometry;
44032 exports.PlaneGeometry = PlaneGeometry;
44033 exports.PlaneBufferGeometry = PlaneBufferGeometry;
44034 exports.LatheGeometry = LatheGeometry;
44035 exports.LatheBufferGeometry = LatheBufferGeometry;
44036 exports.ShapeGeometry = ShapeGeometry;
44037 exports.ShapeBufferGeometry = ShapeBufferGeometry;
44038 exports.ExtrudeGeometry = ExtrudeGeometry;
44039 exports.ExtrudeBufferGeometry = ExtrudeBufferGeometry;
44040 exports.EdgesGeometry = EdgesGeometry;
44041 exports.ConeGeometry = ConeGeometry;
44042 exports.ConeBufferGeometry = ConeBufferGeometry;
44043 exports.CylinderGeometry = CylinderGeometry;
44044 exports.CylinderBufferGeometry = CylinderBufferGeometry;
44045 exports.CircleGeometry = CircleGeometry;
44046 exports.CircleBufferGeometry = CircleBufferGeometry;
44047 exports.BoxGeometry = BoxGeometry;
44048 exports.BoxBufferGeometry = BoxBufferGeometry;
44049 exports.ShadowMaterial = ShadowMaterial;
44050 exports.SpriteMaterial = SpriteMaterial;
44051 exports.RawShaderMaterial = RawShaderMaterial;
44052 exports.ShaderMaterial = ShaderMaterial;
44053 exports.PointsMaterial = PointsMaterial;
44054 exports.MeshPhysicalMaterial = MeshPhysicalMaterial;
44055 exports.MeshStandardMaterial = MeshStandardMaterial;
44056 exports.MeshPhongMaterial = MeshPhongMaterial;
44057 exports.MeshToonMaterial = MeshToonMaterial;
44058 exports.MeshNormalMaterial = MeshNormalMaterial;
44059 exports.MeshLambertMaterial = MeshLambertMaterial;
44060 exports.MeshDepthMaterial = MeshDepthMaterial;
44061 exports.MeshDistanceMaterial = MeshDistanceMaterial;
44062 exports.MeshBasicMaterial = MeshBasicMaterial;
44063 exports.LineDashedMaterial = LineDashedMaterial;
44064 exports.LineBasicMaterial = LineBasicMaterial;
44065 exports.Material = Material;
44066 exports.Float64BufferAttribute = Float64BufferAttribute;
44067 exports.Float32BufferAttribute = Float32BufferAttribute;
44068 exports.Uint32BufferAttribute = Uint32BufferAttribute;
44069 exports.Int32BufferAttribute = Int32BufferAttribute;
44070 exports.Uint16BufferAttribute = Uint16BufferAttribute;
44071 exports.Int16BufferAttribute = Int16BufferAttribute;
44072 exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;
44073 exports.Uint8BufferAttribute = Uint8BufferAttribute;
44074 exports.Int8BufferAttribute = Int8BufferAttribute;
44075 exports.BufferAttribute = BufferAttribute;
44076 exports.REVISION = REVISION;
44077 exports.MOUSE = MOUSE;
44078 exports.CullFaceNone = CullFaceNone;
44079 exports.CullFaceBack = CullFaceBack;
44080 exports.CullFaceFront = CullFaceFront;
44081 exports.CullFaceFrontBack = CullFaceFrontBack;
44082 exports.FrontFaceDirectionCW = FrontFaceDirectionCW;
44083 exports.FrontFaceDirectionCCW = FrontFaceDirectionCCW;
44084 exports.BasicShadowMap = BasicShadowMap;
44085 exports.PCFShadowMap = PCFShadowMap;
44086 exports.PCFSoftShadowMap = PCFSoftShadowMap;
44087 exports.FrontSide = FrontSide;
44088 exports.BackSide = BackSide;
44089 exports.DoubleSide = DoubleSide;
44090 exports.FlatShading = FlatShading;
44091 exports.SmoothShading = SmoothShading;
44092 exports.NoColors = NoColors;
44093 exports.FaceColors = FaceColors;
44094 exports.VertexColors = VertexColors;
44095 exports.NoBlending = NoBlending;
44096 exports.NormalBlending = NormalBlending;
44097 exports.AdditiveBlending = AdditiveBlending;
44098 exports.SubtractiveBlending = SubtractiveBlending;
44099 exports.MultiplyBlending = MultiplyBlending;
44100 exports.CustomBlending = CustomBlending;
44101 exports.AddEquation = AddEquation;
44102 exports.SubtractEquation = SubtractEquation;
44103 exports.ReverseSubtractEquation = ReverseSubtractEquation;
44104 exports.MinEquation = MinEquation;
44105 exports.MaxEquation = MaxEquation;
44106 exports.ZeroFactor = ZeroFactor;
44107 exports.OneFactor = OneFactor;
44108 exports.SrcColorFactor = SrcColorFactor;
44109 exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;
44110 exports.SrcAlphaFactor = SrcAlphaFactor;
44111 exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;
44112 exports.DstAlphaFactor = DstAlphaFactor;
44113 exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;
44114 exports.DstColorFactor = DstColorFactor;
44115 exports.OneMinusDstColorFactor = OneMinusDstColorFactor;
44116 exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;
44117 exports.NeverDepth = NeverDepth;
44118 exports.AlwaysDepth = AlwaysDepth;
44119 exports.LessDepth = LessDepth;
44120 exports.LessEqualDepth = LessEqualDepth;
44121 exports.EqualDepth = EqualDepth;
44122 exports.GreaterEqualDepth = GreaterEqualDepth;
44123 exports.GreaterDepth = GreaterDepth;
44124 exports.NotEqualDepth = NotEqualDepth;
44125 exports.MultiplyOperation = MultiplyOperation;
44126 exports.MixOperation = MixOperation;
44127 exports.AddOperation = AddOperation;
44128 exports.NoToneMapping = NoToneMapping;
44129 exports.LinearToneMapping = LinearToneMapping;
44130 exports.ReinhardToneMapping = ReinhardToneMapping;
44131 exports.Uncharted2ToneMapping = Uncharted2ToneMapping;
44132 exports.CineonToneMapping = CineonToneMapping;
44133 exports.UVMapping = UVMapping;
44134 exports.CubeReflectionMapping = CubeReflectionMapping;
44135 exports.CubeRefractionMapping = CubeRefractionMapping;
44136 exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;
44137 exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;
44138 exports.SphericalReflectionMapping = SphericalReflectionMapping;
44139 exports.CubeUVReflectionMapping = CubeUVReflectionMapping;
44140 exports.CubeUVRefractionMapping = CubeUVRefractionMapping;
44141 exports.RepeatWrapping = RepeatWrapping;
44142 exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
44143 exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
44144 exports.NearestFilter = NearestFilter;
44145 exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
44146 exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;
44147 exports.LinearFilter = LinearFilter;
44148 exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;
44149 exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;
44150 exports.UnsignedByteType = UnsignedByteType;
44151 exports.ByteType = ByteType;
44152 exports.ShortType = ShortType;
44153 exports.UnsignedShortType = UnsignedShortType;
44154 exports.IntType = IntType;
44155 exports.UnsignedIntType = UnsignedIntType;
44156 exports.FloatType = FloatType;
44157 exports.HalfFloatType = HalfFloatType;
44158 exports.UnsignedShort4444Type = UnsignedShort4444Type;
44159 exports.UnsignedShort5551Type = UnsignedShort5551Type;
44160 exports.UnsignedShort565Type = UnsignedShort565Type;
44161 exports.UnsignedInt248Type = UnsignedInt248Type;
44162 exports.AlphaFormat = AlphaFormat;
44163 exports.RGBFormat = RGBFormat;
44164 exports.RGBAFormat = RGBAFormat;
44165 exports.LuminanceFormat = LuminanceFormat;
44166 exports.LuminanceAlphaFormat = LuminanceAlphaFormat;
44167 exports.RGBEFormat = RGBEFormat;
44168 exports.DepthFormat = DepthFormat;
44169 exports.DepthStencilFormat = DepthStencilFormat;
44170 exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;
44171 exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
44172 exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
44173 exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
44174 exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;
44175 exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
44176 exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
44177 exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;
44178 exports.RGB_ETC1_Format = RGB_ETC1_Format;
44179 exports.LoopOnce = LoopOnce;
44180 exports.LoopRepeat = LoopRepeat;
44181 exports.LoopPingPong = LoopPingPong;
44182 exports.InterpolateDiscrete = InterpolateDiscrete;
44183 exports.InterpolateLinear = InterpolateLinear;
44184 exports.InterpolateSmooth = InterpolateSmooth;
44185 exports.ZeroCurvatureEnding = ZeroCurvatureEnding;
44186 exports.ZeroSlopeEnding = ZeroSlopeEnding;
44187 exports.WrapAroundEnding = WrapAroundEnding;
44188 exports.TrianglesDrawMode = TrianglesDrawMode;
44189 exports.TriangleStripDrawMode = TriangleStripDrawMode;
44190 exports.TriangleFanDrawMode = TriangleFanDrawMode;
44191 exports.LinearEncoding = LinearEncoding;
44192 exports.sRGBEncoding = sRGBEncoding;
44193 exports.GammaEncoding = GammaEncoding;
44194 exports.RGBEEncoding = RGBEEncoding;
44195 exports.LogLuvEncoding = LogLuvEncoding;
44196 exports.RGBM7Encoding = RGBM7Encoding;
44197 exports.RGBM16Encoding = RGBM16Encoding;
44198 exports.RGBDEncoding = RGBDEncoding;
44199 exports.BasicDepthPacking = BasicDepthPacking;
44200 exports.RGBADepthPacking = RGBADepthPacking;
44201 exports.CubeGeometry = BoxGeometry;
44202 exports.Face4 = Face4;
44203 exports.LineStrip = LineStrip;
44204 exports.LinePieces = LinePieces;
44205 exports.MeshFaceMaterial = MeshFaceMaterial;
44206 exports.MultiMaterial = MultiMaterial;
44207 exports.PointCloud = PointCloud;
44208 exports.Particle = Particle;
44209 exports.ParticleSystem = ParticleSystem;
44210 exports.PointCloudMaterial = PointCloudMaterial;
44211 exports.ParticleBasicMaterial = ParticleBasicMaterial;
44212 exports.ParticleSystemMaterial = ParticleSystemMaterial;
44213 exports.Vertex = Vertex;
44214 exports.DynamicBufferAttribute = DynamicBufferAttribute;
44215 exports.Int8Attribute = Int8Attribute;
44216 exports.Uint8Attribute = Uint8Attribute;
44217 exports.Uint8ClampedAttribute = Uint8ClampedAttribute;
44218 exports.Int16Attribute = Int16Attribute;
44219 exports.Uint16Attribute = Uint16Attribute;
44220 exports.Int32Attribute = Int32Attribute;
44221 exports.Uint32Attribute = Uint32Attribute;
44222 exports.Float32Attribute = Float32Attribute;
44223 exports.Float64Attribute = Float64Attribute;
44224 exports.ClosedSplineCurve3 = ClosedSplineCurve3;
44225 exports.SplineCurve3 = SplineCurve3;
44226 exports.Spline = Spline;
44227 exports.BoundingBoxHelper = BoundingBoxHelper;
44228 exports.EdgesHelper = EdgesHelper;
44229 exports.WireframeHelper = WireframeHelper;
44230 exports.XHRLoader = XHRLoader;
44231 exports.BinaryTextureLoader = BinaryTextureLoader;
44232 exports.GeometryUtils = GeometryUtils;
44233 exports.ImageUtils = ImageUtils;
44234 exports.Projector = Projector;
44235 exports.CanvasRenderer = CanvasRenderer;
44237 Object.defineProperty(exports, '__esModule', { value: true });