github.com/EngineerKamesh/gofullstack@v0.0.0-20180609171605-d41341d7d4ee/volume3/section2/3dgopher/static/js/three.js (about) 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'; 6 7 // Polyfills 8 9 if ( Number.EPSILON === undefined ) { 10 11 Number.EPSILON = Math.pow( 2, - 52 ); 12 13 } 14 15 // 16 17 if ( Math.sign === undefined ) { 18 19 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign 20 21 Math.sign = function ( x ) { 22 23 return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; 24 25 }; 26 27 } 28 29 if ( Function.prototype.name === undefined ) { 30 31 // Missing in IE9-11. 32 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name 33 34 Object.defineProperty( Function.prototype, 'name', { 35 36 get: function () { 37 38 return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ]; 39 40 } 41 42 } ); 43 44 } 45 46 if ( Object.assign === undefined ) { 47 48 // Missing in IE. 49 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 50 51 ( function () { 52 53 Object.assign = function ( target ) { 54 55 'use strict'; 56 57 if ( target === undefined || target === null ) { 58 59 throw new TypeError( 'Cannot convert undefined or null to object' ); 60 61 } 62 63 var output = Object( target ); 64 65 for ( var index = 1; index < arguments.length; index ++ ) { 66 67 var source = arguments[ index ]; 68 69 if ( source !== undefined && source !== null ) { 70 71 for ( var nextKey in source ) { 72 73 if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { 74 75 output[ nextKey ] = source[ nextKey ]; 76 77 } 78 79 } 80 81 } 82 83 } 84 85 return output; 86 87 }; 88 89 } )(); 90 91 } 92 93 /** 94 * https://github.com/mrdoob/eventdispatcher.js/ 95 */ 96 97 function EventDispatcher() {} 98 99 EventDispatcher.prototype = { 100 101 addEventListener: function ( type, listener ) { 102 103 if ( this._listeners === undefined ) this._listeners = {}; 104 105 var listeners = this._listeners; 106 107 if ( listeners[ type ] === undefined ) { 108 109 listeners[ type ] = []; 110 111 } 112 113 if ( listeners[ type ].indexOf( listener ) === - 1 ) { 114 115 listeners[ type ].push( listener ); 116 117 } 118 119 }, 120 121 hasEventListener: function ( type, listener ) { 122 123 if ( this._listeners === undefined ) return false; 124 125 var listeners = this._listeners; 126 127 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; 128 129 }, 130 131 removeEventListener: function ( type, listener ) { 132 133 if ( this._listeners === undefined ) return; 134 135 var listeners = this._listeners; 136 var listenerArray = listeners[ type ]; 137 138 if ( listenerArray !== undefined ) { 139 140 var index = listenerArray.indexOf( listener ); 141 142 if ( index !== - 1 ) { 143 144 listenerArray.splice( index, 1 ); 145 146 } 147 148 } 149 150 }, 151 152 dispatchEvent: function ( event ) { 153 154 if ( this._listeners === undefined ) return; 155 156 var listeners = this._listeners; 157 var listenerArray = listeners[ event.type ]; 158 159 if ( listenerArray !== undefined ) { 160 161 event.target = this; 162 163 var array = [], i = 0; 164 var length = listenerArray.length; 165 166 for ( i = 0; i < length; i ++ ) { 167 168 array[ i ] = listenerArray[ i ]; 169 170 } 171 172 for ( i = 0; i < length; i ++ ) { 173 174 array[ i ].call( this, event ); 175 176 } 177 178 } 179 180 } 181 182 }; 183 184 var REVISION = '84'; 185 var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; 186 var CullFaceNone = 0; 187 var CullFaceBack = 1; 188 var CullFaceFront = 2; 189 var CullFaceFrontBack = 3; 190 var FrontFaceDirectionCW = 0; 191 var FrontFaceDirectionCCW = 1; 192 var BasicShadowMap = 0; 193 var PCFShadowMap = 1; 194 var PCFSoftShadowMap = 2; 195 var FrontSide = 0; 196 var BackSide = 1; 197 var DoubleSide = 2; 198 var FlatShading = 1; 199 var SmoothShading = 2; 200 var NoColors = 0; 201 var FaceColors = 1; 202 var VertexColors = 2; 203 var NoBlending = 0; 204 var NormalBlending = 1; 205 var AdditiveBlending = 2; 206 var SubtractiveBlending = 3; 207 var MultiplyBlending = 4; 208 var CustomBlending = 5; 209 var AddEquation = 100; 210 var SubtractEquation = 101; 211 var ReverseSubtractEquation = 102; 212 var MinEquation = 103; 213 var MaxEquation = 104; 214 var ZeroFactor = 200; 215 var OneFactor = 201; 216 var SrcColorFactor = 202; 217 var OneMinusSrcColorFactor = 203; 218 var SrcAlphaFactor = 204; 219 var OneMinusSrcAlphaFactor = 205; 220 var DstAlphaFactor = 206; 221 var OneMinusDstAlphaFactor = 207; 222 var DstColorFactor = 208; 223 var OneMinusDstColorFactor = 209; 224 var SrcAlphaSaturateFactor = 210; 225 var NeverDepth = 0; 226 var AlwaysDepth = 1; 227 var LessDepth = 2; 228 var LessEqualDepth = 3; 229 var EqualDepth = 4; 230 var GreaterEqualDepth = 5; 231 var GreaterDepth = 6; 232 var NotEqualDepth = 7; 233 var MultiplyOperation = 0; 234 var MixOperation = 1; 235 var AddOperation = 2; 236 var NoToneMapping = 0; 237 var LinearToneMapping = 1; 238 var ReinhardToneMapping = 2; 239 var Uncharted2ToneMapping = 3; 240 var CineonToneMapping = 4; 241 var UVMapping = 300; 242 var CubeReflectionMapping = 301; 243 var CubeRefractionMapping = 302; 244 var EquirectangularReflectionMapping = 303; 245 var EquirectangularRefractionMapping = 304; 246 var SphericalReflectionMapping = 305; 247 var CubeUVReflectionMapping = 306; 248 var CubeUVRefractionMapping = 307; 249 var RepeatWrapping = 1000; 250 var ClampToEdgeWrapping = 1001; 251 var MirroredRepeatWrapping = 1002; 252 var NearestFilter = 1003; 253 var NearestMipMapNearestFilter = 1004; 254 var NearestMipMapLinearFilter = 1005; 255 var LinearFilter = 1006; 256 var LinearMipMapNearestFilter = 1007; 257 var LinearMipMapLinearFilter = 1008; 258 var UnsignedByteType = 1009; 259 var ByteType = 1010; 260 var ShortType = 1011; 261 var UnsignedShortType = 1012; 262 var IntType = 1013; 263 var UnsignedIntType = 1014; 264 var FloatType = 1015; 265 var HalfFloatType = 1016; 266 var UnsignedShort4444Type = 1017; 267 var UnsignedShort5551Type = 1018; 268 var UnsignedShort565Type = 1019; 269 var UnsignedInt248Type = 1020; 270 var AlphaFormat = 1021; 271 var RGBFormat = 1022; 272 var RGBAFormat = 1023; 273 var LuminanceFormat = 1024; 274 var LuminanceAlphaFormat = 1025; 275 var RGBEFormat = RGBAFormat; 276 var DepthFormat = 1026; 277 var DepthStencilFormat = 1027; 278 var RGB_S3TC_DXT1_Format = 2001; 279 var RGBA_S3TC_DXT1_Format = 2002; 280 var RGBA_S3TC_DXT3_Format = 2003; 281 var RGBA_S3TC_DXT5_Format = 2004; 282 var RGB_PVRTC_4BPPV1_Format = 2100; 283 var RGB_PVRTC_2BPPV1_Format = 2101; 284 var RGBA_PVRTC_4BPPV1_Format = 2102; 285 var RGBA_PVRTC_2BPPV1_Format = 2103; 286 var RGB_ETC1_Format = 2151; 287 var LoopOnce = 2200; 288 var LoopRepeat = 2201; 289 var LoopPingPong = 2202; 290 var InterpolateDiscrete = 2300; 291 var InterpolateLinear = 2301; 292 var InterpolateSmooth = 2302; 293 var ZeroCurvatureEnding = 2400; 294 var ZeroSlopeEnding = 2401; 295 var WrapAroundEnding = 2402; 296 var TrianglesDrawMode = 0; 297 var TriangleStripDrawMode = 1; 298 var TriangleFanDrawMode = 2; 299 var LinearEncoding = 3000; 300 var sRGBEncoding = 3001; 301 var GammaEncoding = 3007; 302 var RGBEEncoding = 3002; 303 var LogLuvEncoding = 3003; 304 var RGBM7Encoding = 3004; 305 var RGBM16Encoding = 3005; 306 var RGBDEncoding = 3006; 307 var BasicDepthPacking = 3200; 308 var RGBADepthPacking = 3201; 309 310 /** 311 * @author alteredq / http://alteredqualia.com/ 312 * @author mrdoob / http://mrdoob.com/ 313 */ 314 315 var _Math = { 316 317 DEG2RAD: Math.PI / 180, 318 RAD2DEG: 180 / Math.PI, 319 320 generateUUID: function () { 321 322 // http://www.broofa.com/Tools/Math.uuid.htm 323 324 var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); 325 var uuid = new Array( 36 ); 326 var rnd = 0, r; 327 328 return function generateUUID() { 329 330 for ( var i = 0; i < 36; i ++ ) { 331 332 if ( i === 8 || i === 13 || i === 18 || i === 23 ) { 333 334 uuid[ i ] = '-'; 335 336 } else if ( i === 14 ) { 337 338 uuid[ i ] = '4'; 339 340 } else { 341 342 if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; 343 r = rnd & 0xf; 344 rnd = rnd >> 4; 345 uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; 346 347 } 348 349 } 350 351 return uuid.join( '' ); 352 353 }; 354 355 }(), 356 357 clamp: function ( value, min, max ) { 358 359 return Math.max( min, Math.min( max, value ) ); 360 361 }, 362 363 // compute euclidian modulo of m % n 364 // https://en.wikipedia.org/wiki/Modulo_operation 365 366 euclideanModulo: function ( n, m ) { 367 368 return ( ( n % m ) + m ) % m; 369 370 }, 371 372 // Linear mapping from range <a1, a2> to range <b1, b2> 373 374 mapLinear: function ( x, a1, a2, b1, b2 ) { 375 376 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); 377 378 }, 379 380 // https://en.wikipedia.org/wiki/Linear_interpolation 381 382 lerp: function ( x, y, t ) { 383 384 return ( 1 - t ) * x + t * y; 385 386 }, 387 388 // http://en.wikipedia.org/wiki/Smoothstep 389 390 smoothstep: function ( x, min, max ) { 391 392 if ( x <= min ) return 0; 393 if ( x >= max ) return 1; 394 395 x = ( x - min ) / ( max - min ); 396 397 return x * x * ( 3 - 2 * x ); 398 399 }, 400 401 smootherstep: function ( x, min, max ) { 402 403 if ( x <= min ) return 0; 404 if ( x >= max ) return 1; 405 406 x = ( x - min ) / ( max - min ); 407 408 return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); 409 410 }, 411 412 // Random integer from <low, high> interval 413 414 randInt: function ( low, high ) { 415 416 return low + Math.floor( Math.random() * ( high - low + 1 ) ); 417 418 }, 419 420 // Random float from <low, high> interval 421 422 randFloat: function ( low, high ) { 423 424 return low + Math.random() * ( high - low ); 425 426 }, 427 428 // Random float from <-range/2, range/2> interval 429 430 randFloatSpread: function ( range ) { 431 432 return range * ( 0.5 - Math.random() ); 433 434 }, 435 436 degToRad: function ( degrees ) { 437 438 return degrees * _Math.DEG2RAD; 439 440 }, 441 442 radToDeg: function ( radians ) { 443 444 return radians * _Math.RAD2DEG; 445 446 }, 447 448 isPowerOfTwo: function ( value ) { 449 450 return ( value & ( value - 1 ) ) === 0 && value !== 0; 451 452 }, 453 454 nearestPowerOfTwo: function ( value ) { 455 456 return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); 457 458 }, 459 460 nextPowerOfTwo: function ( value ) { 461 462 value --; 463 value |= value >> 1; 464 value |= value >> 2; 465 value |= value >> 4; 466 value |= value >> 8; 467 value |= value >> 16; 468 value ++; 469 470 return value; 471 472 } 473 474 }; 475 476 /** 477 * @author mrdoob / http://mrdoob.com/ 478 * @author philogb / http://blog.thejit.org/ 479 * @author egraether / http://egraether.com/ 480 * @author zz85 / http://www.lab4games.net/zz85/blog 481 */ 482 483 function Vector2( x, y ) { 484 485 this.x = x || 0; 486 this.y = y || 0; 487 488 } 489 490 Vector2.prototype = { 491 492 constructor: Vector2, 493 494 isVector2: true, 495 496 get width() { 497 498 return this.x; 499 500 }, 501 502 set width( value ) { 503 504 this.x = value; 505 506 }, 507 508 get height() { 509 510 return this.y; 511 512 }, 513 514 set height( value ) { 515 516 this.y = value; 517 518 }, 519 520 // 521 522 set: function ( x, y ) { 523 524 this.x = x; 525 this.y = y; 526 527 return this; 528 529 }, 530 531 setScalar: function ( scalar ) { 532 533 this.x = scalar; 534 this.y = scalar; 535 536 return this; 537 538 }, 539 540 setX: function ( x ) { 541 542 this.x = x; 543 544 return this; 545 546 }, 547 548 setY: function ( y ) { 549 550 this.y = y; 551 552 return this; 553 554 }, 555 556 setComponent: function ( index, value ) { 557 558 switch ( index ) { 559 560 case 0: this.x = value; break; 561 case 1: this.y = value; break; 562 default: throw new Error( 'index is out of range: ' + index ); 563 564 } 565 566 return this; 567 568 }, 569 570 getComponent: function ( index ) { 571 572 switch ( index ) { 573 574 case 0: return this.x; 575 case 1: return this.y; 576 default: throw new Error( 'index is out of range: ' + index ); 577 578 } 579 580 }, 581 582 clone: function () { 583 584 return new this.constructor( this.x, this.y ); 585 586 }, 587 588 copy: function ( v ) { 589 590 this.x = v.x; 591 this.y = v.y; 592 593 return this; 594 595 }, 596 597 add: function ( v, w ) { 598 599 if ( w !== undefined ) { 600 601 console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); 602 return this.addVectors( v, w ); 603 604 } 605 606 this.x += v.x; 607 this.y += v.y; 608 609 return this; 610 611 }, 612 613 addScalar: function ( s ) { 614 615 this.x += s; 616 this.y += s; 617 618 return this; 619 620 }, 621 622 addVectors: function ( a, b ) { 623 624 this.x = a.x + b.x; 625 this.y = a.y + b.y; 626 627 return this; 628 629 }, 630 631 addScaledVector: function ( v, s ) { 632 633 this.x += v.x * s; 634 this.y += v.y * s; 635 636 return this; 637 638 }, 639 640 sub: function ( v, w ) { 641 642 if ( w !== undefined ) { 643 644 console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); 645 return this.subVectors( v, w ); 646 647 } 648 649 this.x -= v.x; 650 this.y -= v.y; 651 652 return this; 653 654 }, 655 656 subScalar: function ( s ) { 657 658 this.x -= s; 659 this.y -= s; 660 661 return this; 662 663 }, 664 665 subVectors: function ( a, b ) { 666 667 this.x = a.x - b.x; 668 this.y = a.y - b.y; 669 670 return this; 671 672 }, 673 674 multiply: function ( v ) { 675 676 this.x *= v.x; 677 this.y *= v.y; 678 679 return this; 680 681 }, 682 683 multiplyScalar: function ( scalar ) { 684 685 if ( isFinite( scalar ) ) { 686 687 this.x *= scalar; 688 this.y *= scalar; 689 690 } else { 691 692 this.x = 0; 693 this.y = 0; 694 695 } 696 697 return this; 698 699 }, 700 701 divide: function ( v ) { 702 703 this.x /= v.x; 704 this.y /= v.y; 705 706 return this; 707 708 }, 709 710 divideScalar: function ( scalar ) { 711 712 return this.multiplyScalar( 1 / scalar ); 713 714 }, 715 716 min: function ( v ) { 717 718 this.x = Math.min( this.x, v.x ); 719 this.y = Math.min( this.y, v.y ); 720 721 return this; 722 723 }, 724 725 max: function ( v ) { 726 727 this.x = Math.max( this.x, v.x ); 728 this.y = Math.max( this.y, v.y ); 729 730 return this; 731 732 }, 733 734 clamp: function ( min, max ) { 735 736 // This function assumes min < max, if this assumption isn't true it will not operate correctly 737 738 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 739 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 740 741 return this; 742 743 }, 744 745 clampScalar: function () { 746 747 var min, max; 748 749 return function clampScalar( minVal, maxVal ) { 750 751 if ( min === undefined ) { 752 753 min = new Vector2(); 754 max = new Vector2(); 755 756 } 757 758 min.set( minVal, minVal ); 759 max.set( maxVal, maxVal ); 760 761 return this.clamp( min, max ); 762 763 }; 764 765 }(), 766 767 clampLength: function ( min, max ) { 768 769 var length = this.length(); 770 771 return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); 772 773 }, 774 775 floor: function () { 776 777 this.x = Math.floor( this.x ); 778 this.y = Math.floor( this.y ); 779 780 return this; 781 782 }, 783 784 ceil: function () { 785 786 this.x = Math.ceil( this.x ); 787 this.y = Math.ceil( this.y ); 788 789 return this; 790 791 }, 792 793 round: function () { 794 795 this.x = Math.round( this.x ); 796 this.y = Math.round( this.y ); 797 798 return this; 799 800 }, 801 802 roundToZero: function () { 803 804 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); 805 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); 806 807 return this; 808 809 }, 810 811 negate: function () { 812 813 this.x = - this.x; 814 this.y = - this.y; 815 816 return this; 817 818 }, 819 820 dot: function ( v ) { 821 822 return this.x * v.x + this.y * v.y; 823 824 }, 825 826 lengthSq: function () { 827 828 return this.x * this.x + this.y * this.y; 829 830 }, 831 832 length: function () { 833 834 return Math.sqrt( this.x * this.x + this.y * this.y ); 835 836 }, 837 838 lengthManhattan: function() { 839 840 return Math.abs( this.x ) + Math.abs( this.y ); 841 842 }, 843 844 normalize: function () { 845 846 return this.divideScalar( this.length() ); 847 848 }, 849 850 angle: function () { 851 852 // computes the angle in radians with respect to the positive x-axis 853 854 var angle = Math.atan2( this.y, this.x ); 855 856 if ( angle < 0 ) angle += 2 * Math.PI; 857 858 return angle; 859 860 }, 861 862 distanceTo: function ( v ) { 863 864 return Math.sqrt( this.distanceToSquared( v ) ); 865 866 }, 867 868 distanceToSquared: function ( v ) { 869 870 var dx = this.x - v.x, dy = this.y - v.y; 871 return dx * dx + dy * dy; 872 873 }, 874 875 distanceToManhattan: function ( v ) { 876 877 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); 878 879 }, 880 881 setLength: function ( length ) { 882 883 return this.multiplyScalar( length / this.length() ); 884 885 }, 886 887 lerp: function ( v, alpha ) { 888 889 this.x += ( v.x - this.x ) * alpha; 890 this.y += ( v.y - this.y ) * alpha; 891 892 return this; 893 894 }, 895 896 lerpVectors: function ( v1, v2, alpha ) { 897 898 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); 899 900 }, 901 902 equals: function ( v ) { 903 904 return ( ( v.x === this.x ) && ( v.y === this.y ) ); 905 906 }, 907 908 fromArray: function ( array, offset ) { 909 910 if ( offset === undefined ) offset = 0; 911 912 this.x = array[ offset ]; 913 this.y = array[ offset + 1 ]; 914 915 return this; 916 917 }, 918 919 toArray: function ( array, offset ) { 920 921 if ( array === undefined ) array = []; 922 if ( offset === undefined ) offset = 0; 923 924 array[ offset ] = this.x; 925 array[ offset + 1 ] = this.y; 926 927 return array; 928 929 }, 930 931 fromBufferAttribute: function ( attribute, index, offset ) { 932 933 if ( offset !== undefined ) { 934 935 console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' ); 936 937 } 938 939 this.x = attribute.getX( index ); 940 this.y = attribute.getY( index ); 941 942 return this; 943 944 }, 945 946 rotateAround: function ( center, angle ) { 947 948 var c = Math.cos( angle ), s = Math.sin( angle ); 949 950 var x = this.x - center.x; 951 var y = this.y - center.y; 952 953 this.x = x * c - y * s + center.x; 954 this.y = x * s + y * c + center.y; 955 956 return this; 957 958 } 959 960 }; 961 962 /** 963 * @author mrdoob / http://mrdoob.com/ 964 * @author alteredq / http://alteredqualia.com/ 965 * @author szimek / https://github.com/szimek/ 966 */ 967 968 var textureId = 0; 969 970 function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { 971 972 Object.defineProperty( this, 'id', { value: textureId ++ } ); 973 974 this.uuid = _Math.generateUUID(); 975 976 this.name = ''; 977 978 this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE; 979 this.mipmaps = []; 980 981 this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING; 982 983 this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping; 984 this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping; 985 986 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; 987 this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter; 988 989 this.anisotropy = anisotropy !== undefined ? anisotropy : 1; 990 991 this.format = format !== undefined ? format : RGBAFormat; 992 this.type = type !== undefined ? type : UnsignedByteType; 993 994 this.offset = new Vector2( 0, 0 ); 995 this.repeat = new Vector2( 1, 1 ); 996 997 this.generateMipmaps = true; 998 this.premultiplyAlpha = false; 999 this.flipY = true; 1000 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) 1001 1002 1003 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. 1004 // 1005 // Also changing the encoding after already used by a Material will not automatically make the Material 1006 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. 1007 this.encoding = encoding !== undefined ? encoding : LinearEncoding; 1008 1009 this.version = 0; 1010 this.onUpdate = null; 1011 1012 } 1013 1014 Texture.DEFAULT_IMAGE = undefined; 1015 Texture.DEFAULT_MAPPING = UVMapping; 1016 1017 Texture.prototype = { 1018 1019 constructor: Texture, 1020 1021 isTexture: true, 1022 1023 set needsUpdate( value ) { 1024 1025 if ( value === true ) this.version ++; 1026 1027 }, 1028 1029 clone: function () { 1030 1031 return new this.constructor().copy( this ); 1032 1033 }, 1034 1035 copy: function ( source ) { 1036 1037 this.image = source.image; 1038 this.mipmaps = source.mipmaps.slice( 0 ); 1039 1040 this.mapping = source.mapping; 1041 1042 this.wrapS = source.wrapS; 1043 this.wrapT = source.wrapT; 1044 1045 this.magFilter = source.magFilter; 1046 this.minFilter = source.minFilter; 1047 1048 this.anisotropy = source.anisotropy; 1049 1050 this.format = source.format; 1051 this.type = source.type; 1052 1053 this.offset.copy( source.offset ); 1054 this.repeat.copy( source.repeat ); 1055 1056 this.generateMipmaps = source.generateMipmaps; 1057 this.premultiplyAlpha = source.premultiplyAlpha; 1058 this.flipY = source.flipY; 1059 this.unpackAlignment = source.unpackAlignment; 1060 this.encoding = source.encoding; 1061 1062 return this; 1063 1064 }, 1065 1066 toJSON: function ( meta ) { 1067 1068 if ( meta.textures[ this.uuid ] !== undefined ) { 1069 1070 return meta.textures[ this.uuid ]; 1071 1072 } 1073 1074 function getDataURL( image ) { 1075 1076 var canvas; 1077 1078 if ( image.toDataURL !== undefined ) { 1079 1080 canvas = image; 1081 1082 } else { 1083 1084 canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); 1085 canvas.width = image.width; 1086 canvas.height = image.height; 1087 1088 canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height ); 1089 1090 } 1091 1092 if ( canvas.width > 2048 || canvas.height > 2048 ) { 1093 1094 return canvas.toDataURL( 'image/jpeg', 0.6 ); 1095 1096 } else { 1097 1098 return canvas.toDataURL( 'image/png' ); 1099 1100 } 1101 1102 } 1103 1104 var output = { 1105 metadata: { 1106 version: 4.4, 1107 type: 'Texture', 1108 generator: 'Texture.toJSON' 1109 }, 1110 1111 uuid: this.uuid, 1112 name: this.name, 1113 1114 mapping: this.mapping, 1115 1116 repeat: [ this.repeat.x, this.repeat.y ], 1117 offset: [ this.offset.x, this.offset.y ], 1118 wrap: [ this.wrapS, this.wrapT ], 1119 1120 minFilter: this.minFilter, 1121 magFilter: this.magFilter, 1122 anisotropy: this.anisotropy, 1123 1124 flipY: this.flipY 1125 }; 1126 1127 if ( this.image !== undefined ) { 1128 1129 // TODO: Move to THREE.Image 1130 1131 var image = this.image; 1132 1133 if ( image.uuid === undefined ) { 1134 1135 image.uuid = _Math.generateUUID(); // UGH 1136 1137 } 1138 1139 if ( meta.images[ image.uuid ] === undefined ) { 1140 1141 meta.images[ image.uuid ] = { 1142 uuid: image.uuid, 1143 url: getDataURL( image ) 1144 }; 1145 1146 } 1147 1148 output.image = image.uuid; 1149 1150 } 1151 1152 meta.textures[ this.uuid ] = output; 1153 1154 return output; 1155 1156 }, 1157 1158 dispose: function () { 1159 1160 this.dispatchEvent( { type: 'dispose' } ); 1161 1162 }, 1163 1164 transformUv: function ( uv ) { 1165 1166 if ( this.mapping !== UVMapping ) return; 1167 1168 uv.multiply( this.repeat ); 1169 uv.add( this.offset ); 1170 1171 if ( uv.x < 0 || uv.x > 1 ) { 1172 1173 switch ( this.wrapS ) { 1174 1175 case RepeatWrapping: 1176 1177 uv.x = uv.x - Math.floor( uv.x ); 1178 break; 1179 1180 case ClampToEdgeWrapping: 1181 1182 uv.x = uv.x < 0 ? 0 : 1; 1183 break; 1184 1185 case MirroredRepeatWrapping: 1186 1187 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { 1188 1189 uv.x = Math.ceil( uv.x ) - uv.x; 1190 1191 } else { 1192 1193 uv.x = uv.x - Math.floor( uv.x ); 1194 1195 } 1196 break; 1197 1198 } 1199 1200 } 1201 1202 if ( uv.y < 0 || uv.y > 1 ) { 1203 1204 switch ( this.wrapT ) { 1205 1206 case RepeatWrapping: 1207 1208 uv.y = uv.y - Math.floor( uv.y ); 1209 break; 1210 1211 case ClampToEdgeWrapping: 1212 1213 uv.y = uv.y < 0 ? 0 : 1; 1214 break; 1215 1216 case MirroredRepeatWrapping: 1217 1218 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { 1219 1220 uv.y = Math.ceil( uv.y ) - uv.y; 1221 1222 } else { 1223 1224 uv.y = uv.y - Math.floor( uv.y ); 1225 1226 } 1227 break; 1228 1229 } 1230 1231 } 1232 1233 if ( this.flipY ) { 1234 1235 uv.y = 1 - uv.y; 1236 1237 } 1238 1239 } 1240 1241 }; 1242 1243 Object.assign( Texture.prototype, EventDispatcher.prototype ); 1244 1245 /** 1246 * @author supereggbert / http://www.paulbrunt.co.uk/ 1247 * @author philogb / http://blog.thejit.org/ 1248 * @author mikael emtinger / http://gomo.se/ 1249 * @author egraether / http://egraether.com/ 1250 * @author WestLangley / http://github.com/WestLangley 1251 */ 1252 1253 function Vector4( x, y, z, w ) { 1254 1255 this.x = x || 0; 1256 this.y = y || 0; 1257 this.z = z || 0; 1258 this.w = ( w !== undefined ) ? w : 1; 1259 1260 } 1261 1262 Vector4.prototype = { 1263 1264 constructor: Vector4, 1265 1266 isVector4: true, 1267 1268 set: function ( x, y, z, w ) { 1269 1270 this.x = x; 1271 this.y = y; 1272 this.z = z; 1273 this.w = w; 1274 1275 return this; 1276 1277 }, 1278 1279 setScalar: function ( scalar ) { 1280 1281 this.x = scalar; 1282 this.y = scalar; 1283 this.z = scalar; 1284 this.w = scalar; 1285 1286 return this; 1287 1288 }, 1289 1290 setX: function ( x ) { 1291 1292 this.x = x; 1293 1294 return this; 1295 1296 }, 1297 1298 setY: function ( y ) { 1299 1300 this.y = y; 1301 1302 return this; 1303 1304 }, 1305 1306 setZ: function ( z ) { 1307 1308 this.z = z; 1309 1310 return this; 1311 1312 }, 1313 1314 setW: function ( w ) { 1315 1316 this.w = w; 1317 1318 return this; 1319 1320 }, 1321 1322 setComponent: function ( index, value ) { 1323 1324 switch ( index ) { 1325 1326 case 0: this.x = value; break; 1327 case 1: this.y = value; break; 1328 case 2: this.z = value; break; 1329 case 3: this.w = value; break; 1330 default: throw new Error( 'index is out of range: ' + index ); 1331 1332 } 1333 1334 return this; 1335 1336 }, 1337 1338 getComponent: function ( index ) { 1339 1340 switch ( index ) { 1341 1342 case 0: return this.x; 1343 case 1: return this.y; 1344 case 2: return this.z; 1345 case 3: return this.w; 1346 default: throw new Error( 'index is out of range: ' + index ); 1347 1348 } 1349 1350 }, 1351 1352 clone: function () { 1353 1354 return new this.constructor( this.x, this.y, this.z, this.w ); 1355 1356 }, 1357 1358 copy: function ( v ) { 1359 1360 this.x = v.x; 1361 this.y = v.y; 1362 this.z = v.z; 1363 this.w = ( v.w !== undefined ) ? v.w : 1; 1364 1365 return this; 1366 1367 }, 1368 1369 add: function ( v, w ) { 1370 1371 if ( w !== undefined ) { 1372 1373 console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); 1374 return this.addVectors( v, w ); 1375 1376 } 1377 1378 this.x += v.x; 1379 this.y += v.y; 1380 this.z += v.z; 1381 this.w += v.w; 1382 1383 return this; 1384 1385 }, 1386 1387 addScalar: function ( s ) { 1388 1389 this.x += s; 1390 this.y += s; 1391 this.z += s; 1392 this.w += s; 1393 1394 return this; 1395 1396 }, 1397 1398 addVectors: function ( a, b ) { 1399 1400 this.x = a.x + b.x; 1401 this.y = a.y + b.y; 1402 this.z = a.z + b.z; 1403 this.w = a.w + b.w; 1404 1405 return this; 1406 1407 }, 1408 1409 addScaledVector: function ( v, s ) { 1410 1411 this.x += v.x * s; 1412 this.y += v.y * s; 1413 this.z += v.z * s; 1414 this.w += v.w * s; 1415 1416 return this; 1417 1418 }, 1419 1420 sub: function ( v, w ) { 1421 1422 if ( w !== undefined ) { 1423 1424 console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); 1425 return this.subVectors( v, w ); 1426 1427 } 1428 1429 this.x -= v.x; 1430 this.y -= v.y; 1431 this.z -= v.z; 1432 this.w -= v.w; 1433 1434 return this; 1435 1436 }, 1437 1438 subScalar: function ( s ) { 1439 1440 this.x -= s; 1441 this.y -= s; 1442 this.z -= s; 1443 this.w -= s; 1444 1445 return this; 1446 1447 }, 1448 1449 subVectors: function ( a, b ) { 1450 1451 this.x = a.x - b.x; 1452 this.y = a.y - b.y; 1453 this.z = a.z - b.z; 1454 this.w = a.w - b.w; 1455 1456 return this; 1457 1458 }, 1459 1460 multiplyScalar: function ( scalar ) { 1461 1462 if ( isFinite( scalar ) ) { 1463 1464 this.x *= scalar; 1465 this.y *= scalar; 1466 this.z *= scalar; 1467 this.w *= scalar; 1468 1469 } else { 1470 1471 this.x = 0; 1472 this.y = 0; 1473 this.z = 0; 1474 this.w = 0; 1475 1476 } 1477 1478 return this; 1479 1480 }, 1481 1482 applyMatrix4: function ( m ) { 1483 1484 var x = this.x, y = this.y, z = this.z, w = this.w; 1485 var e = m.elements; 1486 1487 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; 1488 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; 1489 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; 1490 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; 1491 1492 return this; 1493 1494 }, 1495 1496 divideScalar: function ( scalar ) { 1497 1498 return this.multiplyScalar( 1 / scalar ); 1499 1500 }, 1501 1502 setAxisAngleFromQuaternion: function ( q ) { 1503 1504 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm 1505 1506 // q is assumed to be normalized 1507 1508 this.w = 2 * Math.acos( q.w ); 1509 1510 var s = Math.sqrt( 1 - q.w * q.w ); 1511 1512 if ( s < 0.0001 ) { 1513 1514 this.x = 1; 1515 this.y = 0; 1516 this.z = 0; 1517 1518 } else { 1519 1520 this.x = q.x / s; 1521 this.y = q.y / s; 1522 this.z = q.z / s; 1523 1524 } 1525 1526 return this; 1527 1528 }, 1529 1530 setAxisAngleFromRotationMatrix: function ( m ) { 1531 1532 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm 1533 1534 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 1535 1536 var angle, x, y, z, // variables for result 1537 epsilon = 0.01, // margin to allow for rounding errors 1538 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees 1539 1540 te = m.elements, 1541 1542 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 1543 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 1544 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 1545 1546 if ( ( Math.abs( m12 - m21 ) < epsilon ) && 1547 ( Math.abs( m13 - m31 ) < epsilon ) && 1548 ( Math.abs( m23 - m32 ) < epsilon ) ) { 1549 1550 // singularity found 1551 // first check for identity matrix which must have +1 for all terms 1552 // in leading diagonal and zero in other terms 1553 1554 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && 1555 ( Math.abs( m13 + m31 ) < epsilon2 ) && 1556 ( Math.abs( m23 + m32 ) < epsilon2 ) && 1557 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { 1558 1559 // this singularity is identity matrix so angle = 0 1560 1561 this.set( 1, 0, 0, 0 ); 1562 1563 return this; // zero angle, arbitrary axis 1564 1565 } 1566 1567 // otherwise this singularity is angle = 180 1568 1569 angle = Math.PI; 1570 1571 var xx = ( m11 + 1 ) / 2; 1572 var yy = ( m22 + 1 ) / 2; 1573 var zz = ( m33 + 1 ) / 2; 1574 var xy = ( m12 + m21 ) / 4; 1575 var xz = ( m13 + m31 ) / 4; 1576 var yz = ( m23 + m32 ) / 4; 1577 1578 if ( ( xx > yy ) && ( xx > zz ) ) { 1579 1580 // m11 is the largest diagonal term 1581 1582 if ( xx < epsilon ) { 1583 1584 x = 0; 1585 y = 0.707106781; 1586 z = 0.707106781; 1587 1588 } else { 1589 1590 x = Math.sqrt( xx ); 1591 y = xy / x; 1592 z = xz / x; 1593 1594 } 1595 1596 } else if ( yy > zz ) { 1597 1598 // m22 is the largest diagonal term 1599 1600 if ( yy < epsilon ) { 1601 1602 x = 0.707106781; 1603 y = 0; 1604 z = 0.707106781; 1605 1606 } else { 1607 1608 y = Math.sqrt( yy ); 1609 x = xy / y; 1610 z = yz / y; 1611 1612 } 1613 1614 } else { 1615 1616 // m33 is the largest diagonal term so base result on this 1617 1618 if ( zz < epsilon ) { 1619 1620 x = 0.707106781; 1621 y = 0.707106781; 1622 z = 0; 1623 1624 } else { 1625 1626 z = Math.sqrt( zz ); 1627 x = xz / z; 1628 y = yz / z; 1629 1630 } 1631 1632 } 1633 1634 this.set( x, y, z, angle ); 1635 1636 return this; // return 180 deg rotation 1637 1638 } 1639 1640 // as we have reached here there are no singularities so we can handle normally 1641 1642 var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + 1643 ( m13 - m31 ) * ( m13 - m31 ) + 1644 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize 1645 1646 if ( Math.abs( s ) < 0.001 ) s = 1; 1647 1648 // prevent divide by zero, should not happen if matrix is orthogonal and should be 1649 // caught by singularity test above, but I've left it in just in case 1650 1651 this.x = ( m32 - m23 ) / s; 1652 this.y = ( m13 - m31 ) / s; 1653 this.z = ( m21 - m12 ) / s; 1654 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); 1655 1656 return this; 1657 1658 }, 1659 1660 min: function ( v ) { 1661 1662 this.x = Math.min( this.x, v.x ); 1663 this.y = Math.min( this.y, v.y ); 1664 this.z = Math.min( this.z, v.z ); 1665 this.w = Math.min( this.w, v.w ); 1666 1667 return this; 1668 1669 }, 1670 1671 max: function ( v ) { 1672 1673 this.x = Math.max( this.x, v.x ); 1674 this.y = Math.max( this.y, v.y ); 1675 this.z = Math.max( this.z, v.z ); 1676 this.w = Math.max( this.w, v.w ); 1677 1678 return this; 1679 1680 }, 1681 1682 clamp: function ( min, max ) { 1683 1684 // This function assumes min < max, if this assumption isn't true it will not operate correctly 1685 1686 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 1687 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 1688 this.z = Math.max( min.z, Math.min( max.z, this.z ) ); 1689 this.w = Math.max( min.w, Math.min( max.w, this.w ) ); 1690 1691 return this; 1692 1693 }, 1694 1695 clampScalar: function () { 1696 1697 var min, max; 1698 1699 return function clampScalar( minVal, maxVal ) { 1700 1701 if ( min === undefined ) { 1702 1703 min = new Vector4(); 1704 max = new Vector4(); 1705 1706 } 1707 1708 min.set( minVal, minVal, minVal, minVal ); 1709 max.set( maxVal, maxVal, maxVal, maxVal ); 1710 1711 return this.clamp( min, max ); 1712 1713 }; 1714 1715 }(), 1716 1717 floor: function () { 1718 1719 this.x = Math.floor( this.x ); 1720 this.y = Math.floor( this.y ); 1721 this.z = Math.floor( this.z ); 1722 this.w = Math.floor( this.w ); 1723 1724 return this; 1725 1726 }, 1727 1728 ceil: function () { 1729 1730 this.x = Math.ceil( this.x ); 1731 this.y = Math.ceil( this.y ); 1732 this.z = Math.ceil( this.z ); 1733 this.w = Math.ceil( this.w ); 1734 1735 return this; 1736 1737 }, 1738 1739 round: function () { 1740 1741 this.x = Math.round( this.x ); 1742 this.y = Math.round( this.y ); 1743 this.z = Math.round( this.z ); 1744 this.w = Math.round( this.w ); 1745 1746 return this; 1747 1748 }, 1749 1750 roundToZero: function () { 1751 1752 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); 1753 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); 1754 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); 1755 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); 1756 1757 return this; 1758 1759 }, 1760 1761 negate: function () { 1762 1763 this.x = - this.x; 1764 this.y = - this.y; 1765 this.z = - this.z; 1766 this.w = - this.w; 1767 1768 return this; 1769 1770 }, 1771 1772 dot: function ( v ) { 1773 1774 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 1775 1776 }, 1777 1778 lengthSq: function () { 1779 1780 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; 1781 1782 }, 1783 1784 length: function () { 1785 1786 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); 1787 1788 }, 1789 1790 lengthManhattan: function () { 1791 1792 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); 1793 1794 }, 1795 1796 normalize: function () { 1797 1798 return this.divideScalar( this.length() ); 1799 1800 }, 1801 1802 setLength: function ( length ) { 1803 1804 return this.multiplyScalar( length / this.length() ); 1805 1806 }, 1807 1808 lerp: function ( v, alpha ) { 1809 1810 this.x += ( v.x - this.x ) * alpha; 1811 this.y += ( v.y - this.y ) * alpha; 1812 this.z += ( v.z - this.z ) * alpha; 1813 this.w += ( v.w - this.w ) * alpha; 1814 1815 return this; 1816 1817 }, 1818 1819 lerpVectors: function ( v1, v2, alpha ) { 1820 1821 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); 1822 1823 }, 1824 1825 equals: function ( v ) { 1826 1827 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); 1828 1829 }, 1830 1831 fromArray: function ( array, offset ) { 1832 1833 if ( offset === undefined ) offset = 0; 1834 1835 this.x = array[ offset ]; 1836 this.y = array[ offset + 1 ]; 1837 this.z = array[ offset + 2 ]; 1838 this.w = array[ offset + 3 ]; 1839 1840 return this; 1841 1842 }, 1843 1844 toArray: function ( array, offset ) { 1845 1846 if ( array === undefined ) array = []; 1847 if ( offset === undefined ) offset = 0; 1848 1849 array[ offset ] = this.x; 1850 array[ offset + 1 ] = this.y; 1851 array[ offset + 2 ] = this.z; 1852 array[ offset + 3 ] = this.w; 1853 1854 return array; 1855 1856 }, 1857 1858 fromBufferAttribute: function ( attribute, index, offset ) { 1859 1860 if ( offset !== undefined ) { 1861 1862 console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); 1863 1864 } 1865 1866 this.x = attribute.getX( index ); 1867 this.y = attribute.getY( index ); 1868 this.z = attribute.getZ( index ); 1869 this.w = attribute.getW( index ); 1870 1871 return this; 1872 1873 } 1874 1875 }; 1876 1877 /** 1878 * @author szimek / https://github.com/szimek/ 1879 * @author alteredq / http://alteredqualia.com/ 1880 * @author Marius Kintel / https://github.com/kintel 1881 */ 1882 1883 /* 1884 In options, we can specify: 1885 * Texture parameters for an auto-generated target texture 1886 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers 1887 */ 1888 function WebGLRenderTarget( width, height, options ) { 1889 1890 this.uuid = _Math.generateUUID(); 1891 1892 this.width = width; 1893 this.height = height; 1894 1895 this.scissor = new Vector4( 0, 0, width, height ); 1896 this.scissorTest = false; 1897 1898 this.viewport = new Vector4( 0, 0, width, height ); 1899 1900 options = options || {}; 1901 1902 if ( options.minFilter === undefined ) options.minFilter = LinearFilter; 1903 1904 this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); 1905 1906 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; 1907 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; 1908 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; 1909 1910 } 1911 1912 WebGLRenderTarget.prototype = { 1913 1914 constructor: WebGLRenderTarget, 1915 1916 isWebGLRenderTarget: true, 1917 1918 setSize: function ( width, height ) { 1919 1920 if ( this.width !== width || this.height !== height ) { 1921 1922 this.width = width; 1923 this.height = height; 1924 1925 this.dispose(); 1926 1927 } 1928 1929 this.viewport.set( 0, 0, width, height ); 1930 this.scissor.set( 0, 0, width, height ); 1931 1932 }, 1933 1934 clone: function () { 1935 1936 return new this.constructor().copy( this ); 1937 1938 }, 1939 1940 copy: function ( source ) { 1941 1942 this.width = source.width; 1943 this.height = source.height; 1944 1945 this.viewport.copy( source.viewport ); 1946 1947 this.texture = source.texture.clone(); 1948 1949 this.depthBuffer = source.depthBuffer; 1950 this.stencilBuffer = source.stencilBuffer; 1951 this.depthTexture = source.depthTexture; 1952 1953 return this; 1954 1955 }, 1956 1957 dispose: function () { 1958 1959 this.dispatchEvent( { type: 'dispose' } ); 1960 1961 } 1962 1963 }; 1964 1965 Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype ); 1966 1967 /** 1968 * @author alteredq / http://alteredqualia.com 1969 */ 1970 1971 function WebGLRenderTargetCube( width, height, options ) { 1972 1973 WebGLRenderTarget.call( this, width, height, options ); 1974 1975 this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 1976 this.activeMipMapLevel = 0; 1977 1978 } 1979 1980 WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype ); 1981 WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube; 1982 1983 WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true; 1984 1985 /** 1986 * @author mikael emtinger / http://gomo.se/ 1987 * @author alteredq / http://alteredqualia.com/ 1988 * @author WestLangley / http://github.com/WestLangley 1989 * @author bhouston / http://clara.io 1990 */ 1991 1992 function Quaternion( x, y, z, w ) { 1993 1994 this._x = x || 0; 1995 this._y = y || 0; 1996 this._z = z || 0; 1997 this._w = ( w !== undefined ) ? w : 1; 1998 1999 } 2000 2001 Quaternion.prototype = { 2002 2003 constructor: Quaternion, 2004 2005 get x () { 2006 2007 return this._x; 2008 2009 }, 2010 2011 set x ( value ) { 2012 2013 this._x = value; 2014 this.onChangeCallback(); 2015 2016 }, 2017 2018 get y () { 2019 2020 return this._y; 2021 2022 }, 2023 2024 set y ( value ) { 2025 2026 this._y = value; 2027 this.onChangeCallback(); 2028 2029 }, 2030 2031 get z () { 2032 2033 return this._z; 2034 2035 }, 2036 2037 set z ( value ) { 2038 2039 this._z = value; 2040 this.onChangeCallback(); 2041 2042 }, 2043 2044 get w () { 2045 2046 return this._w; 2047 2048 }, 2049 2050 set w ( value ) { 2051 2052 this._w = value; 2053 this.onChangeCallback(); 2054 2055 }, 2056 2057 set: function ( x, y, z, w ) { 2058 2059 this._x = x; 2060 this._y = y; 2061 this._z = z; 2062 this._w = w; 2063 2064 this.onChangeCallback(); 2065 2066 return this; 2067 2068 }, 2069 2070 clone: function () { 2071 2072 return new this.constructor( this._x, this._y, this._z, this._w ); 2073 2074 }, 2075 2076 copy: function ( quaternion ) { 2077 2078 this._x = quaternion.x; 2079 this._y = quaternion.y; 2080 this._z = quaternion.z; 2081 this._w = quaternion.w; 2082 2083 this.onChangeCallback(); 2084 2085 return this; 2086 2087 }, 2088 2089 setFromEuler: function ( euler, update ) { 2090 2091 if ( (euler && euler.isEuler) === false ) { 2092 2093 throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); 2094 2095 } 2096 2097 // http://www.mathworks.com/matlabcentral/fileexchange/ 2098 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ 2099 // content/SpinCalc.m 2100 2101 var c1 = Math.cos( euler._x / 2 ); 2102 var c2 = Math.cos( euler._y / 2 ); 2103 var c3 = Math.cos( euler._z / 2 ); 2104 var s1 = Math.sin( euler._x / 2 ); 2105 var s2 = Math.sin( euler._y / 2 ); 2106 var s3 = Math.sin( euler._z / 2 ); 2107 2108 var order = euler.order; 2109 2110 if ( order === 'XYZ' ) { 2111 2112 this._x = s1 * c2 * c3 + c1 * s2 * s3; 2113 this._y = c1 * s2 * c3 - s1 * c2 * s3; 2114 this._z = c1 * c2 * s3 + s1 * s2 * c3; 2115 this._w = c1 * c2 * c3 - s1 * s2 * s3; 2116 2117 } else if ( order === 'YXZ' ) { 2118 2119 this._x = s1 * c2 * c3 + c1 * s2 * s3; 2120 this._y = c1 * s2 * c3 - s1 * c2 * s3; 2121 this._z = c1 * c2 * s3 - s1 * s2 * c3; 2122 this._w = c1 * c2 * c3 + s1 * s2 * s3; 2123 2124 } else if ( order === 'ZXY' ) { 2125 2126 this._x = s1 * c2 * c3 - c1 * s2 * s3; 2127 this._y = c1 * s2 * c3 + s1 * c2 * s3; 2128 this._z = c1 * c2 * s3 + s1 * s2 * c3; 2129 this._w = c1 * c2 * c3 - s1 * s2 * s3; 2130 2131 } else if ( order === 'ZYX' ) { 2132 2133 this._x = s1 * c2 * c3 - c1 * s2 * s3; 2134 this._y = c1 * s2 * c3 + s1 * c2 * s3; 2135 this._z = c1 * c2 * s3 - s1 * s2 * c3; 2136 this._w = c1 * c2 * c3 + s1 * s2 * s3; 2137 2138 } else if ( order === 'YZX' ) { 2139 2140 this._x = s1 * c2 * c3 + c1 * s2 * s3; 2141 this._y = c1 * s2 * c3 + s1 * c2 * s3; 2142 this._z = c1 * c2 * s3 - s1 * s2 * c3; 2143 this._w = c1 * c2 * c3 - s1 * s2 * s3; 2144 2145 } else if ( order === 'XZY' ) { 2146 2147 this._x = s1 * c2 * c3 - c1 * s2 * s3; 2148 this._y = c1 * s2 * c3 - s1 * c2 * s3; 2149 this._z = c1 * c2 * s3 + s1 * s2 * c3; 2150 this._w = c1 * c2 * c3 + s1 * s2 * s3; 2151 2152 } 2153 2154 if ( update !== false ) this.onChangeCallback(); 2155 2156 return this; 2157 2158 }, 2159 2160 setFromAxisAngle: function ( axis, angle ) { 2161 2162 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 2163 2164 // assumes axis is normalized 2165 2166 var halfAngle = angle / 2, s = Math.sin( halfAngle ); 2167 2168 this._x = axis.x * s; 2169 this._y = axis.y * s; 2170 this._z = axis.z * s; 2171 this._w = Math.cos( halfAngle ); 2172 2173 this.onChangeCallback(); 2174 2175 return this; 2176 2177 }, 2178 2179 setFromRotationMatrix: function ( m ) { 2180 2181 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm 2182 2183 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 2184 2185 var te = m.elements, 2186 2187 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 2188 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 2189 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], 2190 2191 trace = m11 + m22 + m33, 2192 s; 2193 2194 if ( trace > 0 ) { 2195 2196 s = 0.5 / Math.sqrt( trace + 1.0 ); 2197 2198 this._w = 0.25 / s; 2199 this._x = ( m32 - m23 ) * s; 2200 this._y = ( m13 - m31 ) * s; 2201 this._z = ( m21 - m12 ) * s; 2202 2203 } else if ( m11 > m22 && m11 > m33 ) { 2204 2205 s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); 2206 2207 this._w = ( m32 - m23 ) / s; 2208 this._x = 0.25 * s; 2209 this._y = ( m12 + m21 ) / s; 2210 this._z = ( m13 + m31 ) / s; 2211 2212 } else if ( m22 > m33 ) { 2213 2214 s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); 2215 2216 this._w = ( m13 - m31 ) / s; 2217 this._x = ( m12 + m21 ) / s; 2218 this._y = 0.25 * s; 2219 this._z = ( m23 + m32 ) / s; 2220 2221 } else { 2222 2223 s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); 2224 2225 this._w = ( m21 - m12 ) / s; 2226 this._x = ( m13 + m31 ) / s; 2227 this._y = ( m23 + m32 ) / s; 2228 this._z = 0.25 * s; 2229 2230 } 2231 2232 this.onChangeCallback(); 2233 2234 return this; 2235 2236 }, 2237 2238 setFromUnitVectors: function () { 2239 2240 // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final 2241 2242 // assumes direction vectors vFrom and vTo are normalized 2243 2244 var v1, r; 2245 2246 var EPS = 0.000001; 2247 2248 return function setFromUnitVectors( vFrom, vTo ) { 2249 2250 if ( v1 === undefined ) v1 = new Vector3(); 2251 2252 r = vFrom.dot( vTo ) + 1; 2253 2254 if ( r < EPS ) { 2255 2256 r = 0; 2257 2258 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { 2259 2260 v1.set( - vFrom.y, vFrom.x, 0 ); 2261 2262 } else { 2263 2264 v1.set( 0, - vFrom.z, vFrom.y ); 2265 2266 } 2267 2268 } else { 2269 2270 v1.crossVectors( vFrom, vTo ); 2271 2272 } 2273 2274 this._x = v1.x; 2275 this._y = v1.y; 2276 this._z = v1.z; 2277 this._w = r; 2278 2279 return this.normalize(); 2280 2281 }; 2282 2283 }(), 2284 2285 inverse: function () { 2286 2287 return this.conjugate().normalize(); 2288 2289 }, 2290 2291 conjugate: function () { 2292 2293 this._x *= - 1; 2294 this._y *= - 1; 2295 this._z *= - 1; 2296 2297 this.onChangeCallback(); 2298 2299 return this; 2300 2301 }, 2302 2303 dot: function ( v ) { 2304 2305 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; 2306 2307 }, 2308 2309 lengthSq: function () { 2310 2311 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; 2312 2313 }, 2314 2315 length: function () { 2316 2317 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); 2318 2319 }, 2320 2321 normalize: function () { 2322 2323 var l = this.length(); 2324 2325 if ( l === 0 ) { 2326 2327 this._x = 0; 2328 this._y = 0; 2329 this._z = 0; 2330 this._w = 1; 2331 2332 } else { 2333 2334 l = 1 / l; 2335 2336 this._x = this._x * l; 2337 this._y = this._y * l; 2338 this._z = this._z * l; 2339 this._w = this._w * l; 2340 2341 } 2342 2343 this.onChangeCallback(); 2344 2345 return this; 2346 2347 }, 2348 2349 multiply: function ( q, p ) { 2350 2351 if ( p !== undefined ) { 2352 2353 console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); 2354 return this.multiplyQuaternions( q, p ); 2355 2356 } 2357 2358 return this.multiplyQuaternions( this, q ); 2359 2360 }, 2361 2362 premultiply: function ( q ) { 2363 2364 return this.multiplyQuaternions( q, this ); 2365 2366 }, 2367 2368 multiplyQuaternions: function ( a, b ) { 2369 2370 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm 2371 2372 var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; 2373 var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; 2374 2375 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; 2376 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; 2377 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; 2378 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; 2379 2380 this.onChangeCallback(); 2381 2382 return this; 2383 2384 }, 2385 2386 slerp: function ( qb, t ) { 2387 2388 if ( t === 0 ) return this; 2389 if ( t === 1 ) return this.copy( qb ); 2390 2391 var x = this._x, y = this._y, z = this._z, w = this._w; 2392 2393 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ 2394 2395 var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; 2396 2397 if ( cosHalfTheta < 0 ) { 2398 2399 this._w = - qb._w; 2400 this._x = - qb._x; 2401 this._y = - qb._y; 2402 this._z = - qb._z; 2403 2404 cosHalfTheta = - cosHalfTheta; 2405 2406 } else { 2407 2408 this.copy( qb ); 2409 2410 } 2411 2412 if ( cosHalfTheta >= 1.0 ) { 2413 2414 this._w = w; 2415 this._x = x; 2416 this._y = y; 2417 this._z = z; 2418 2419 return this; 2420 2421 } 2422 2423 var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); 2424 2425 if ( Math.abs( sinHalfTheta ) < 0.001 ) { 2426 2427 this._w = 0.5 * ( w + this._w ); 2428 this._x = 0.5 * ( x + this._x ); 2429 this._y = 0.5 * ( y + this._y ); 2430 this._z = 0.5 * ( z + this._z ); 2431 2432 return this; 2433 2434 } 2435 2436 var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); 2437 var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, 2438 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; 2439 2440 this._w = ( w * ratioA + this._w * ratioB ); 2441 this._x = ( x * ratioA + this._x * ratioB ); 2442 this._y = ( y * ratioA + this._y * ratioB ); 2443 this._z = ( z * ratioA + this._z * ratioB ); 2444 2445 this.onChangeCallback(); 2446 2447 return this; 2448 2449 }, 2450 2451 equals: function ( quaternion ) { 2452 2453 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); 2454 2455 }, 2456 2457 fromArray: function ( array, offset ) { 2458 2459 if ( offset === undefined ) offset = 0; 2460 2461 this._x = array[ offset ]; 2462 this._y = array[ offset + 1 ]; 2463 this._z = array[ offset + 2 ]; 2464 this._w = array[ offset + 3 ]; 2465 2466 this.onChangeCallback(); 2467 2468 return this; 2469 2470 }, 2471 2472 toArray: function ( array, offset ) { 2473 2474 if ( array === undefined ) array = []; 2475 if ( offset === undefined ) offset = 0; 2476 2477 array[ offset ] = this._x; 2478 array[ offset + 1 ] = this._y; 2479 array[ offset + 2 ] = this._z; 2480 array[ offset + 3 ] = this._w; 2481 2482 return array; 2483 2484 }, 2485 2486 onChange: function ( callback ) { 2487 2488 this.onChangeCallback = callback; 2489 2490 return this; 2491 2492 }, 2493 2494 onChangeCallback: function () {} 2495 2496 }; 2497 2498 Object.assign( Quaternion, { 2499 2500 slerp: function( qa, qb, qm, t ) { 2501 2502 return qm.copy( qa ).slerp( qb, t ); 2503 2504 }, 2505 2506 slerpFlat: function( 2507 dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { 2508 2509 // fuzz-free, array-based Quaternion SLERP operation 2510 2511 var x0 = src0[ srcOffset0 + 0 ], 2512 y0 = src0[ srcOffset0 + 1 ], 2513 z0 = src0[ srcOffset0 + 2 ], 2514 w0 = src0[ srcOffset0 + 3 ], 2515 2516 x1 = src1[ srcOffset1 + 0 ], 2517 y1 = src1[ srcOffset1 + 1 ], 2518 z1 = src1[ srcOffset1 + 2 ], 2519 w1 = src1[ srcOffset1 + 3 ]; 2520 2521 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { 2522 2523 var s = 1 - t, 2524 2525 cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, 2526 2527 dir = ( cos >= 0 ? 1 : - 1 ), 2528 sqrSin = 1 - cos * cos; 2529 2530 // Skip the Slerp for tiny steps to avoid numeric problems: 2531 if ( sqrSin > Number.EPSILON ) { 2532 2533 var sin = Math.sqrt( sqrSin ), 2534 len = Math.atan2( sin, cos * dir ); 2535 2536 s = Math.sin( s * len ) / sin; 2537 t = Math.sin( t * len ) / sin; 2538 2539 } 2540 2541 var tDir = t * dir; 2542 2543 x0 = x0 * s + x1 * tDir; 2544 y0 = y0 * s + y1 * tDir; 2545 z0 = z0 * s + z1 * tDir; 2546 w0 = w0 * s + w1 * tDir; 2547 2548 // Normalize in case we just did a lerp: 2549 if ( s === 1 - t ) { 2550 2551 var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); 2552 2553 x0 *= f; 2554 y0 *= f; 2555 z0 *= f; 2556 w0 *= f; 2557 2558 } 2559 2560 } 2561 2562 dst[ dstOffset ] = x0; 2563 dst[ dstOffset + 1 ] = y0; 2564 dst[ dstOffset + 2 ] = z0; 2565 dst[ dstOffset + 3 ] = w0; 2566 2567 } 2568 2569 } ); 2570 2571 /** 2572 * @author mrdoob / http://mrdoob.com/ 2573 * @author *kile / http://kile.stravaganza.org/ 2574 * @author philogb / http://blog.thejit.org/ 2575 * @author mikael emtinger / http://gomo.se/ 2576 * @author egraether / http://egraether.com/ 2577 * @author WestLangley / http://github.com/WestLangley 2578 */ 2579 2580 function Vector3( x, y, z ) { 2581 2582 this.x = x || 0; 2583 this.y = y || 0; 2584 this.z = z || 0; 2585 2586 } 2587 2588 Vector3.prototype = { 2589 2590 constructor: Vector3, 2591 2592 isVector3: true, 2593 2594 set: function ( x, y, z ) { 2595 2596 this.x = x; 2597 this.y = y; 2598 this.z = z; 2599 2600 return this; 2601 2602 }, 2603 2604 setScalar: function ( scalar ) { 2605 2606 this.x = scalar; 2607 this.y = scalar; 2608 this.z = scalar; 2609 2610 return this; 2611 2612 }, 2613 2614 setX: function ( x ) { 2615 2616 this.x = x; 2617 2618 return this; 2619 2620 }, 2621 2622 setY: function ( y ) { 2623 2624 this.y = y; 2625 2626 return this; 2627 2628 }, 2629 2630 setZ: function ( z ) { 2631 2632 this.z = z; 2633 2634 return this; 2635 2636 }, 2637 2638 setComponent: function ( index, value ) { 2639 2640 switch ( index ) { 2641 2642 case 0: this.x = value; break; 2643 case 1: this.y = value; break; 2644 case 2: this.z = value; break; 2645 default: throw new Error( 'index is out of range: ' + index ); 2646 2647 } 2648 2649 return this; 2650 2651 }, 2652 2653 getComponent: function ( index ) { 2654 2655 switch ( index ) { 2656 2657 case 0: return this.x; 2658 case 1: return this.y; 2659 case 2: return this.z; 2660 default: throw new Error( 'index is out of range: ' + index ); 2661 2662 } 2663 2664 }, 2665 2666 clone: function () { 2667 2668 return new this.constructor( this.x, this.y, this.z ); 2669 2670 }, 2671 2672 copy: function ( v ) { 2673 2674 this.x = v.x; 2675 this.y = v.y; 2676 this.z = v.z; 2677 2678 return this; 2679 2680 }, 2681 2682 add: function ( v, w ) { 2683 2684 if ( w !== undefined ) { 2685 2686 console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); 2687 return this.addVectors( v, w ); 2688 2689 } 2690 2691 this.x += v.x; 2692 this.y += v.y; 2693 this.z += v.z; 2694 2695 return this; 2696 2697 }, 2698 2699 addScalar: function ( s ) { 2700 2701 this.x += s; 2702 this.y += s; 2703 this.z += s; 2704 2705 return this; 2706 2707 }, 2708 2709 addVectors: function ( a, b ) { 2710 2711 this.x = a.x + b.x; 2712 this.y = a.y + b.y; 2713 this.z = a.z + b.z; 2714 2715 return this; 2716 2717 }, 2718 2719 addScaledVector: function ( v, s ) { 2720 2721 this.x += v.x * s; 2722 this.y += v.y * s; 2723 this.z += v.z * s; 2724 2725 return this; 2726 2727 }, 2728 2729 sub: function ( v, w ) { 2730 2731 if ( w !== undefined ) { 2732 2733 console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); 2734 return this.subVectors( v, w ); 2735 2736 } 2737 2738 this.x -= v.x; 2739 this.y -= v.y; 2740 this.z -= v.z; 2741 2742 return this; 2743 2744 }, 2745 2746 subScalar: function ( s ) { 2747 2748 this.x -= s; 2749 this.y -= s; 2750 this.z -= s; 2751 2752 return this; 2753 2754 }, 2755 2756 subVectors: function ( a, b ) { 2757 2758 this.x = a.x - b.x; 2759 this.y = a.y - b.y; 2760 this.z = a.z - b.z; 2761 2762 return this; 2763 2764 }, 2765 2766 multiply: function ( v, w ) { 2767 2768 if ( w !== undefined ) { 2769 2770 console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); 2771 return this.multiplyVectors( v, w ); 2772 2773 } 2774 2775 this.x *= v.x; 2776 this.y *= v.y; 2777 this.z *= v.z; 2778 2779 return this; 2780 2781 }, 2782 2783 multiplyScalar: function ( scalar ) { 2784 2785 if ( isFinite( scalar ) ) { 2786 2787 this.x *= scalar; 2788 this.y *= scalar; 2789 this.z *= scalar; 2790 2791 } else { 2792 2793 this.x = 0; 2794 this.y = 0; 2795 this.z = 0; 2796 2797 } 2798 2799 return this; 2800 2801 }, 2802 2803 multiplyVectors: function ( a, b ) { 2804 2805 this.x = a.x * b.x; 2806 this.y = a.y * b.y; 2807 this.z = a.z * b.z; 2808 2809 return this; 2810 2811 }, 2812 2813 applyEuler: function () { 2814 2815 var quaternion; 2816 2817 return function applyEuler( euler ) { 2818 2819 if ( (euler && euler.isEuler) === false ) { 2820 2821 console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); 2822 2823 } 2824 2825 if ( quaternion === undefined ) quaternion = new Quaternion(); 2826 2827 return this.applyQuaternion( quaternion.setFromEuler( euler ) ); 2828 2829 }; 2830 2831 }(), 2832 2833 applyAxisAngle: function () { 2834 2835 var quaternion; 2836 2837 return function applyAxisAngle( axis, angle ) { 2838 2839 if ( quaternion === undefined ) quaternion = new Quaternion(); 2840 2841 return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); 2842 2843 }; 2844 2845 }(), 2846 2847 applyMatrix3: function ( m ) { 2848 2849 var x = this.x, y = this.y, z = this.z; 2850 var e = m.elements; 2851 2852 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; 2853 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; 2854 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; 2855 2856 return this; 2857 2858 }, 2859 2860 applyMatrix4: function ( m ) { 2861 2862 var x = this.x, y = this.y, z = this.z; 2863 var e = m.elements; 2864 2865 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ]; 2866 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ]; 2867 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ]; 2868 var w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ]; 2869 2870 return this.divideScalar( w ); 2871 2872 }, 2873 2874 applyQuaternion: function ( q ) { 2875 2876 var x = this.x, y = this.y, z = this.z; 2877 var qx = q.x, qy = q.y, qz = q.z, qw = q.w; 2878 2879 // calculate quat * vector 2880 2881 var ix = qw * x + qy * z - qz * y; 2882 var iy = qw * y + qz * x - qx * z; 2883 var iz = qw * z + qx * y - qy * x; 2884 var iw = - qx * x - qy * y - qz * z; 2885 2886 // calculate result * inverse quat 2887 2888 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; 2889 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; 2890 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; 2891 2892 return this; 2893 2894 }, 2895 2896 project: function () { 2897 2898 var matrix; 2899 2900 return function project( camera ) { 2901 2902 if ( matrix === undefined ) matrix = new Matrix4(); 2903 2904 matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); 2905 return this.applyMatrix4( matrix ); 2906 2907 }; 2908 2909 }(), 2910 2911 unproject: function () { 2912 2913 var matrix; 2914 2915 return function unproject( camera ) { 2916 2917 if ( matrix === undefined ) matrix = new Matrix4(); 2918 2919 matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); 2920 return this.applyMatrix4( matrix ); 2921 2922 }; 2923 2924 }(), 2925 2926 transformDirection: function ( m ) { 2927 2928 // input: THREE.Matrix4 affine matrix 2929 // vector interpreted as a direction 2930 2931 var x = this.x, y = this.y, z = this.z; 2932 var e = m.elements; 2933 2934 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; 2935 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; 2936 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; 2937 2938 return this.normalize(); 2939 2940 }, 2941 2942 divide: function ( v ) { 2943 2944 this.x /= v.x; 2945 this.y /= v.y; 2946 this.z /= v.z; 2947 2948 return this; 2949 2950 }, 2951 2952 divideScalar: function ( scalar ) { 2953 2954 return this.multiplyScalar( 1 / scalar ); 2955 2956 }, 2957 2958 min: function ( v ) { 2959 2960 this.x = Math.min( this.x, v.x ); 2961 this.y = Math.min( this.y, v.y ); 2962 this.z = Math.min( this.z, v.z ); 2963 2964 return this; 2965 2966 }, 2967 2968 max: function ( v ) { 2969 2970 this.x = Math.max( this.x, v.x ); 2971 this.y = Math.max( this.y, v.y ); 2972 this.z = Math.max( this.z, v.z ); 2973 2974 return this; 2975 2976 }, 2977 2978 clamp: function ( min, max ) { 2979 2980 // This function assumes min < max, if this assumption isn't true it will not operate correctly 2981 2982 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 2983 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 2984 this.z = Math.max( min.z, Math.min( max.z, this.z ) ); 2985 2986 return this; 2987 2988 }, 2989 2990 clampScalar: function () { 2991 2992 var min, max; 2993 2994 return function clampScalar( minVal, maxVal ) { 2995 2996 if ( min === undefined ) { 2997 2998 min = new Vector3(); 2999 max = new Vector3(); 3000 3001 } 3002 3003 min.set( minVal, minVal, minVal ); 3004 max.set( maxVal, maxVal, maxVal ); 3005 3006 return this.clamp( min, max ); 3007 3008 }; 3009 3010 }(), 3011 3012 clampLength: function ( min, max ) { 3013 3014 var length = this.length(); 3015 3016 return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); 3017 3018 }, 3019 3020 floor: function () { 3021 3022 this.x = Math.floor( this.x ); 3023 this.y = Math.floor( this.y ); 3024 this.z = Math.floor( this.z ); 3025 3026 return this; 3027 3028 }, 3029 3030 ceil: function () { 3031 3032 this.x = Math.ceil( this.x ); 3033 this.y = Math.ceil( this.y ); 3034 this.z = Math.ceil( this.z ); 3035 3036 return this; 3037 3038 }, 3039 3040 round: function () { 3041 3042 this.x = Math.round( this.x ); 3043 this.y = Math.round( this.y ); 3044 this.z = Math.round( this.z ); 3045 3046 return this; 3047 3048 }, 3049 3050 roundToZero: function () { 3051 3052 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); 3053 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); 3054 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); 3055 3056 return this; 3057 3058 }, 3059 3060 negate: function () { 3061 3062 this.x = - this.x; 3063 this.y = - this.y; 3064 this.z = - this.z; 3065 3066 return this; 3067 3068 }, 3069 3070 dot: function ( v ) { 3071 3072 return this.x * v.x + this.y * v.y + this.z * v.z; 3073 3074 }, 3075 3076 lengthSq: function () { 3077 3078 return this.x * this.x + this.y * this.y + this.z * this.z; 3079 3080 }, 3081 3082 length: function () { 3083 3084 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); 3085 3086 }, 3087 3088 lengthManhattan: function () { 3089 3090 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); 3091 3092 }, 3093 3094 normalize: function () { 3095 3096 return this.divideScalar( this.length() ); 3097 3098 }, 3099 3100 setLength: function ( length ) { 3101 3102 return this.multiplyScalar( length / this.length() ); 3103 3104 }, 3105 3106 lerp: function ( v, alpha ) { 3107 3108 this.x += ( v.x - this.x ) * alpha; 3109 this.y += ( v.y - this.y ) * alpha; 3110 this.z += ( v.z - this.z ) * alpha; 3111 3112 return this; 3113 3114 }, 3115 3116 lerpVectors: function ( v1, v2, alpha ) { 3117 3118 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); 3119 3120 }, 3121 3122 cross: function ( v, w ) { 3123 3124 if ( w !== undefined ) { 3125 3126 console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); 3127 return this.crossVectors( v, w ); 3128 3129 } 3130 3131 var x = this.x, y = this.y, z = this.z; 3132 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; 3136 3137 return this; 3138 3139 }, 3140 3141 crossVectors: function ( a, b ) { 3142 3143 var ax = a.x, ay = a.y, az = a.z; 3144 var bx = b.x, by = b.y, bz = b.z; 3145 3146 this.x = ay * bz - az * by; 3147 this.y = az * bx - ax * bz; 3148 this.z = ax * by - ay * bx; 3149 3150 return this; 3151 3152 }, 3153 3154 projectOnVector: function ( vector ) { 3155 3156 var scalar = vector.dot( this ) / vector.lengthSq(); 3157 3158 return this.copy( vector ).multiplyScalar( scalar ); 3159 3160 }, 3161 3162 projectOnPlane: function () { 3163 3164 var v1; 3165 3166 return function projectOnPlane( planeNormal ) { 3167 3168 if ( v1 === undefined ) v1 = new Vector3(); 3169 3170 v1.copy( this ).projectOnVector( planeNormal ); 3171 3172 return this.sub( v1 ); 3173 3174 }; 3175 3176 }(), 3177 3178 reflect: function () { 3179 3180 // reflect incident vector off plane orthogonal to normal 3181 // normal is assumed to have unit length 3182 3183 var v1; 3184 3185 return function reflect( normal ) { 3186 3187 if ( v1 === undefined ) v1 = new Vector3(); 3188 3189 return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); 3190 3191 }; 3192 3193 }(), 3194 3195 angleTo: function ( v ) { 3196 3197 var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); 3198 3199 // clamp, to handle numerical problems 3200 3201 return Math.acos( _Math.clamp( theta, - 1, 1 ) ); 3202 3203 }, 3204 3205 distanceTo: function ( v ) { 3206 3207 return Math.sqrt( this.distanceToSquared( v ) ); 3208 3209 }, 3210 3211 distanceToSquared: function ( v ) { 3212 3213 var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; 3214 3215 return dx * dx + dy * dy + dz * dz; 3216 3217 }, 3218 3219 distanceToManhattan: function ( v ) { 3220 3221 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); 3222 3223 }, 3224 3225 setFromSpherical: function( s ) { 3226 3227 var sinPhiRadius = Math.sin( s.phi ) * s.radius; 3228 3229 this.x = sinPhiRadius * Math.sin( s.theta ); 3230 this.y = Math.cos( s.phi ) * s.radius; 3231 this.z = sinPhiRadius * Math.cos( s.theta ); 3232 3233 return this; 3234 3235 }, 3236 3237 setFromCylindrical: function( c ) { 3238 3239 this.x = c.radius * Math.sin( c.theta ); 3240 this.y = c.y; 3241 this.z = c.radius * Math.cos( c.theta ); 3242 3243 return this; 3244 3245 }, 3246 3247 setFromMatrixPosition: function ( m ) { 3248 3249 return this.setFromMatrixColumn( m, 3 ); 3250 3251 }, 3252 3253 setFromMatrixScale: function ( m ) { 3254 3255 var sx = this.setFromMatrixColumn( m, 0 ).length(); 3256 var sy = this.setFromMatrixColumn( m, 1 ).length(); 3257 var sz = this.setFromMatrixColumn( m, 2 ).length(); 3258 3259 this.x = sx; 3260 this.y = sy; 3261 this.z = sz; 3262 3263 return this; 3264 3265 }, 3266 3267 setFromMatrixColumn: function ( m, index ) { 3268 3269 if ( typeof m === 'number' ) { 3270 3271 console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' ); 3272 var temp = m; 3273 m = index; 3274 index = temp; 3275 3276 } 3277 3278 return this.fromArray( m.elements, index * 4 ); 3279 3280 }, 3281 3282 equals: function ( v ) { 3283 3284 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); 3285 3286 }, 3287 3288 fromArray: function ( array, offset ) { 3289 3290 if ( offset === undefined ) offset = 0; 3291 3292 this.x = array[ offset ]; 3293 this.y = array[ offset + 1 ]; 3294 this.z = array[ offset + 2 ]; 3295 3296 return this; 3297 3298 }, 3299 3300 toArray: function ( array, offset ) { 3301 3302 if ( array === undefined ) array = []; 3303 if ( offset === undefined ) offset = 0; 3304 3305 array[ offset ] = this.x; 3306 array[ offset + 1 ] = this.y; 3307 array[ offset + 2 ] = this.z; 3308 3309 return array; 3310 3311 }, 3312 3313 fromBufferAttribute: function ( attribute, index, offset ) { 3314 3315 if ( offset !== undefined ) { 3316 3317 console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); 3318 3319 } 3320 3321 this.x = attribute.getX( index ); 3322 this.y = attribute.getY( index ); 3323 this.z = attribute.getZ( index ); 3324 3325 return this; 3326 3327 } 3328 3329 }; 3330 3331 /** 3332 * @author mrdoob / http://mrdoob.com/ 3333 * @author supereggbert / http://www.paulbrunt.co.uk/ 3334 * @author philogb / http://blog.thejit.org/ 3335 * @author jordi_ros / http://plattsoft.com 3336 * @author D1plo1d / http://github.com/D1plo1d 3337 * @author alteredq / http://alteredqualia.com/ 3338 * @author mikael emtinger / http://gomo.se/ 3339 * @author timknip / http://www.floorplanner.com/ 3340 * @author bhouston / http://clara.io 3341 * @author WestLangley / http://github.com/WestLangley 3342 */ 3343 3344 function Matrix4() { 3345 3346 this.elements = new Float32Array( [ 3347 3348 1, 0, 0, 0, 3349 0, 1, 0, 0, 3350 0, 0, 1, 0, 3351 0, 0, 0, 1 3352 3353 ] ); 3354 3355 if ( arguments.length > 0 ) { 3356 3357 console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); 3358 3359 } 3360 3361 } 3362 3363 Matrix4.prototype = { 3364 3365 constructor: Matrix4, 3366 3367 isMatrix4: true, 3368 3369 set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 3370 3371 var te = this.elements; 3372 3373 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; 3374 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; 3375 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; 3376 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; 3377 3378 return this; 3379 3380 }, 3381 3382 identity: function () { 3383 3384 this.set( 3385 3386 1, 0, 0, 0, 3387 0, 1, 0, 0, 3388 0, 0, 1, 0, 3389 0, 0, 0, 1 3390 3391 ); 3392 3393 return this; 3394 3395 }, 3396 3397 clone: function () { 3398 3399 return new Matrix4().fromArray( this.elements ); 3400 3401 }, 3402 3403 copy: function ( m ) { 3404 3405 this.elements.set( m.elements ); 3406 3407 return this; 3408 3409 }, 3410 3411 copyPosition: function ( m ) { 3412 3413 var te = this.elements; 3414 var me = m.elements; 3415 3416 te[ 12 ] = me[ 12 ]; 3417 te[ 13 ] = me[ 13 ]; 3418 te[ 14 ] = me[ 14 ]; 3419 3420 return this; 3421 3422 }, 3423 3424 extractBasis: function ( xAxis, yAxis, zAxis ) { 3425 3426 xAxis.setFromMatrixColumn( this, 0 ); 3427 yAxis.setFromMatrixColumn( this, 1 ); 3428 zAxis.setFromMatrixColumn( this, 2 ); 3429 3430 return this; 3431 3432 }, 3433 3434 makeBasis: function ( xAxis, yAxis, zAxis ) { 3435 3436 this.set( 3437 xAxis.x, yAxis.x, zAxis.x, 0, 3438 xAxis.y, yAxis.y, zAxis.y, 0, 3439 xAxis.z, yAxis.z, zAxis.z, 0, 3440 0, 0, 0, 1 3441 ); 3442 3443 return this; 3444 3445 }, 3446 3447 extractRotation: function () { 3448 3449 var v1; 3450 3451 return function extractRotation( m ) { 3452 3453 if ( v1 === undefined ) v1 = new Vector3(); 3454 3455 var te = this.elements; 3456 var me = m.elements; 3457 3458 var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length(); 3459 var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length(); 3460 var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length(); 3461 3462 te[ 0 ] = me[ 0 ] * scaleX; 3463 te[ 1 ] = me[ 1 ] * scaleX; 3464 te[ 2 ] = me[ 2 ] * scaleX; 3465 3466 te[ 4 ] = me[ 4 ] * scaleY; 3467 te[ 5 ] = me[ 5 ] * scaleY; 3468 te[ 6 ] = me[ 6 ] * scaleY; 3469 3470 te[ 8 ] = me[ 8 ] * scaleZ; 3471 te[ 9 ] = me[ 9 ] * scaleZ; 3472 te[ 10 ] = me[ 10 ] * scaleZ; 3473 3474 return this; 3475 3476 }; 3477 3478 }(), 3479 3480 makeRotationFromEuler: function ( euler ) { 3481 3482 if ( (euler && euler.isEuler) === false ) { 3483 3484 console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); 3485 3486 } 3487 3488 var te = this.elements; 3489 3490 var x = euler.x, y = euler.y, z = euler.z; 3491 var a = Math.cos( x ), b = Math.sin( x ); 3492 var c = Math.cos( y ), d = Math.sin( y ); 3493 var e = Math.cos( z ), f = Math.sin( z ); 3494 3495 if ( euler.order === 'XYZ' ) { 3496 3497 var ae = a * e, af = a * f, be = b * e, bf = b * f; 3498 3499 te[ 0 ] = c * e; 3500 te[ 4 ] = - c * f; 3501 te[ 8 ] = d; 3502 3503 te[ 1 ] = af + be * d; 3504 te[ 5 ] = ae - bf * d; 3505 te[ 9 ] = - b * c; 3506 3507 te[ 2 ] = bf - ae * d; 3508 te[ 6 ] = be + af * d; 3509 te[ 10 ] = a * c; 3510 3511 } else if ( euler.order === 'YXZ' ) { 3512 3513 var ce = c * e, cf = c * f, de = d * e, df = d * f; 3514 3515 te[ 0 ] = ce + df * b; 3516 te[ 4 ] = de * b - cf; 3517 te[ 8 ] = a * d; 3518 3519 te[ 1 ] = a * f; 3520 te[ 5 ] = a * e; 3521 te[ 9 ] = - b; 3522 3523 te[ 2 ] = cf * b - de; 3524 te[ 6 ] = df + ce * b; 3525 te[ 10 ] = a * c; 3526 3527 } else if ( euler.order === 'ZXY' ) { 3528 3529 var ce = c * e, cf = c * f, de = d * e, df = d * f; 3530 3531 te[ 0 ] = ce - df * b; 3532 te[ 4 ] = - a * f; 3533 te[ 8 ] = de + cf * b; 3534 3535 te[ 1 ] = cf + de * b; 3536 te[ 5 ] = a * e; 3537 te[ 9 ] = df - ce * b; 3538 3539 te[ 2 ] = - a * d; 3540 te[ 6 ] = b; 3541 te[ 10 ] = a * c; 3542 3543 } else if ( euler.order === 'ZYX' ) { 3544 3545 var ae = a * e, af = a * f, be = b * e, bf = b * f; 3546 3547 te[ 0 ] = c * e; 3548 te[ 4 ] = be * d - af; 3549 te[ 8 ] = ae * d + bf; 3550 3551 te[ 1 ] = c * f; 3552 te[ 5 ] = bf * d + ae; 3553 te[ 9 ] = af * d - be; 3554 3555 te[ 2 ] = - d; 3556 te[ 6 ] = b * c; 3557 te[ 10 ] = a * c; 3558 3559 } else if ( euler.order === 'YZX' ) { 3560 3561 var ac = a * c, ad = a * d, bc = b * c, bd = b * d; 3562 3563 te[ 0 ] = c * e; 3564 te[ 4 ] = bd - ac * f; 3565 te[ 8 ] = bc * f + ad; 3566 3567 te[ 1 ] = f; 3568 te[ 5 ] = a * e; 3569 te[ 9 ] = - b * e; 3570 3571 te[ 2 ] = - d * e; 3572 te[ 6 ] = ad * f + bc; 3573 te[ 10 ] = ac - bd * f; 3574 3575 } else if ( euler.order === 'XZY' ) { 3576 3577 var ac = a * c, ad = a * d, bc = b * c, bd = b * d; 3578 3579 te[ 0 ] = c * e; 3580 te[ 4 ] = - f; 3581 te[ 8 ] = d * e; 3582 3583 te[ 1 ] = ac * f + bd; 3584 te[ 5 ] = a * e; 3585 te[ 9 ] = ad * f - bc; 3586 3587 te[ 2 ] = bc * f - ad; 3588 te[ 6 ] = b * e; 3589 te[ 10 ] = bd * f + ac; 3590 3591 } 3592 3593 // last column 3594 te[ 3 ] = 0; 3595 te[ 7 ] = 0; 3596 te[ 11 ] = 0; 3597 3598 // bottom row 3599 te[ 12 ] = 0; 3600 te[ 13 ] = 0; 3601 te[ 14 ] = 0; 3602 te[ 15 ] = 1; 3603 3604 return this; 3605 3606 }, 3607 3608 makeRotationFromQuaternion: function ( q ) { 3609 3610 var te = this.elements; 3611 3612 var x = q.x, y = q.y, z = q.z, w = q.w; 3613 var x2 = x + x, y2 = y + y, z2 = z + z; 3614 var xx = x * x2, xy = x * y2, xz = x * z2; 3615 var yy = y * y2, yz = y * z2, zz = z * z2; 3616 var wx = w * x2, wy = w * y2, wz = w * z2; 3617 3618 te[ 0 ] = 1 - ( yy + zz ); 3619 te[ 4 ] = xy - wz; 3620 te[ 8 ] = xz + wy; 3621 3622 te[ 1 ] = xy + wz; 3623 te[ 5 ] = 1 - ( xx + zz ); 3624 te[ 9 ] = yz - wx; 3625 3626 te[ 2 ] = xz - wy; 3627 te[ 6 ] = yz + wx; 3628 te[ 10 ] = 1 - ( xx + yy ); 3629 3630 // last column 3631 te[ 3 ] = 0; 3632 te[ 7 ] = 0; 3633 te[ 11 ] = 0; 3634 3635 // bottom row 3636 te[ 12 ] = 0; 3637 te[ 13 ] = 0; 3638 te[ 14 ] = 0; 3639 te[ 15 ] = 1; 3640 3641 return this; 3642 3643 }, 3644 3645 lookAt: function () { 3646 3647 var x, y, z; 3648 3649 return function lookAt( eye, target, up ) { 3650 3651 if ( x === undefined ) { 3652 3653 x = new Vector3(); 3654 y = new Vector3(); 3655 z = new Vector3(); 3656 3657 } 3658 3659 var te = this.elements; 3660 3661 z.subVectors( eye, target ).normalize(); 3662 3663 if ( z.lengthSq() === 0 ) { 3664 3665 z.z = 1; 3666 3667 } 3668 3669 x.crossVectors( up, z ).normalize(); 3670 3671 if ( x.lengthSq() === 0 ) { 3672 3673 z.z += 0.0001; 3674 x.crossVectors( up, z ).normalize(); 3675 3676 } 3677 3678 y.crossVectors( z, x ); 3679 3680 3681 te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x; 3682 te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y; 3683 te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z; 3684 3685 return this; 3686 3687 }; 3688 3689 }(), 3690 3691 multiply: function ( m, n ) { 3692 3693 if ( n !== undefined ) { 3694 3695 console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); 3696 return this.multiplyMatrices( m, n ); 3697 3698 } 3699 3700 return this.multiplyMatrices( this, m ); 3701 3702 }, 3703 3704 premultiply: function ( m ) { 3705 3706 return this.multiplyMatrices( m, this ); 3707 3708 }, 3709 3710 multiplyMatrices: function ( a, b ) { 3711 3712 var ae = a.elements; 3713 var be = b.elements; 3714 var te = this.elements; 3715 3716 var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; 3717 var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; 3718 var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; 3719 var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; 3720 3721 var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; 3722 var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; 3723 var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; 3724 var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; 3725 3726 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 3727 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 3728 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 3729 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 3730 3731 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 3732 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 3733 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 3734 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 3735 3736 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 3737 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 3738 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 3739 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 3740 3741 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 3742 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 3743 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 3744 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 3745 3746 return this; 3747 3748 }, 3749 3750 multiplyToArray: function ( a, b, r ) { 3751 3752 var te = this.elements; 3753 3754 this.multiplyMatrices( a, b ); 3755 3756 r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ]; 3757 r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ]; 3758 r[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ]; 3759 r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ]; 3760 3761 return this; 3762 3763 }, 3764 3765 multiplyScalar: function ( s ) { 3766 3767 var te = this.elements; 3768 3769 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; 3770 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; 3771 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; 3772 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; 3773 3774 return this; 3775 3776 }, 3777 3778 applyToBufferAttribute: function () { 3779 3780 var v1; 3781 3782 return function applyToBufferAttribute( attribute ) { 3783 3784 if ( v1 === undefined ) v1 = new Vector3(); 3785 3786 for ( var i = 0, l = attribute.count; i < l; i ++ ) { 3787 3788 v1.x = attribute.getX( i ); 3789 v1.y = attribute.getY( i ); 3790 v1.z = attribute.getZ( i ); 3791 3792 v1.applyMatrix4( this ); 3793 3794 attribute.setXYZ( i, v1.x, v1.y, v1.z ); 3795 3796 } 3797 3798 return attribute; 3799 3800 }; 3801 3802 }(), 3803 3804 determinant: function () { 3805 3806 var te = this.elements; 3807 3808 var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; 3809 var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; 3810 var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; 3811 var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; 3812 3813 //TODO: make this more efficient 3814 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) 3815 3816 return ( 3817 n41 * ( 3818 + n14 * n23 * n32 3819 - n13 * n24 * n32 3820 - n14 * n22 * n33 3821 + n12 * n24 * n33 3822 + n13 * n22 * n34 3823 - n12 * n23 * n34 3824 ) + 3825 n42 * ( 3826 + n11 * n23 * n34 3827 - n11 * n24 * n33 3828 + n14 * n21 * n33 3829 - n13 * n21 * n34 3830 + n13 * n24 * n31 3831 - n14 * n23 * n31 3832 ) + 3833 n43 * ( 3834 + n11 * n24 * n32 3835 - n11 * n22 * n34 3836 - n14 * n21 * n32 3837 + n12 * n21 * n34 3838 + n14 * n22 * n31 3839 - n12 * n24 * n31 3840 ) + 3841 n44 * ( 3842 - n13 * n22 * n31 3843 - n11 * n23 * n32 3844 + n11 * n22 * n33 3845 + n13 * n21 * n32 3846 - n12 * n21 * n33 3847 + n12 * n23 * n31 3848 ) 3849 3850 ); 3851 3852 }, 3853 3854 transpose: function () { 3855 3856 var te = this.elements; 3857 var tmp; 3858 3859 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; 3860 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; 3861 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; 3862 3863 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; 3864 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; 3865 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; 3866 3867 return this; 3868 3869 }, 3870 3871 setPosition: function ( v ) { 3872 3873 var te = this.elements; 3874 3875 te[ 12 ] = v.x; 3876 te[ 13 ] = v.y; 3877 te[ 14 ] = v.z; 3878 3879 return this; 3880 3881 }, 3882 3883 getInverse: function ( m, throwOnDegenerate ) { 3884 3885 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm 3886 var te = this.elements, 3887 me = m.elements, 3888 3889 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ], 3890 n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ], 3891 n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ], 3892 n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ], 3893 3894 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, 3895 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, 3896 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, 3897 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; 3898 3899 var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; 3900 3901 if ( det === 0 ) { 3902 3903 var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; 3904 3905 if ( throwOnDegenerate === true ) { 3906 3907 throw new Error( msg ); 3908 3909 } else { 3910 3911 console.warn( msg ); 3912 3913 } 3914 3915 return this.identity(); 3916 3917 } 3918 3919 var detInv = 1 / det; 3920 3921 te[ 0 ] = t11 * detInv; 3922 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; 3923 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; 3924 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; 3925 3926 te[ 4 ] = t12 * detInv; 3927 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; 3928 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; 3929 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; 3930 3931 te[ 8 ] = t13 * detInv; 3932 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; 3933 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; 3934 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; 3935 3936 te[ 12 ] = t14 * detInv; 3937 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; 3938 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; 3939 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; 3940 3941 return this; 3942 3943 }, 3944 3945 scale: function ( v ) { 3946 3947 var te = this.elements; 3948 var x = v.x, y = v.y, z = v.z; 3949 3950 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; 3951 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; 3952 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; 3953 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; 3954 3955 return this; 3956 3957 }, 3958 3959 getMaxScaleOnAxis: function () { 3960 3961 var te = this.elements; 3962 3963 var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; 3964 var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; 3965 var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; 3966 3967 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); 3968 3969 }, 3970 3971 makeTranslation: function ( x, y, z ) { 3972 3973 this.set( 3974 3975 1, 0, 0, x, 3976 0, 1, 0, y, 3977 0, 0, 1, z, 3978 0, 0, 0, 1 3979 3980 ); 3981 3982 return this; 3983 3984 }, 3985 3986 makeRotationX: function ( theta ) { 3987 3988 var c = Math.cos( theta ), s = Math.sin( theta ); 3989 3990 this.set( 3991 3992 1, 0, 0, 0, 3993 0, c, - s, 0, 3994 0, s, c, 0, 3995 0, 0, 0, 1 3996 3997 ); 3998 3999 return this; 4000 4001 }, 4002 4003 makeRotationY: function ( theta ) { 4004 4005 var c = Math.cos( theta ), s = Math.sin( theta ); 4006 4007 this.set( 4008 4009 c, 0, s, 0, 4010 0, 1, 0, 0, 4011 - s, 0, c, 0, 4012 0, 0, 0, 1 4013 4014 ); 4015 4016 return this; 4017 4018 }, 4019 4020 makeRotationZ: function ( theta ) { 4021 4022 var c = Math.cos( theta ), s = Math.sin( theta ); 4023 4024 this.set( 4025 4026 c, - s, 0, 0, 4027 s, c, 0, 0, 4028 0, 0, 1, 0, 4029 0, 0, 0, 1 4030 4031 ); 4032 4033 return this; 4034 4035 }, 4036 4037 makeRotationAxis: function ( axis, angle ) { 4038 4039 // Based on http://www.gamedev.net/reference/articles/article1199.asp 4040 4041 var c = Math.cos( angle ); 4042 var s = Math.sin( angle ); 4043 var t = 1 - c; 4044 var x = axis.x, y = axis.y, z = axis.z; 4045 var tx = t * x, ty = t * y; 4046 4047 this.set( 4048 4049 tx * x + c, tx * y - s * z, tx * z + s * y, 0, 4050 tx * y + s * z, ty * y + c, ty * z - s * x, 0, 4051 tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 4052 0, 0, 0, 1 4053 4054 ); 4055 4056 return this; 4057 4058 }, 4059 4060 makeScale: function ( x, y, z ) { 4061 4062 this.set( 4063 4064 x, 0, 0, 0, 4065 0, y, 0, 0, 4066 0, 0, z, 0, 4067 0, 0, 0, 1 4068 4069 ); 4070 4071 return this; 4072 4073 }, 4074 4075 makeShear: function ( x, y, z ) { 4076 4077 this.set( 4078 4079 1, y, z, 0, 4080 x, 1, z, 0, 4081 x, y, 1, 0, 4082 0, 0, 0, 1 4083 4084 ); 4085 4086 return this; 4087 4088 }, 4089 4090 compose: function ( position, quaternion, scale ) { 4091 4092 this.makeRotationFromQuaternion( quaternion ); 4093 this.scale( scale ); 4094 this.setPosition( position ); 4095 4096 return this; 4097 4098 }, 4099 4100 decompose: function () { 4101 4102 var vector, matrix; 4103 4104 return function decompose( position, quaternion, scale ) { 4105 4106 if ( vector === undefined ) { 4107 4108 vector = new Vector3(); 4109 matrix = new Matrix4(); 4110 4111 } 4112 4113 var te = this.elements; 4114 4115 var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); 4116 var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); 4117 var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); 4118 4119 // if determine is negative, we need to invert one scale 4120 var det = this.determinant(); 4121 if ( det < 0 ) { 4122 4123 sx = - sx; 4124 4125 } 4126 4127 position.x = te[ 12 ]; 4128 position.y = te[ 13 ]; 4129 position.z = te[ 14 ]; 4130 4131 // scale the rotation part 4132 4133 matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() 4134 4135 var invSX = 1 / sx; 4136 var invSY = 1 / sy; 4137 var invSZ = 1 / sz; 4138 4139 matrix.elements[ 0 ] *= invSX; 4140 matrix.elements[ 1 ] *= invSX; 4141 matrix.elements[ 2 ] *= invSX; 4142 4143 matrix.elements[ 4 ] *= invSY; 4144 matrix.elements[ 5 ] *= invSY; 4145 matrix.elements[ 6 ] *= invSY; 4146 4147 matrix.elements[ 8 ] *= invSZ; 4148 matrix.elements[ 9 ] *= invSZ; 4149 matrix.elements[ 10 ] *= invSZ; 4150 4151 quaternion.setFromRotationMatrix( matrix ); 4152 4153 scale.x = sx; 4154 scale.y = sy; 4155 scale.z = sz; 4156 4157 return this; 4158 4159 }; 4160 4161 }(), 4162 4163 makePerspective: function ( left, right, top, bottom, near, far ) { 4164 4165 if ( far === undefined ) { 4166 4167 console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); 4168 4169 } 4170 4171 var te = this.elements; 4172 var x = 2 * near / ( right - left ); 4173 var y = 2 * near / ( top - bottom ); 4174 4175 var a = ( right + left ) / ( right - left ); 4176 var b = ( top + bottom ) / ( top - bottom ); 4177 var c = - ( far + near ) / ( far - near ); 4178 var d = - 2 * far * near / ( far - near ); 4179 4180 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; 4181 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; 4182 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; 4183 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; 4184 4185 return this; 4186 4187 }, 4188 4189 makeOrthographic: function ( left, right, top, bottom, near, far ) { 4190 4191 var te = this.elements; 4192 var w = 1.0 / ( right - left ); 4193 var h = 1.0 / ( top - bottom ); 4194 var p = 1.0 / ( far - near ); 4195 4196 var x = ( right + left ) * w; 4197 var y = ( top + bottom ) * h; 4198 var z = ( far + near ) * p; 4199 4200 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; 4201 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; 4202 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; 4203 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; 4204 4205 return this; 4206 4207 }, 4208 4209 equals: function ( matrix ) { 4210 4211 var te = this.elements; 4212 var me = matrix.elements; 4213 4214 for ( var i = 0; i < 16; i ++ ) { 4215 4216 if ( te[ i ] !== me[ i ] ) return false; 4217 4218 } 4219 4220 return true; 4221 4222 }, 4223 4224 fromArray: function ( array, offset ) { 4225 4226 if ( offset === undefined ) offset = 0; 4227 4228 for( var i = 0; i < 16; i ++ ) { 4229 4230 this.elements[ i ] = array[ i + offset ]; 4231 4232 } 4233 4234 return this; 4235 4236 }, 4237 4238 toArray: function ( array, offset ) { 4239 4240 if ( array === undefined ) array = []; 4241 if ( offset === undefined ) offset = 0; 4242 4243 var te = this.elements; 4244 4245 array[ offset ] = te[ 0 ]; 4246 array[ offset + 1 ] = te[ 1 ]; 4247 array[ offset + 2 ] = te[ 2 ]; 4248 array[ offset + 3 ] = te[ 3 ]; 4249 4250 array[ offset + 4 ] = te[ 4 ]; 4251 array[ offset + 5 ] = te[ 5 ]; 4252 array[ offset + 6 ] = te[ 6 ]; 4253 array[ offset + 7 ] = te[ 7 ]; 4254 4255 array[ offset + 8 ] = te[ 8 ]; 4256 array[ offset + 9 ] = te[ 9 ]; 4257 array[ offset + 10 ] = te[ 10 ]; 4258 array[ offset + 11 ] = te[ 11 ]; 4259 4260 array[ offset + 12 ] = te[ 12 ]; 4261 array[ offset + 13 ] = te[ 13 ]; 4262 array[ offset + 14 ] = te[ 14 ]; 4263 array[ offset + 15 ] = te[ 15 ]; 4264 4265 return array; 4266 4267 } 4268 4269 }; 4270 4271 /** 4272 * @author mrdoob / http://mrdoob.com/ 4273 */ 4274 4275 function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { 4276 4277 images = images !== undefined ? images : []; 4278 mapping = mapping !== undefined ? mapping : CubeReflectionMapping; 4279 4280 Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); 4281 4282 this.flipY = false; 4283 4284 } 4285 4286 CubeTexture.prototype = Object.create( Texture.prototype ); 4287 CubeTexture.prototype.constructor = CubeTexture; 4288 4289 CubeTexture.prototype.isCubeTexture = true; 4290 4291 Object.defineProperty( CubeTexture.prototype, 'images', { 4292 4293 get: function () { 4294 4295 return this.image; 4296 4297 }, 4298 4299 set: function ( value ) { 4300 4301 this.image = value; 4302 4303 } 4304 4305 } ); 4306 4307 /** 4308 * @author tschw 4309 * 4310 * Uniforms of a program. 4311 * Those form a tree structure with a special top-level container for the root, 4312 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'. 4313 * 4314 * 4315 * Properties of inner nodes including the top-level container: 4316 * 4317 * .seq - array of nested uniforms 4318 * .map - nested uniforms by name 4319 * 4320 * 4321 * Methods of all nodes except the top-level container: 4322 * 4323 * .setValue( gl, value, [renderer] ) 4324 * 4325 * uploads a uniform value(s) 4326 * the 'renderer' parameter is needed for sampler uniforms 4327 * 4328 * 4329 * Static methods of the top-level container (renderer factorizations): 4330 * 4331 * .upload( gl, seq, values, renderer ) 4332 * 4333 * sets uniforms in 'seq' to 'values[id].value' 4334 * 4335 * .seqWithValue( seq, values ) : filteredSeq 4336 * 4337 * filters 'seq' entries with corresponding entry in values 4338 * 4339 * 4340 * Methods of the top-level container (renderer factorizations): 4341 * 4342 * .setValue( gl, name, value ) 4343 * 4344 * sets uniform with name 'name' to 'value' 4345 * 4346 * .set( gl, obj, prop ) 4347 * 4348 * sets uniform from object and property with same name than uniform 4349 * 4350 * .setOptional( gl, obj, prop ) 4351 * 4352 * like .set for an optional property of the object 4353 * 4354 */ 4355 4356 var emptyTexture = new Texture(); 4357 var emptyCubeTexture = new CubeTexture(); 4358 4359 // --- Base for inner nodes (including the root) --- 4360 4361 function UniformContainer() { 4362 4363 this.seq = []; 4364 this.map = {}; 4365 4366 } 4367 4368 // --- Utilities --- 4369 4370 // Array Caches (provide typed arrays for temporary by size) 4371 4372 var arrayCacheF32 = []; 4373 var arrayCacheI32 = []; 4374 4375 // Flattening for arrays of vectors and matrices 4376 4377 function flatten( array, nBlocks, blockSize ) { 4378 4379 var firstElem = array[ 0 ]; 4380 4381 if ( firstElem <= 0 || firstElem > 0 ) return array; 4382 // unoptimized: ! isNaN( firstElem ) 4383 // see http://jacksondunstan.com/articles/983 4384 4385 var n = nBlocks * blockSize, 4386 r = arrayCacheF32[ n ]; 4387 4388 if ( r === undefined ) { 4389 4390 r = new Float32Array( n ); 4391 arrayCacheF32[ n ] = r; 4392 4393 } 4394 4395 if ( nBlocks !== 0 ) { 4396 4397 firstElem.toArray( r, 0 ); 4398 4399 for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { 4400 4401 offset += blockSize; 4402 array[ i ].toArray( r, offset ); 4403 4404 } 4405 4406 } 4407 4408 return r; 4409 4410 } 4411 4412 // Texture unit allocation 4413 4414 function allocTexUnits( renderer, n ) { 4415 4416 var r = arrayCacheI32[ n ]; 4417 4418 if ( r === undefined ) { 4419 4420 r = new Int32Array( n ); 4421 arrayCacheI32[ n ] = r; 4422 4423 } 4424 4425 for ( var i = 0; i !== n; ++ i ) 4426 r[ i ] = renderer.allocTextureUnit(); 4427 4428 return r; 4429 4430 } 4431 4432 // --- Setters --- 4433 4434 // Note: Defining these methods externally, because they come in a bunch 4435 // and this way their names minify. 4436 4437 // Single scalar 4438 4439 function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); } 4440 function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); } 4441 4442 // Single float vector (from flat array or THREE.VectorN) 4443 4444 function setValue2fv( gl, v ) { 4445 4446 if ( v.x === undefined ) gl.uniform2fv( this.addr, v ); 4447 else gl.uniform2f( this.addr, v.x, v.y ); 4448 4449 } 4450 4451 function setValue3fv( gl, v ) { 4452 4453 if ( v.x !== undefined ) 4454 gl.uniform3f( this.addr, v.x, v.y, v.z ); 4455 else if ( v.r !== undefined ) 4456 gl.uniform3f( this.addr, v.r, v.g, v.b ); 4457 else 4458 gl.uniform3fv( this.addr, v ); 4459 4460 } 4461 4462 function setValue4fv( gl, v ) { 4463 4464 if ( v.x === undefined ) gl.uniform4fv( this.addr, v ); 4465 else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); 4466 4467 } 4468 4469 // Single matrix (from flat array or MatrixN) 4470 4471 function setValue2fm( gl, v ) { 4472 4473 gl.uniformMatrix2fv( this.addr, false, v.elements || v ); 4474 4475 } 4476 4477 function setValue3fm( gl, v ) { 4478 4479 gl.uniformMatrix3fv( this.addr, false, v.elements || v ); 4480 4481 } 4482 4483 function setValue4fm( gl, v ) { 4484 4485 gl.uniformMatrix4fv( this.addr, false, v.elements || v ); 4486 4487 } 4488 4489 // Single texture (2D / Cube) 4490 4491 function setValueT1( gl, v, renderer ) { 4492 4493 var unit = renderer.allocTextureUnit(); 4494 gl.uniform1i( this.addr, unit ); 4495 renderer.setTexture2D( v || emptyTexture, unit ); 4496 4497 } 4498 4499 function setValueT6( gl, v, renderer ) { 4500 4501 var unit = renderer.allocTextureUnit(); 4502 gl.uniform1i( this.addr, unit ); 4503 renderer.setTextureCube( v || emptyCubeTexture, unit ); 4504 4505 } 4506 4507 // Integer / Boolean vectors or arrays thereof (always flat arrays) 4508 4509 function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); } 4510 function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); } 4511 function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); } 4512 4513 // Helper to pick the right setter for the singular case 4514 4515 function getSingularSetter( type ) { 4516 4517 switch ( type ) { 4518 4519 case 0x1406: return setValue1f; // FLOAT 4520 case 0x8b50: return setValue2fv; // _VEC2 4521 case 0x8b51: return setValue3fv; // _VEC3 4522 case 0x8b52: return setValue4fv; // _VEC4 4523 4524 case 0x8b5a: return setValue2fm; // _MAT2 4525 case 0x8b5b: return setValue3fm; // _MAT3 4526 case 0x8b5c: return setValue4fm; // _MAT4 4527 4528 case 0x8b5e: return setValueT1; // SAMPLER_2D 4529 case 0x8b60: return setValueT6; // SAMPLER_CUBE 4530 4531 case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL 4532 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 4533 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 4534 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 4535 4536 } 4537 4538 } 4539 4540 // Array of scalars 4541 4542 function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); } 4543 function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); } 4544 4545 // Array of vectors (flat or from THREE classes) 4546 4547 function setValueV2a( gl, v ) { 4548 4549 gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) ); 4550 4551 } 4552 4553 function setValueV3a( gl, v ) { 4554 4555 gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) ); 4556 4557 } 4558 4559 function setValueV4a( gl, v ) { 4560 4561 gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) ); 4562 4563 } 4564 4565 // Array of matrices (flat or from THREE clases) 4566 4567 function setValueM2a( gl, v ) { 4568 4569 gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) ); 4570 4571 } 4572 4573 function setValueM3a( gl, v ) { 4574 4575 gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) ); 4576 4577 } 4578 4579 function setValueM4a( gl, v ) { 4580 4581 gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) ); 4582 4583 } 4584 4585 // Array of textures (2D / Cube) 4586 4587 function setValueT1a( gl, v, renderer ) { 4588 4589 var n = v.length, 4590 units = allocTexUnits( renderer, n ); 4591 4592 gl.uniform1iv( this.addr, units ); 4593 4594 for ( var i = 0; i !== n; ++ i ) { 4595 4596 renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); 4597 4598 } 4599 4600 } 4601 4602 function setValueT6a( gl, v, renderer ) { 4603 4604 var n = v.length, 4605 units = allocTexUnits( renderer, n ); 4606 4607 gl.uniform1iv( this.addr, units ); 4608 4609 for ( var i = 0; i !== n; ++ i ) { 4610 4611 renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); 4612 4613 } 4614 4615 } 4616 4617 // Helper to pick the right setter for a pure (bottom-level) array 4618 4619 function getPureArraySetter( type ) { 4620 4621 switch ( type ) { 4622 4623 case 0x1406: return setValue1fv; // FLOAT 4624 case 0x8b50: return setValueV2a; // _VEC2 4625 case 0x8b51: return setValueV3a; // _VEC3 4626 case 0x8b52: return setValueV4a; // _VEC4 4627 4628 case 0x8b5a: return setValueM2a; // _MAT2 4629 case 0x8b5b: return setValueM3a; // _MAT3 4630 case 0x8b5c: return setValueM4a; // _MAT4 4631 4632 case 0x8b5e: return setValueT1a; // SAMPLER_2D 4633 case 0x8b60: return setValueT6a; // SAMPLER_CUBE 4634 4635 case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL 4636 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 4637 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 4638 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 4639 4640 } 4641 4642 } 4643 4644 // --- Uniform Classes --- 4645 4646 function SingleUniform( id, activeInfo, addr ) { 4647 4648 this.id = id; 4649 this.addr = addr; 4650 this.setValue = getSingularSetter( activeInfo.type ); 4651 4652 // this.path = activeInfo.name; // DEBUG 4653 4654 } 4655 4656 function PureArrayUniform( id, activeInfo, addr ) { 4657 4658 this.id = id; 4659 this.addr = addr; 4660 this.size = activeInfo.size; 4661 this.setValue = getPureArraySetter( activeInfo.type ); 4662 4663 // this.path = activeInfo.name; // DEBUG 4664 4665 } 4666 4667 function StructuredUniform( id ) { 4668 4669 this.id = id; 4670 4671 UniformContainer.call( this ); // mix-in 4672 4673 } 4674 4675 StructuredUniform.prototype.setValue = function( gl, value ) { 4676 4677 // Note: Don't need an extra 'renderer' parameter, since samplers 4678 // are not allowed in structured uniforms. 4679 4680 var seq = this.seq; 4681 4682 for ( var i = 0, n = seq.length; i !== n; ++ i ) { 4683 4684 var u = seq[ i ]; 4685 u.setValue( gl, value[ u.id ] ); 4686 4687 } 4688 4689 }; 4690 4691 // --- Top-level --- 4692 4693 // Parser - builds up the property tree from the path strings 4694 4695 var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g; 4696 4697 // extracts 4698 // - the identifier (member name or array index) 4699 // - followed by an optional right bracket (found when array index) 4700 // - followed by an optional left bracket or dot (type of subscript) 4701 // 4702 // Note: These portions can be read in a non-overlapping fashion and 4703 // allow straightforward parsing of the hierarchy that WebGL encodes 4704 // in the uniform names. 4705 4706 function addUniform( container, uniformObject ) { 4707 4708 container.seq.push( uniformObject ); 4709 container.map[ uniformObject.id ] = uniformObject; 4710 4711 } 4712 4713 function parseUniform( activeInfo, addr, container ) { 4714 4715 var path = activeInfo.name, 4716 pathLength = path.length; 4717 4718 // reset RegExp object, because of the early exit of a previous run 4719 RePathPart.lastIndex = 0; 4720 4721 for (; ;) { 4722 4723 var match = RePathPart.exec( path ), 4724 matchEnd = RePathPart.lastIndex, 4725 4726 id = match[ 1 ], 4727 idIsIndex = match[ 2 ] === ']', 4728 subscript = match[ 3 ]; 4729 4730 if ( idIsIndex ) id = id | 0; // convert to integer 4731 4732 if ( subscript === undefined || 4733 subscript === '[' && matchEnd + 2 === pathLength ) { 4734 // bare name or "pure" bottom-level array "[0]" suffix 4735 4736 addUniform( container, subscript === undefined ? 4737 new SingleUniform( id, activeInfo, addr ) : 4738 new PureArrayUniform( id, activeInfo, addr ) ); 4739 4740 break; 4741 4742 } else { 4743 // step into inner node / create it in case it doesn't exist 4744 4745 var map = container.map, 4746 next = map[ id ]; 4747 4748 if ( next === undefined ) { 4749 4750 next = new StructuredUniform( id ); 4751 addUniform( container, next ); 4752 4753 } 4754 4755 container = next; 4756 4757 } 4758 4759 } 4760 4761 } 4762 4763 // Root Container 4764 4765 function WebGLUniforms( gl, program, renderer ) { 4766 4767 UniformContainer.call( this ); 4768 4769 this.renderer = renderer; 4770 4771 var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); 4772 4773 for ( var i = 0; i < n; ++ i ) { 4774 4775 var info = gl.getActiveUniform( program, i ), 4776 path = info.name, 4777 addr = gl.getUniformLocation( program, path ); 4778 4779 parseUniform( info, addr, this ); 4780 4781 } 4782 4783 } 4784 4785 WebGLUniforms.prototype.setValue = function( gl, name, value ) { 4786 4787 var u = this.map[ name ]; 4788 4789 if ( u !== undefined ) u.setValue( gl, value, this.renderer ); 4790 4791 }; 4792 4793 WebGLUniforms.prototype.set = function( gl, object, name ) { 4794 4795 var u = this.map[ name ]; 4796 4797 if ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer ); 4798 4799 }; 4800 4801 WebGLUniforms.prototype.setOptional = function( gl, object, name ) { 4802 4803 var v = object[ name ]; 4804 4805 if ( v !== undefined ) this.setValue( gl, name, v ); 4806 4807 }; 4808 4809 4810 // Static interface 4811 4812 WebGLUniforms.upload = function( gl, seq, values, renderer ) { 4813 4814 for ( var i = 0, n = seq.length; i !== n; ++ i ) { 4815 4816 var u = seq[ i ], 4817 v = values[ u.id ]; 4818 4819 if ( v.needsUpdate !== false ) { 4820 // note: always updating when .needsUpdate is undefined 4821 4822 u.setValue( gl, v.value, renderer ); 4823 4824 } 4825 4826 } 4827 4828 }; 4829 4830 WebGLUniforms.seqWithValue = function( seq, values ) { 4831 4832 var r = []; 4833 4834 for ( var i = 0, n = seq.length; i !== n; ++ i ) { 4835 4836 var u = seq[ i ]; 4837 if ( u.id in values ) r.push( u ); 4838 4839 } 4840 4841 return r; 4842 4843 }; 4844 4845 /** 4846 * Uniform Utilities 4847 */ 4848 4849 var UniformsUtils = { 4850 4851 merge: function ( uniforms ) { 4852 4853 var merged = {}; 4854 4855 for ( var u = 0; u < uniforms.length; u ++ ) { 4856 4857 var tmp = this.clone( uniforms[ u ] ); 4858 4859 for ( var p in tmp ) { 4860 4861 merged[ p ] = tmp[ p ]; 4862 4863 } 4864 4865 } 4866 4867 return merged; 4868 4869 }, 4870 4871 clone: function ( uniforms_src ) { 4872 4873 var uniforms_dst = {}; 4874 4875 for ( var u in uniforms_src ) { 4876 4877 uniforms_dst[ u ] = {}; 4878 4879 for ( var p in uniforms_src[ u ] ) { 4880 4881 var parameter_src = uniforms_src[ u ][ p ]; 4882 4883 if ( parameter_src && ( parameter_src.isColor || 4884 parameter_src.isMatrix3 || parameter_src.isMatrix4 || 4885 parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || 4886 parameter_src.isTexture ) ) { 4887 4888 uniforms_dst[ u ][ p ] = parameter_src.clone(); 4889 4890 } else if ( Array.isArray( parameter_src ) ) { 4891 4892 uniforms_dst[ u ][ p ] = parameter_src.slice(); 4893 4894 } else { 4895 4896 uniforms_dst[ u ][ p ] = parameter_src; 4897 4898 } 4899 4900 } 4901 4902 } 4903 4904 return uniforms_dst; 4905 4906 } 4907 4908 }; 4909 4910 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; 4911 4912 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; 4913 4914 var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n"; 4915 4916 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"; 4917 4918 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 4919 4920 var begin_vertex = "\nvec3 transformed = vec3( position );\n"; 4921 4922 var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; 4923 4924 var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\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 ltcTextureCoords( const in GeometricContext geometry, 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\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\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}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3( 1, 0, t.y ),\n\t\tvec3( 0, t.z, 0 ),\n\t\tvec3( t.w, 0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\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"; 4925 4926 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 = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\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"; 4927 4928 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"; 4929 4930 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"; 4931 4932 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n"; 4933 4934 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; 4935 4936 var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; 4937 4938 var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; 4939 4940 var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; 4941 4942 var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; 4943 4944 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"; 4945 4946 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"; 4947 4948 var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; 4949 4950 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; 4951 4952 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n"; 4953 4954 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"; 4955 4956 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; 4957 4958 var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; 4959 4960 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"; 4961 4962 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, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * 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"; 4963 4964 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"; 4965 4966 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"; 4967 4968 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"; 4969 4970 var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif"; 4971 4972 var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n"; 4973 4974 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"; 4975 4976 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"; 4977 4978 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"; 4979 4980 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; 4981 4982 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 4983 4984 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"; 4985 4986 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};\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 = saturate( reflectVec.y * 0.5 + 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"; 4987 4988 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; 4989 4990 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};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff / PI2;\n\t}\n#endif\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_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n"; 4991 4992 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"; 4993 4994 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 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\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"; 4995 4996 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 ] ) : 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"; 4997 4998 var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif"; 4999 5000 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"; 5001 5002 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"; 5003 5004 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"; 5005 5006 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; 5007 5008 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; 5009 5010 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"; 5011 5012 var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n"; 5013 5014 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n"; 5015 5016 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 5017 5018 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"; 5019 5020 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"; 5021 5022 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"; 5023 5024 var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n"; 5025 5026 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 ) * flipNormal;\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"; 5027 5028 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 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\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"; 5029 5030 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"; 5031 5032 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; 5033 5034 var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n"; 5035 5036 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n"; 5037 5038 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 5039 5040 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\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\treturn (\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\treturn (\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\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\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 ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\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"; 5041 5042 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"; 5043 5044 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"; 5045 5046 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 ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n"; 5047 5048 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"; 5049 5050 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 boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\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"; 5051 5052 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\tskinned = bindMatrixInverse * skinned;\n#endif\n"; 5053 5054 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"; 5055 5056 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"; 5057 5058 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 5059 5060 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; 5061 5062 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"; 5063 5064 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"; 5065 5066 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"; 5067 5068 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"; 5069 5070 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; 5071 5072 var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif"; 5073 5074 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; 5075 5076 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n"; 5077 5078 var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n"; 5079 5080 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"; 5081 5082 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"; 5083 5084 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#include <begin_vertex>\n\t#include <displacementmap_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}\n"; 5085 5086 var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include <common>\n#include <packing>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n"; 5087 5088 var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include <common>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <skinbase_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition;\n}\n"; 5089 5090 var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n"; 5091 5092 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"; 5093 5094 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"; 5095 5096 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"; 5097 5098 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 <normal_flip>\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"; 5099 5100 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"; 5101 5102 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 <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 <normal_flip>\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"; 5103 5104 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"; 5105 5106 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 <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_flip>\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 <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n"; 5107 5108 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 <displacementmap_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\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"; 5109 5110 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 <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 <specularmap_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_flip>\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 <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n"; 5111 5112 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 <specularmap_pars_fragment>\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 <displacementmap_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\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n"; 5113 5114 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_flip>\n\t#include <normal_fragment>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; 5115 5116 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 <displacementmap_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_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"; 5117 5118 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"; 5119 5120 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"; 5121 5122 var shadow_frag = "uniform 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( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n"; 5123 5124 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"; 5125 5126 var ShaderChunk = { 5127 alphamap_fragment: alphamap_fragment, 5128 alphamap_pars_fragment: alphamap_pars_fragment, 5129 alphatest_fragment: alphatest_fragment, 5130 aomap_fragment: aomap_fragment, 5131 aomap_pars_fragment: aomap_pars_fragment, 5132 begin_vertex: begin_vertex, 5133 beginnormal_vertex: beginnormal_vertex, 5134 bsdfs: bsdfs, 5135 bumpmap_pars_fragment: bumpmap_pars_fragment, 5136 clipping_planes_fragment: clipping_planes_fragment, 5137 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 5138 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 5139 clipping_planes_vertex: clipping_planes_vertex, 5140 color_fragment: color_fragment, 5141 color_pars_fragment: color_pars_fragment, 5142 color_pars_vertex: color_pars_vertex, 5143 color_vertex: color_vertex, 5144 common: common, 5145 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 5146 defaultnormal_vertex: defaultnormal_vertex, 5147 displacementmap_pars_vertex: displacementmap_pars_vertex, 5148 displacementmap_vertex: displacementmap_vertex, 5149 emissivemap_fragment: emissivemap_fragment, 5150 emissivemap_pars_fragment: emissivemap_pars_fragment, 5151 encodings_fragment: encodings_fragment, 5152 encodings_pars_fragment: encodings_pars_fragment, 5153 envmap_fragment: envmap_fragment, 5154 envmap_pars_fragment: envmap_pars_fragment, 5155 envmap_pars_vertex: envmap_pars_vertex, 5156 envmap_vertex: envmap_vertex, 5157 fog_vertex: fog_vertex, 5158 fog_pars_vertex: fog_pars_vertex, 5159 fog_fragment: fog_fragment, 5160 fog_pars_fragment: fog_pars_fragment, 5161 gradientmap_pars_fragment: gradientmap_pars_fragment, 5162 lightmap_fragment: lightmap_fragment, 5163 lightmap_pars_fragment: lightmap_pars_fragment, 5164 lights_lambert_vertex: lights_lambert_vertex, 5165 lights_pars: lights_pars, 5166 lights_phong_fragment: lights_phong_fragment, 5167 lights_phong_pars_fragment: lights_phong_pars_fragment, 5168 lights_physical_fragment: lights_physical_fragment, 5169 lights_physical_pars_fragment: lights_physical_pars_fragment, 5170 lights_template: lights_template, 5171 logdepthbuf_fragment: logdepthbuf_fragment, 5172 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 5173 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 5174 logdepthbuf_vertex: logdepthbuf_vertex, 5175 map_fragment: map_fragment, 5176 map_pars_fragment: map_pars_fragment, 5177 map_particle_fragment: map_particle_fragment, 5178 map_particle_pars_fragment: map_particle_pars_fragment, 5179 metalnessmap_fragment: metalnessmap_fragment, 5180 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 5181 morphnormal_vertex: morphnormal_vertex, 5182 morphtarget_pars_vertex: morphtarget_pars_vertex, 5183 morphtarget_vertex: morphtarget_vertex, 5184 normal_flip: normal_flip, 5185 normal_fragment: normal_fragment, 5186 normalmap_pars_fragment: normalmap_pars_fragment, 5187 packing: packing, 5188 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 5189 project_vertex: project_vertex, 5190 roughnessmap_fragment: roughnessmap_fragment, 5191 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 5192 shadowmap_pars_fragment: shadowmap_pars_fragment, 5193 shadowmap_pars_vertex: shadowmap_pars_vertex, 5194 shadowmap_vertex: shadowmap_vertex, 5195 shadowmask_pars_fragment: shadowmask_pars_fragment, 5196 skinbase_vertex: skinbase_vertex, 5197 skinning_pars_vertex: skinning_pars_vertex, 5198 skinning_vertex: skinning_vertex, 5199 skinnormal_vertex: skinnormal_vertex, 5200 specularmap_fragment: specularmap_fragment, 5201 specularmap_pars_fragment: specularmap_pars_fragment, 5202 tonemapping_fragment: tonemapping_fragment, 5203 tonemapping_pars_fragment: tonemapping_pars_fragment, 5204 uv_pars_fragment: uv_pars_fragment, 5205 uv_pars_vertex: uv_pars_vertex, 5206 uv_vertex: uv_vertex, 5207 uv2_pars_fragment: uv2_pars_fragment, 5208 uv2_pars_vertex: uv2_pars_vertex, 5209 uv2_vertex: uv2_vertex, 5210 worldpos_vertex: worldpos_vertex, 5211 5212 cube_frag: cube_frag, 5213 cube_vert: cube_vert, 5214 depth_frag: depth_frag, 5215 depth_vert: depth_vert, 5216 distanceRGBA_frag: distanceRGBA_frag, 5217 distanceRGBA_vert: distanceRGBA_vert, 5218 equirect_frag: equirect_frag, 5219 equirect_vert: equirect_vert, 5220 linedashed_frag: linedashed_frag, 5221 linedashed_vert: linedashed_vert, 5222 meshbasic_frag: meshbasic_frag, 5223 meshbasic_vert: meshbasic_vert, 5224 meshlambert_frag: meshlambert_frag, 5225 meshlambert_vert: meshlambert_vert, 5226 meshphong_frag: meshphong_frag, 5227 meshphong_vert: meshphong_vert, 5228 meshphysical_frag: meshphysical_frag, 5229 meshphysical_vert: meshphysical_vert, 5230 normal_frag: normal_frag, 5231 normal_vert: normal_vert, 5232 points_frag: points_frag, 5233 points_vert: points_vert, 5234 shadow_frag: shadow_frag, 5235 shadow_vert: shadow_vert 5236 }; 5237 5238 /** 5239 * @author mrdoob / http://mrdoob.com/ 5240 */ 5241 5242 function Color( r, g, b ) { 5243 5244 if ( g === undefined && b === undefined ) { 5245 5246 // r is THREE.Color, hex or string 5247 return this.set( r ); 5248 5249 } 5250 5251 return this.setRGB( r, g, b ); 5252 5253 } 5254 5255 Color.prototype = { 5256 5257 constructor: Color, 5258 5259 isColor: true, 5260 5261 r: 1, g: 1, b: 1, 5262 5263 set: function ( value ) { 5264 5265 if ( value && value.isColor ) { 5266 5267 this.copy( value ); 5268 5269 } else if ( typeof value === 'number' ) { 5270 5271 this.setHex( value ); 5272 5273 } else if ( typeof value === 'string' ) { 5274 5275 this.setStyle( value ); 5276 5277 } 5278 5279 return this; 5280 5281 }, 5282 5283 setScalar: function ( scalar ) { 5284 5285 this.r = scalar; 5286 this.g = scalar; 5287 this.b = scalar; 5288 5289 return this; 5290 5291 }, 5292 5293 setHex: function ( hex ) { 5294 5295 hex = Math.floor( hex ); 5296 5297 this.r = ( hex >> 16 & 255 ) / 255; 5298 this.g = ( hex >> 8 & 255 ) / 255; 5299 this.b = ( hex & 255 ) / 255; 5300 5301 return this; 5302 5303 }, 5304 5305 setRGB: function ( r, g, b ) { 5306 5307 this.r = r; 5308 this.g = g; 5309 this.b = b; 5310 5311 return this; 5312 5313 }, 5314 5315 setHSL: function () { 5316 5317 function hue2rgb( p, q, t ) { 5318 5319 if ( t < 0 ) t += 1; 5320 if ( t > 1 ) t -= 1; 5321 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; 5322 if ( t < 1 / 2 ) return q; 5323 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); 5324 return p; 5325 5326 } 5327 5328 return function setHSL( h, s, l ) { 5329 5330 // h,s,l ranges are in 0.0 - 1.0 5331 h = _Math.euclideanModulo( h, 1 ); 5332 s = _Math.clamp( s, 0, 1 ); 5333 l = _Math.clamp( l, 0, 1 ); 5334 5335 if ( s === 0 ) { 5336 5337 this.r = this.g = this.b = l; 5338 5339 } else { 5340 5341 var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); 5342 var q = ( 2 * l ) - p; 5343 5344 this.r = hue2rgb( q, p, h + 1 / 3 ); 5345 this.g = hue2rgb( q, p, h ); 5346 this.b = hue2rgb( q, p, h - 1 / 3 ); 5347 5348 } 5349 5350 return this; 5351 5352 }; 5353 5354 }(), 5355 5356 setStyle: function ( style ) { 5357 5358 function handleAlpha( string ) { 5359 5360 if ( string === undefined ) return; 5361 5362 if ( parseFloat( string ) < 1 ) { 5363 5364 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); 5365 5366 } 5367 5368 } 5369 5370 5371 var m; 5372 5373 if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { 5374 5375 // rgb / hsl 5376 5377 var color; 5378 var name = m[ 1 ]; 5379 var components = m[ 2 ]; 5380 5381 switch ( name ) { 5382 5383 case 'rgb': 5384 case 'rgba': 5385 5386 if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { 5387 5388 // rgb(255,0,0) rgba(255,0,0,0.5) 5389 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; 5390 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; 5391 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; 5392 5393 handleAlpha( color[ 5 ] ); 5394 5395 return this; 5396 5397 } 5398 5399 if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { 5400 5401 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 5402 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; 5403 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; 5404 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; 5405 5406 handleAlpha( color[ 5 ] ); 5407 5408 return this; 5409 5410 } 5411 5412 break; 5413 5414 case 'hsl': 5415 case 'hsla': 5416 5417 if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { 5418 5419 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 5420 var h = parseFloat( color[ 1 ] ) / 360; 5421 var s = parseInt( color[ 2 ], 10 ) / 100; 5422 var l = parseInt( color[ 3 ], 10 ) / 100; 5423 5424 handleAlpha( color[ 5 ] ); 5425 5426 return this.setHSL( h, s, l ); 5427 5428 } 5429 5430 break; 5431 5432 } 5433 5434 } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { 5435 5436 // hex color 5437 5438 var hex = m[ 1 ]; 5439 var size = hex.length; 5440 5441 if ( size === 3 ) { 5442 5443 // #ff0 5444 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; 5445 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; 5446 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; 5447 5448 return this; 5449 5450 } else if ( size === 6 ) { 5451 5452 // #ff0000 5453 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; 5454 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; 5455 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; 5456 5457 return this; 5458 5459 } 5460 5461 } 5462 5463 if ( style && style.length > 0 ) { 5464 5465 // color keywords 5466 var hex = ColorKeywords[ style ]; 5467 5468 if ( hex !== undefined ) { 5469 5470 // red 5471 this.setHex( hex ); 5472 5473 } else { 5474 5475 // unknown color 5476 console.warn( 'THREE.Color: Unknown color ' + style ); 5477 5478 } 5479 5480 } 5481 5482 return this; 5483 5484 }, 5485 5486 clone: function () { 5487 5488 return new this.constructor( this.r, this.g, this.b ); 5489 5490 }, 5491 5492 copy: function ( color ) { 5493 5494 this.r = color.r; 5495 this.g = color.g; 5496 this.b = color.b; 5497 5498 return this; 5499 5500 }, 5501 5502 copyGammaToLinear: function ( color, gammaFactor ) { 5503 5504 if ( gammaFactor === undefined ) gammaFactor = 2.0; 5505 5506 this.r = Math.pow( color.r, gammaFactor ); 5507 this.g = Math.pow( color.g, gammaFactor ); 5508 this.b = Math.pow( color.b, gammaFactor ); 5509 5510 return this; 5511 5512 }, 5513 5514 copyLinearToGamma: function ( color, gammaFactor ) { 5515 5516 if ( gammaFactor === undefined ) gammaFactor = 2.0; 5517 5518 var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; 5519 5520 this.r = Math.pow( color.r, safeInverse ); 5521 this.g = Math.pow( color.g, safeInverse ); 5522 this.b = Math.pow( color.b, safeInverse ); 5523 5524 return this; 5525 5526 }, 5527 5528 convertGammaToLinear: function () { 5529 5530 var r = this.r, g = this.g, b = this.b; 5531 5532 this.r = r * r; 5533 this.g = g * g; 5534 this.b = b * b; 5535 5536 return this; 5537 5538 }, 5539 5540 convertLinearToGamma: function () { 5541 5542 this.r = Math.sqrt( this.r ); 5543 this.g = Math.sqrt( this.g ); 5544 this.b = Math.sqrt( this.b ); 5545 5546 return this; 5547 5548 }, 5549 5550 getHex: function () { 5551 5552 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; 5553 5554 }, 5555 5556 getHexString: function () { 5557 5558 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); 5559 5560 }, 5561 5562 getHSL: function ( optionalTarget ) { 5563 5564 // h,s,l ranges are in 0.0 - 1.0 5565 5566 var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; 5567 5568 var r = this.r, g = this.g, b = this.b; 5569 5570 var max = Math.max( r, g, b ); 5571 var min = Math.min( r, g, b ); 5572 5573 var hue, saturation; 5574 var lightness = ( min + max ) / 2.0; 5575 5576 if ( min === max ) { 5577 5578 hue = 0; 5579 saturation = 0; 5580 5581 } else { 5582 5583 var delta = max - min; 5584 5585 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); 5586 5587 switch ( max ) { 5588 5589 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; 5590 case g: hue = ( b - r ) / delta + 2; break; 5591 case b: hue = ( r - g ) / delta + 4; break; 5592 5593 } 5594 5595 hue /= 6; 5596 5597 } 5598 5599 hsl.h = hue; 5600 hsl.s = saturation; 5601 hsl.l = lightness; 5602 5603 return hsl; 5604 5605 }, 5606 5607 getStyle: function () { 5608 5609 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; 5610 5611 }, 5612 5613 offsetHSL: function ( h, s, l ) { 5614 5615 var hsl = this.getHSL(); 5616 5617 hsl.h += h; hsl.s += s; hsl.l += l; 5618 5619 this.setHSL( hsl.h, hsl.s, hsl.l ); 5620 5621 return this; 5622 5623 }, 5624 5625 add: function ( color ) { 5626 5627 this.r += color.r; 5628 this.g += color.g; 5629 this.b += color.b; 5630 5631 return this; 5632 5633 }, 5634 5635 addColors: function ( color1, color2 ) { 5636 5637 this.r = color1.r + color2.r; 5638 this.g = color1.g + color2.g; 5639 this.b = color1.b + color2.b; 5640 5641 return this; 5642 5643 }, 5644 5645 addScalar: function ( s ) { 5646 5647 this.r += s; 5648 this.g += s; 5649 this.b += s; 5650 5651 return this; 5652 5653 }, 5654 5655 sub: function( color ) { 5656 5657 this.r = Math.max( 0, this.r - color.r ); 5658 this.g = Math.max( 0, this.g - color.g ); 5659 this.b = Math.max( 0, this.b - color.b ); 5660 5661 return this; 5662 5663 }, 5664 5665 multiply: function ( color ) { 5666 5667 this.r *= color.r; 5668 this.g *= color.g; 5669 this.b *= color.b; 5670 5671 return this; 5672 5673 }, 5674 5675 multiplyScalar: function ( s ) { 5676 5677 this.r *= s; 5678 this.g *= s; 5679 this.b *= s; 5680 5681 return this; 5682 5683 }, 5684 5685 lerp: function ( color, alpha ) { 5686 5687 this.r += ( color.r - this.r ) * alpha; 5688 this.g += ( color.g - this.g ) * alpha; 5689 this.b += ( color.b - this.b ) * alpha; 5690 5691 return this; 5692 5693 }, 5694 5695 equals: function ( c ) { 5696 5697 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); 5698 5699 }, 5700 5701 fromArray: function ( array, offset ) { 5702 5703 if ( offset === undefined ) offset = 0; 5704 5705 this.r = array[ offset ]; 5706 this.g = array[ offset + 1 ]; 5707 this.b = array[ offset + 2 ]; 5708 5709 return this; 5710 5711 }, 5712 5713 toArray: function ( array, offset ) { 5714 5715 if ( array === undefined ) array = []; 5716 if ( offset === undefined ) offset = 0; 5717 5718 array[ offset ] = this.r; 5719 array[ offset + 1 ] = this.g; 5720 array[ offset + 2 ] = this.b; 5721 5722 return array; 5723 5724 }, 5725 5726 toJSON: function () { 5727 5728 return this.getHex(); 5729 5730 } 5731 5732 }; 5733 5734 var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 5735 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 5736 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 5737 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 5738 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 5739 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 5740 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 5741 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 5742 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 5743 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 5744 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 5745 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 5746 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 5747 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 5748 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 5749 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 5750 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 5751 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 5752 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 5753 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 5754 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 5755 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 5756 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 5757 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; 5758 5759 /** 5760 * @author alteredq / http://alteredqualia.com/ 5761 */ 5762 5763 function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { 5764 5765 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); 5766 5767 this.image = { data: data, width: width, height: height }; 5768 5769 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; 5770 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; 5771 5772 this.generateMipmaps = false; 5773 this.flipY = false; 5774 this.unpackAlignment = 1; 5775 5776 } 5777 5778 DataTexture.prototype = Object.create( Texture.prototype ); 5779 DataTexture.prototype.constructor = DataTexture; 5780 5781 DataTexture.prototype.isDataTexture = true; 5782 5783 /** 5784 * Uniforms library for shared webgl shaders 5785 */ 5786 5787 var UniformsLib = { 5788 5789 common: { 5790 5791 diffuse: { value: new Color( 0xeeeeee ) }, 5792 opacity: { value: 1.0 }, 5793 5794 map: { value: null }, 5795 offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }, 5796 5797 specularMap: { value: null }, 5798 alphaMap: { value: null }, 5799 5800 envMap: { value: null }, 5801 flipEnvMap: { value: - 1 }, 5802 reflectivity: { value: 1.0 }, 5803 refractionRatio: { value: 0.98 } 5804 5805 }, 5806 5807 aomap: { 5808 5809 aoMap: { value: null }, 5810 aoMapIntensity: { value: 1 } 5811 5812 }, 5813 5814 lightmap: { 5815 5816 lightMap: { value: null }, 5817 lightMapIntensity: { value: 1 } 5818 5819 }, 5820 5821 emissivemap: { 5822 5823 emissiveMap: { value: null } 5824 5825 }, 5826 5827 bumpmap: { 5828 5829 bumpMap: { value: null }, 5830 bumpScale: { value: 1 } 5831 5832 }, 5833 5834 normalmap: { 5835 5836 normalMap: { value: null }, 5837 normalScale: { value: new Vector2( 1, 1 ) } 5838 5839 }, 5840 5841 displacementmap: { 5842 5843 displacementMap: { value: null }, 5844 displacementScale: { value: 1 }, 5845 displacementBias: { value: 0 } 5846 5847 }, 5848 5849 roughnessmap: { 5850 5851 roughnessMap: { value: null } 5852 5853 }, 5854 5855 metalnessmap: { 5856 5857 metalnessMap: { value: null } 5858 5859 }, 5860 5861 gradientmap: { 5862 5863 gradientMap: { value: null } 5864 5865 }, 5866 5867 fog: { 5868 5869 fogDensity: { value: 0.00025 }, 5870 fogNear: { value: 1 }, 5871 fogFar: { value: 2000 }, 5872 fogColor: { value: new Color( 0xffffff ) } 5873 5874 }, 5875 5876 lights: { 5877 5878 ambientLightColor: { value: [] }, 5879 5880 directionalLights: { value: [], properties: { 5881 direction: {}, 5882 color: {}, 5883 5884 shadow: {}, 5885 shadowBias: {}, 5886 shadowRadius: {}, 5887 shadowMapSize: {} 5888 } }, 5889 5890 directionalShadowMap: { value: [] }, 5891 directionalShadowMatrix: { value: [] }, 5892 5893 spotLights: { value: [], properties: { 5894 color: {}, 5895 position: {}, 5896 direction: {}, 5897 distance: {}, 5898 coneCos: {}, 5899 penumbraCos: {}, 5900 decay: {}, 5901 5902 shadow: {}, 5903 shadowBias: {}, 5904 shadowRadius: {}, 5905 shadowMapSize: {} 5906 } }, 5907 5908 spotShadowMap: { value: [] }, 5909 spotShadowMatrix: { value: [] }, 5910 5911 pointLights: { value: [], properties: { 5912 color: {}, 5913 position: {}, 5914 decay: {}, 5915 distance: {}, 5916 5917 shadow: {}, 5918 shadowBias: {}, 5919 shadowRadius: {}, 5920 shadowMapSize: {} 5921 } }, 5922 5923 pointShadowMap: { value: [] }, 5924 pointShadowMatrix: { value: [] }, 5925 5926 hemisphereLights: { value: [], properties: { 5927 direction: {}, 5928 skyColor: {}, 5929 groundColor: {} 5930 } }, 5931 5932 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 5933 rectAreaLights: { value: [], properties: { 5934 color: {}, 5935 position: {}, 5936 width: {}, 5937 height: {} 5938 } } 5939 5940 }, 5941 5942 points: { 5943 5944 diffuse: { value: new Color( 0xeeeeee ) }, 5945 opacity: { value: 1.0 }, 5946 size: { value: 1.0 }, 5947 scale: { value: 1.0 }, 5948 map: { value: null }, 5949 offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) } 5950 5951 } 5952 5953 }; 5954 5955 /** 5956 * @author alteredq / http://alteredqualia.com/ 5957 * @author mrdoob / http://mrdoob.com/ 5958 * @author mikael emtinger / http://gomo.se/ 5959 */ 5960 5961 var ShaderLib = { 5962 5963 basic: { 5964 5965 uniforms: UniformsUtils.merge( [ 5966 UniformsLib.common, 5967 UniformsLib.aomap, 5968 UniformsLib.lightmap, 5969 UniformsLib.fog 5970 ] ), 5971 5972 vertexShader: ShaderChunk.meshbasic_vert, 5973 fragmentShader: ShaderChunk.meshbasic_frag 5974 5975 }, 5976 5977 lambert: { 5978 5979 uniforms: UniformsUtils.merge( [ 5980 UniformsLib.common, 5981 UniformsLib.aomap, 5982 UniformsLib.lightmap, 5983 UniformsLib.emissivemap, 5984 UniformsLib.fog, 5985 UniformsLib.lights, 5986 { 5987 emissive: { value: new Color( 0x000000 ) } 5988 } 5989 ] ), 5990 5991 vertexShader: ShaderChunk.meshlambert_vert, 5992 fragmentShader: ShaderChunk.meshlambert_frag 5993 5994 }, 5995 5996 phong: { 5997 5998 uniforms: UniformsUtils.merge( [ 5999 UniformsLib.common, 6000 UniformsLib.aomap, 6001 UniformsLib.lightmap, 6002 UniformsLib.emissivemap, 6003 UniformsLib.bumpmap, 6004 UniformsLib.normalmap, 6005 UniformsLib.displacementmap, 6006 UniformsLib.gradientmap, 6007 UniformsLib.fog, 6008 UniformsLib.lights, 6009 { 6010 emissive: { value: new Color( 0x000000 ) }, 6011 specular: { value: new Color( 0x111111 ) }, 6012 shininess: { value: 30 } 6013 } 6014 ] ), 6015 6016 vertexShader: ShaderChunk.meshphong_vert, 6017 fragmentShader: ShaderChunk.meshphong_frag 6018 6019 }, 6020 6021 standard: { 6022 6023 uniforms: UniformsUtils.merge( [ 6024 UniformsLib.common, 6025 UniformsLib.aomap, 6026 UniformsLib.lightmap, 6027 UniformsLib.emissivemap, 6028 UniformsLib.bumpmap, 6029 UniformsLib.normalmap, 6030 UniformsLib.displacementmap, 6031 UniformsLib.roughnessmap, 6032 UniformsLib.metalnessmap, 6033 UniformsLib.fog, 6034 UniformsLib.lights, 6035 { 6036 emissive: { value: new Color( 0x000000 ) }, 6037 roughness: { value: 0.5 }, 6038 metalness: { value: 0 }, 6039 envMapIntensity: { value: 1 } // temporary 6040 } 6041 ] ), 6042 6043 vertexShader: ShaderChunk.meshphysical_vert, 6044 fragmentShader: ShaderChunk.meshphysical_frag 6045 6046 }, 6047 6048 points: { 6049 6050 uniforms: UniformsUtils.merge( [ 6051 UniformsLib.points, 6052 UniformsLib.fog 6053 ] ), 6054 6055 vertexShader: ShaderChunk.points_vert, 6056 fragmentShader: ShaderChunk.points_frag 6057 6058 }, 6059 6060 dashed: { 6061 6062 uniforms: UniformsUtils.merge( [ 6063 UniformsLib.common, 6064 UniformsLib.fog, 6065 { 6066 scale: { value: 1 }, 6067 dashSize: { value: 1 }, 6068 totalSize: { value: 2 } 6069 } 6070 ] ), 6071 6072 vertexShader: ShaderChunk.linedashed_vert, 6073 fragmentShader: ShaderChunk.linedashed_frag 6074 6075 }, 6076 6077 depth: { 6078 6079 uniforms: UniformsUtils.merge( [ 6080 UniformsLib.common, 6081 UniformsLib.displacementmap 6082 ] ), 6083 6084 vertexShader: ShaderChunk.depth_vert, 6085 fragmentShader: ShaderChunk.depth_frag 6086 6087 }, 6088 6089 normal: { 6090 6091 uniforms: UniformsUtils.merge( [ 6092 UniformsLib.common, 6093 UniformsLib.bumpmap, 6094 UniformsLib.normalmap, 6095 UniformsLib.displacementmap, 6096 { 6097 opacity: { value: 1.0 } 6098 } 6099 ] ), 6100 6101 vertexShader: ShaderChunk.normal_vert, 6102 fragmentShader: ShaderChunk.normal_frag 6103 6104 }, 6105 6106 /* ------------------------------------------------------------------------- 6107 // Cube map shader 6108 ------------------------------------------------------------------------- */ 6109 6110 cube: { 6111 6112 uniforms: { 6113 tCube: { value: null }, 6114 tFlip: { value: - 1 }, 6115 opacity: { value: 1.0 } 6116 }, 6117 6118 vertexShader: ShaderChunk.cube_vert, 6119 fragmentShader: ShaderChunk.cube_frag 6120 6121 }, 6122 6123 /* ------------------------------------------------------------------------- 6124 // Cube map shader 6125 ------------------------------------------------------------------------- */ 6126 6127 equirect: { 6128 6129 uniforms: { 6130 tEquirect: { value: null }, 6131 tFlip: { value: - 1 } 6132 }, 6133 6134 vertexShader: ShaderChunk.equirect_vert, 6135 fragmentShader: ShaderChunk.equirect_frag 6136 6137 }, 6138 6139 distanceRGBA: { 6140 6141 uniforms: { 6142 lightPos: { value: new Vector3() } 6143 }, 6144 6145 vertexShader: ShaderChunk.distanceRGBA_vert, 6146 fragmentShader: ShaderChunk.distanceRGBA_frag 6147 6148 } 6149 6150 }; 6151 6152 ShaderLib.physical = { 6153 6154 uniforms: UniformsUtils.merge( [ 6155 ShaderLib.standard.uniforms, 6156 { 6157 clearCoat: { value: 0 }, 6158 clearCoatRoughness: { value: 0 } 6159 } 6160 ] ), 6161 6162 vertexShader: ShaderChunk.meshphysical_vert, 6163 fragmentShader: ShaderChunk.meshphysical_frag 6164 6165 }; 6166 6167 /** 6168 * @author bhouston / http://clara.io 6169 */ 6170 6171 function Box2( min, max ) { 6172 6173 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); 6174 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); 6175 6176 } 6177 6178 Box2.prototype = { 6179 6180 constructor: Box2, 6181 6182 set: function ( min, max ) { 6183 6184 this.min.copy( min ); 6185 this.max.copy( max ); 6186 6187 return this; 6188 6189 }, 6190 6191 setFromPoints: function ( points ) { 6192 6193 this.makeEmpty(); 6194 6195 for ( var i = 0, il = points.length; i < il; i ++ ) { 6196 6197 this.expandByPoint( points[ i ] ); 6198 6199 } 6200 6201 return this; 6202 6203 }, 6204 6205 setFromCenterAndSize: function () { 6206 6207 var v1 = new Vector2(); 6208 6209 return function setFromCenterAndSize( center, size ) { 6210 6211 var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); 6212 this.min.copy( center ).sub( halfSize ); 6213 this.max.copy( center ).add( halfSize ); 6214 6215 return this; 6216 6217 }; 6218 6219 }(), 6220 6221 clone: function () { 6222 6223 return new this.constructor().copy( this ); 6224 6225 }, 6226 6227 copy: function ( box ) { 6228 6229 this.min.copy( box.min ); 6230 this.max.copy( box.max ); 6231 6232 return this; 6233 6234 }, 6235 6236 makeEmpty: function () { 6237 6238 this.min.x = this.min.y = + Infinity; 6239 this.max.x = this.max.y = - Infinity; 6240 6241 return this; 6242 6243 }, 6244 6245 isEmpty: function () { 6246 6247 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 6248 6249 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); 6250 6251 }, 6252 6253 getCenter: function ( optionalTarget ) { 6254 6255 var result = optionalTarget || new Vector2(); 6256 return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 6257 6258 }, 6259 6260 getSize: function ( optionalTarget ) { 6261 6262 var result = optionalTarget || new Vector2(); 6263 return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min ); 6264 6265 }, 6266 6267 expandByPoint: function ( point ) { 6268 6269 this.min.min( point ); 6270 this.max.max( point ); 6271 6272 return this; 6273 6274 }, 6275 6276 expandByVector: function ( vector ) { 6277 6278 this.min.sub( vector ); 6279 this.max.add( vector ); 6280 6281 return this; 6282 6283 }, 6284 6285 expandByScalar: function ( scalar ) { 6286 6287 this.min.addScalar( - scalar ); 6288 this.max.addScalar( scalar ); 6289 6290 return this; 6291 6292 }, 6293 6294 containsPoint: function ( point ) { 6295 6296 return point.x < this.min.x || point.x > this.max.x || 6297 point.y < this.min.y || point.y > this.max.y ? false : true; 6298 6299 }, 6300 6301 containsBox: function ( box ) { 6302 6303 return this.min.x <= box.min.x && box.max.x <= this.max.x && 6304 this.min.y <= box.min.y && box.max.y <= this.max.y; 6305 6306 }, 6307 6308 getParameter: function ( point, optionalTarget ) { 6309 6310 // This can potentially have a divide by zero if the box 6311 // has a size dimension of 0. 6312 6313 var result = optionalTarget || new Vector2(); 6314 6315 return result.set( 6316 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 6317 ( point.y - this.min.y ) / ( this.max.y - this.min.y ) 6318 ); 6319 6320 }, 6321 6322 intersectsBox: function ( box ) { 6323 6324 // using 6 splitting planes to rule out intersections. 6325 return box.max.x < this.min.x || box.min.x > this.max.x || 6326 box.max.y < this.min.y || box.min.y > this.max.y ? false : true; 6327 6328 }, 6329 6330 clampPoint: function ( point, optionalTarget ) { 6331 6332 var result = optionalTarget || new Vector2(); 6333 return result.copy( point ).clamp( this.min, this.max ); 6334 6335 }, 6336 6337 distanceToPoint: function () { 6338 6339 var v1 = new Vector2(); 6340 6341 return function distanceToPoint( point ) { 6342 6343 var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); 6344 return clampedPoint.sub( point ).length(); 6345 6346 }; 6347 6348 }(), 6349 6350 intersect: function ( box ) { 6351 6352 this.min.max( box.min ); 6353 this.max.min( box.max ); 6354 6355 return this; 6356 6357 }, 6358 6359 union: function ( box ) { 6360 6361 this.min.min( box.min ); 6362 this.max.max( box.max ); 6363 6364 return this; 6365 6366 }, 6367 6368 translate: function ( offset ) { 6369 6370 this.min.add( offset ); 6371 this.max.add( offset ); 6372 6373 return this; 6374 6375 }, 6376 6377 equals: function ( box ) { 6378 6379 return box.min.equals( this.min ) && box.max.equals( this.max ); 6380 6381 } 6382 6383 }; 6384 6385 /** 6386 * @author mikael emtinger / http://gomo.se/ 6387 * @author alteredq / http://alteredqualia.com/ 6388 */ 6389 6390 function LensFlarePlugin( renderer, flares ) { 6391 6392 var gl = renderer.context; 6393 var state = renderer.state; 6394 6395 var vertexBuffer, elementBuffer; 6396 var shader, program, attributes, uniforms; 6397 6398 var tempTexture, occlusionTexture; 6399 6400 function init() { 6401 6402 var vertices = new Float32Array( [ 6403 - 1, - 1, 0, 0, 6404 1, - 1, 1, 0, 6405 1, 1, 1, 1, 6406 - 1, 1, 0, 1 6407 ] ); 6408 6409 var faces = new Uint16Array( [ 6410 0, 1, 2, 6411 0, 2, 3 6412 ] ); 6413 6414 // buffers 6415 6416 vertexBuffer = gl.createBuffer(); 6417 elementBuffer = gl.createBuffer(); 6418 6419 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); 6420 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); 6421 6422 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); 6423 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); 6424 6425 // textures 6426 6427 tempTexture = gl.createTexture(); 6428 occlusionTexture = gl.createTexture(); 6429 6430 state.bindTexture( gl.TEXTURE_2D, tempTexture ); 6431 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); 6432 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); 6433 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); 6434 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); 6435 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); 6436 6437 state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); 6438 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); 6439 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); 6440 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); 6441 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); 6442 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); 6443 6444 shader = { 6445 6446 vertexShader: [ 6447 6448 "uniform lowp int renderType;", 6449 6450 "uniform vec3 screenPosition;", 6451 "uniform vec2 scale;", 6452 "uniform float rotation;", 6453 6454 "uniform sampler2D occlusionMap;", 6455 6456 "attribute vec2 position;", 6457 "attribute vec2 uv;", 6458 6459 "varying vec2 vUV;", 6460 "varying float vVisibility;", 6461 6462 "void main() {", 6463 6464 "vUV = uv;", 6465 6466 "vec2 pos = position;", 6467 6468 "if ( renderType == 2 ) {", 6469 6470 "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", 6471 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", 6472 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", 6473 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", 6474 "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", 6475 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", 6476 "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", 6477 "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", 6478 "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", 6479 6480 "vVisibility = visibility.r / 9.0;", 6481 "vVisibility *= 1.0 - visibility.g / 9.0;", 6482 "vVisibility *= visibility.b / 9.0;", 6483 "vVisibility *= 1.0 - visibility.a / 9.0;", 6484 6485 "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", 6486 "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", 6487 6488 "}", 6489 6490 "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", 6491 6492 "}" 6493 6494 ].join( "\n" ), 6495 6496 fragmentShader: [ 6497 6498 "uniform lowp int renderType;", 6499 6500 "uniform sampler2D map;", 6501 "uniform float opacity;", 6502 "uniform vec3 color;", 6503 6504 "varying vec2 vUV;", 6505 "varying float vVisibility;", 6506 6507 "void main() {", 6508 6509 // pink square 6510 6511 "if ( renderType == 0 ) {", 6512 6513 "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", 6514 6515 // restore 6516 6517 "} else if ( renderType == 1 ) {", 6518 6519 "gl_FragColor = texture2D( map, vUV );", 6520 6521 // flare 6522 6523 "} else {", 6524 6525 "vec4 texture = texture2D( map, vUV );", 6526 "texture.a *= opacity * vVisibility;", 6527 "gl_FragColor = texture;", 6528 "gl_FragColor.rgb *= color;", 6529 6530 "}", 6531 6532 "}" 6533 6534 ].join( "\n" ) 6535 6536 }; 6537 6538 program = createProgram( shader ); 6539 6540 attributes = { 6541 vertex: gl.getAttribLocation ( program, "position" ), 6542 uv: gl.getAttribLocation ( program, "uv" ) 6543 }; 6544 6545 uniforms = { 6546 renderType: gl.getUniformLocation( program, "renderType" ), 6547 map: gl.getUniformLocation( program, "map" ), 6548 occlusionMap: gl.getUniformLocation( program, "occlusionMap" ), 6549 opacity: gl.getUniformLocation( program, "opacity" ), 6550 color: gl.getUniformLocation( program, "color" ), 6551 scale: gl.getUniformLocation( program, "scale" ), 6552 rotation: gl.getUniformLocation( program, "rotation" ), 6553 screenPosition: gl.getUniformLocation( program, "screenPosition" ) 6554 }; 6555 6556 } 6557 6558 /* 6559 * Render lens flares 6560 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, 6561 * reads these back and calculates occlusion. 6562 */ 6563 6564 this.render = function ( scene, camera, viewport ) { 6565 6566 if ( flares.length === 0 ) return; 6567 6568 var tempPosition = new Vector3(); 6569 6570 var invAspect = viewport.w / viewport.z, 6571 halfViewportWidth = viewport.z * 0.5, 6572 halfViewportHeight = viewport.w * 0.5; 6573 6574 var size = 16 / viewport.w, 6575 scale = new Vector2( size * invAspect, size ); 6576 6577 var screenPosition = new Vector3( 1, 1, 0 ), 6578 screenPositionPixels = new Vector2( 1, 1 ); 6579 6580 var validArea = new Box2(); 6581 6582 validArea.min.set( viewport.x, viewport.y ); 6583 validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); 6584 6585 if ( program === undefined ) { 6586 6587 init(); 6588 6589 } 6590 6591 gl.useProgram( program ); 6592 6593 state.initAttributes(); 6594 state.enableAttribute( attributes.vertex ); 6595 state.enableAttribute( attributes.uv ); 6596 state.disableUnusedAttributes(); 6597 6598 // loop through all lens flares to update their occlusion and positions 6599 // setup gl and common used attribs/uniforms 6600 6601 gl.uniform1i( uniforms.occlusionMap, 0 ); 6602 gl.uniform1i( uniforms.map, 1 ); 6603 6604 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); 6605 gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); 6606 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); 6607 6608 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); 6609 6610 state.disable( gl.CULL_FACE ); 6611 state.setDepthWrite( false ); 6612 6613 for ( var i = 0, l = flares.length; i < l; i ++ ) { 6614 6615 size = 16 / viewport.w; 6616 scale.set( size * invAspect, size ); 6617 6618 // calc object screen position 6619 6620 var flare = flares[ i ]; 6621 6622 tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); 6623 6624 tempPosition.applyMatrix4( camera.matrixWorldInverse ); 6625 tempPosition.applyMatrix4( camera.projectionMatrix ); 6626 6627 // setup arrays for gl programs 6628 6629 screenPosition.copy( tempPosition ); 6630 6631 // horizontal and vertical coordinate of the lower left corner of the pixels to copy 6632 6633 screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8; 6634 screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8; 6635 6636 // screen cull 6637 6638 if ( validArea.containsPoint( screenPositionPixels ) === true ) { 6639 6640 // save current RGB to temp texture 6641 6642 state.activeTexture( gl.TEXTURE0 ); 6643 state.bindTexture( gl.TEXTURE_2D, null ); 6644 state.activeTexture( gl.TEXTURE1 ); 6645 state.bindTexture( gl.TEXTURE_2D, tempTexture ); 6646 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); 6647 6648 6649 // render pink quad 6650 6651 gl.uniform1i( uniforms.renderType, 0 ); 6652 gl.uniform2f( uniforms.scale, scale.x, scale.y ); 6653 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); 6654 6655 state.disable( gl.BLEND ); 6656 state.enable( gl.DEPTH_TEST ); 6657 6658 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); 6659 6660 6661 // copy result to occlusionMap 6662 6663 state.activeTexture( gl.TEXTURE0 ); 6664 state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); 6665 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); 6666 6667 6668 // restore graphics 6669 6670 gl.uniform1i( uniforms.renderType, 1 ); 6671 state.disable( gl.DEPTH_TEST ); 6672 6673 state.activeTexture( gl.TEXTURE1 ); 6674 state.bindTexture( gl.TEXTURE_2D, tempTexture ); 6675 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); 6676 6677 6678 // update object positions 6679 6680 flare.positionScreen.copy( screenPosition ); 6681 6682 if ( flare.customUpdateCallback ) { 6683 6684 flare.customUpdateCallback( flare ); 6685 6686 } else { 6687 6688 flare.updateLensFlares(); 6689 6690 } 6691 6692 // render flares 6693 6694 gl.uniform1i( uniforms.renderType, 2 ); 6695 state.enable( gl.BLEND ); 6696 6697 for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { 6698 6699 var sprite = flare.lensFlares[ j ]; 6700 6701 if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { 6702 6703 screenPosition.x = sprite.x; 6704 screenPosition.y = sprite.y; 6705 screenPosition.z = sprite.z; 6706 6707 size = sprite.size * sprite.scale / viewport.w; 6708 6709 scale.x = size * invAspect; 6710 scale.y = size; 6711 6712 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); 6713 gl.uniform2f( uniforms.scale, scale.x, scale.y ); 6714 gl.uniform1f( uniforms.rotation, sprite.rotation ); 6715 6716 gl.uniform1f( uniforms.opacity, sprite.opacity ); 6717 gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); 6718 6719 state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); 6720 renderer.setTexture2D( sprite.texture, 1 ); 6721 6722 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); 6723 6724 } 6725 6726 } 6727 6728 } 6729 6730 } 6731 6732 // restore gl 6733 6734 state.enable( gl.CULL_FACE ); 6735 state.enable( gl.DEPTH_TEST ); 6736 state.setDepthWrite( true ); 6737 6738 renderer.resetGLState(); 6739 6740 }; 6741 6742 function createProgram( shader ) { 6743 6744 var program = gl.createProgram(); 6745 6746 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); 6747 var vertexShader = gl.createShader( gl.VERTEX_SHADER ); 6748 6749 var prefix = "precision " + renderer.getPrecision() + " float;\n"; 6750 6751 gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); 6752 gl.shaderSource( vertexShader, prefix + shader.vertexShader ); 6753 6754 gl.compileShader( fragmentShader ); 6755 gl.compileShader( vertexShader ); 6756 6757 gl.attachShader( program, fragmentShader ); 6758 gl.attachShader( program, vertexShader ); 6759 6760 gl.linkProgram( program ); 6761 6762 return program; 6763 6764 } 6765 6766 } 6767 6768 /** 6769 * @author mikael emtinger / http://gomo.se/ 6770 * @author alteredq / http://alteredqualia.com/ 6771 */ 6772 6773 function SpritePlugin( renderer, sprites ) { 6774 6775 var gl = renderer.context; 6776 var state = renderer.state; 6777 6778 var vertexBuffer, elementBuffer; 6779 var program, attributes, uniforms; 6780 6781 var texture; 6782 6783 // decompose matrixWorld 6784 6785 var spritePosition = new Vector3(); 6786 var spriteRotation = new Quaternion(); 6787 var spriteScale = new Vector3(); 6788 6789 function init() { 6790 6791 var vertices = new Float32Array( [ 6792 - 0.5, - 0.5, 0, 0, 6793 0.5, - 0.5, 1, 0, 6794 0.5, 0.5, 1, 1, 6795 - 0.5, 0.5, 0, 1 6796 ] ); 6797 6798 var faces = new Uint16Array( [ 6799 0, 1, 2, 6800 0, 2, 3 6801 ] ); 6802 6803 vertexBuffer = gl.createBuffer(); 6804 elementBuffer = gl.createBuffer(); 6805 6806 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); 6807 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); 6808 6809 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); 6810 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); 6811 6812 program = createProgram(); 6813 6814 attributes = { 6815 position: gl.getAttribLocation ( program, 'position' ), 6816 uv: gl.getAttribLocation ( program, 'uv' ) 6817 }; 6818 6819 uniforms = { 6820 uvOffset: gl.getUniformLocation( program, 'uvOffset' ), 6821 uvScale: gl.getUniformLocation( program, 'uvScale' ), 6822 6823 rotation: gl.getUniformLocation( program, 'rotation' ), 6824 scale: gl.getUniformLocation( program, 'scale' ), 6825 6826 color: gl.getUniformLocation( program, 'color' ), 6827 map: gl.getUniformLocation( program, 'map' ), 6828 opacity: gl.getUniformLocation( program, 'opacity' ), 6829 6830 modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), 6831 projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), 6832 6833 fogType: gl.getUniformLocation( program, 'fogType' ), 6834 fogDensity: gl.getUniformLocation( program, 'fogDensity' ), 6835 fogNear: gl.getUniformLocation( program, 'fogNear' ), 6836 fogFar: gl.getUniformLocation( program, 'fogFar' ), 6837 fogColor: gl.getUniformLocation( program, 'fogColor' ), 6838 6839 alphaTest: gl.getUniformLocation( program, 'alphaTest' ) 6840 }; 6841 6842 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); 6843 canvas.width = 8; 6844 canvas.height = 8; 6845 6846 var context = canvas.getContext( '2d' ); 6847 context.fillStyle = 'white'; 6848 context.fillRect( 0, 0, 8, 8 ); 6849 6850 texture = new Texture( canvas ); 6851 texture.needsUpdate = true; 6852 6853 } 6854 6855 this.render = function ( scene, camera ) { 6856 6857 if ( sprites.length === 0 ) return; 6858 6859 // setup gl 6860 6861 if ( program === undefined ) { 6862 6863 init(); 6864 6865 } 6866 6867 gl.useProgram( program ); 6868 6869 state.initAttributes(); 6870 state.enableAttribute( attributes.position ); 6871 state.enableAttribute( attributes.uv ); 6872 state.disableUnusedAttributes(); 6873 6874 state.disable( gl.CULL_FACE ); 6875 state.enable( gl.BLEND ); 6876 6877 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); 6878 gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); 6879 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); 6880 6881 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); 6882 6883 gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); 6884 6885 state.activeTexture( gl.TEXTURE0 ); 6886 gl.uniform1i( uniforms.map, 0 ); 6887 6888 var oldFogType = 0; 6889 var sceneFogType = 0; 6890 var fog = scene.fog; 6891 6892 if ( fog ) { 6893 6894 gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); 6895 6896 if ( fog.isFog ) { 6897 6898 gl.uniform1f( uniforms.fogNear, fog.near ); 6899 gl.uniform1f( uniforms.fogFar, fog.far ); 6900 6901 gl.uniform1i( uniforms.fogType, 1 ); 6902 oldFogType = 1; 6903 sceneFogType = 1; 6904 6905 } else if ( fog.isFogExp2 ) { 6906 6907 gl.uniform1f( uniforms.fogDensity, fog.density ); 6908 6909 gl.uniform1i( uniforms.fogType, 2 ); 6910 oldFogType = 2; 6911 sceneFogType = 2; 6912 6913 } 6914 6915 } else { 6916 6917 gl.uniform1i( uniforms.fogType, 0 ); 6918 oldFogType = 0; 6919 sceneFogType = 0; 6920 6921 } 6922 6923 6924 // update positions and sort 6925 6926 for ( var i = 0, l = sprites.length; i < l; i ++ ) { 6927 6928 var sprite = sprites[ i ]; 6929 6930 sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); 6931 sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; 6932 6933 } 6934 6935 sprites.sort( painterSortStable ); 6936 6937 // render all sprites 6938 6939 var scale = []; 6940 6941 for ( var i = 0, l = sprites.length; i < l; i ++ ) { 6942 6943 var sprite = sprites[ i ]; 6944 var material = sprite.material; 6945 6946 if ( material.visible === false ) continue; 6947 6948 gl.uniform1f( uniforms.alphaTest, material.alphaTest ); 6949 gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); 6950 6951 sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); 6952 6953 scale[ 0 ] = spriteScale.x; 6954 scale[ 1 ] = spriteScale.y; 6955 6956 var fogType = 0; 6957 6958 if ( scene.fog && material.fog ) { 6959 6960 fogType = sceneFogType; 6961 6962 } 6963 6964 if ( oldFogType !== fogType ) { 6965 6966 gl.uniform1i( uniforms.fogType, fogType ); 6967 oldFogType = fogType; 6968 6969 } 6970 6971 if ( material.map !== null ) { 6972 6973 gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); 6974 gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); 6975 6976 } else { 6977 6978 gl.uniform2f( uniforms.uvOffset, 0, 0 ); 6979 gl.uniform2f( uniforms.uvScale, 1, 1 ); 6980 6981 } 6982 6983 gl.uniform1f( uniforms.opacity, material.opacity ); 6984 gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); 6985 6986 gl.uniform1f( uniforms.rotation, material.rotation ); 6987 gl.uniform2fv( uniforms.scale, scale ); 6988 6989 state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); 6990 state.setDepthTest( material.depthTest ); 6991 state.setDepthWrite( material.depthWrite ); 6992 6993 if ( material.map ) { 6994 6995 renderer.setTexture2D( material.map, 0 ); 6996 6997 } else { 6998 6999 renderer.setTexture2D( texture, 0 ); 7000 7001 } 7002 7003 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); 7004 7005 } 7006 7007 // restore gl 7008 7009 state.enable( gl.CULL_FACE ); 7010 7011 renderer.resetGLState(); 7012 7013 }; 7014 7015 function createProgram() { 7016 7017 var program = gl.createProgram(); 7018 7019 var vertexShader = gl.createShader( gl.VERTEX_SHADER ); 7020 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); 7021 7022 gl.shaderSource( vertexShader, [ 7023 7024 'precision ' + renderer.getPrecision() + ' float;', 7025 7026 'uniform mat4 modelViewMatrix;', 7027 'uniform mat4 projectionMatrix;', 7028 'uniform float rotation;', 7029 'uniform vec2 scale;', 7030 'uniform vec2 uvOffset;', 7031 'uniform vec2 uvScale;', 7032 7033 'attribute vec2 position;', 7034 'attribute vec2 uv;', 7035 7036 'varying vec2 vUV;', 7037 7038 'void main() {', 7039 7040 'vUV = uvOffset + uv * uvScale;', 7041 7042 'vec2 alignedPosition = position * scale;', 7043 7044 'vec2 rotatedPosition;', 7045 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', 7046 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', 7047 7048 'vec4 finalPosition;', 7049 7050 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', 7051 'finalPosition.xy += rotatedPosition;', 7052 'finalPosition = projectionMatrix * finalPosition;', 7053 7054 'gl_Position = finalPosition;', 7055 7056 '}' 7057 7058 ].join( '\n' ) ); 7059 7060 gl.shaderSource( fragmentShader, [ 7061 7062 'precision ' + renderer.getPrecision() + ' float;', 7063 7064 'uniform vec3 color;', 7065 'uniform sampler2D map;', 7066 'uniform float opacity;', 7067 7068 'uniform int fogType;', 7069 'uniform vec3 fogColor;', 7070 'uniform float fogDensity;', 7071 'uniform float fogNear;', 7072 'uniform float fogFar;', 7073 'uniform float alphaTest;', 7074 7075 'varying vec2 vUV;', 7076 7077 'void main() {', 7078 7079 'vec4 texture = texture2D( map, vUV );', 7080 7081 'if ( texture.a < alphaTest ) discard;', 7082 7083 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', 7084 7085 'if ( fogType > 0 ) {', 7086 7087 'float depth = gl_FragCoord.z / gl_FragCoord.w;', 7088 'float fogFactor = 0.0;', 7089 7090 'if ( fogType == 1 ) {', 7091 7092 'fogFactor = smoothstep( fogNear, fogFar, depth );', 7093 7094 '} else {', 7095 7096 'const float LOG2 = 1.442695;', 7097 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', 7098 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', 7099 7100 '}', 7101 7102 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', 7103 7104 '}', 7105 7106 '}' 7107 7108 ].join( '\n' ) ); 7109 7110 gl.compileShader( vertexShader ); 7111 gl.compileShader( fragmentShader ); 7112 7113 gl.attachShader( program, vertexShader ); 7114 gl.attachShader( program, fragmentShader ); 7115 7116 gl.linkProgram( program ); 7117 7118 return program; 7119 7120 } 7121 7122 function painterSortStable( a, b ) { 7123 7124 if ( a.renderOrder !== b.renderOrder ) { 7125 7126 return a.renderOrder - b.renderOrder; 7127 7128 } else if ( a.z !== b.z ) { 7129 7130 return b.z - a.z; 7131 7132 } else { 7133 7134 return b.id - a.id; 7135 7136 } 7137 7138 } 7139 7140 } 7141 7142 /** 7143 * @author mrdoob / http://mrdoob.com/ 7144 * @author alteredq / http://alteredqualia.com/ 7145 */ 7146 7147 var materialId = 0; 7148 7149 function Material() { 7150 7151 Object.defineProperty( this, 'id', { value: materialId ++ } ); 7152 7153 this.uuid = _Math.generateUUID(); 7154 7155 this.name = ''; 7156 this.type = 'Material'; 7157 7158 this.fog = true; 7159 this.lights = true; 7160 7161 this.blending = NormalBlending; 7162 this.side = FrontSide; 7163 this.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading 7164 this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors 7165 7166 this.opacity = 1; 7167 this.transparent = false; 7168 7169 this.blendSrc = SrcAlphaFactor; 7170 this.blendDst = OneMinusSrcAlphaFactor; 7171 this.blendEquation = AddEquation; 7172 this.blendSrcAlpha = null; 7173 this.blendDstAlpha = null; 7174 this.blendEquationAlpha = null; 7175 7176 this.depthFunc = LessEqualDepth; 7177 this.depthTest = true; 7178 this.depthWrite = true; 7179 7180 this.clippingPlanes = null; 7181 this.clipIntersection = false; 7182 this.clipShadows = false; 7183 7184 this.colorWrite = true; 7185 7186 this.precision = null; // override the renderer's default precision for this material 7187 7188 this.polygonOffset = false; 7189 this.polygonOffsetFactor = 0; 7190 this.polygonOffsetUnits = 0; 7191 7192 this.alphaTest = 0; 7193 this.premultipliedAlpha = false; 7194 7195 this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer 7196 7197 this.visible = true; 7198 7199 this._needsUpdate = true; 7200 7201 } 7202 7203 Material.prototype = { 7204 7205 constructor: Material, 7206 7207 isMaterial: true, 7208 7209 get needsUpdate() { 7210 7211 return this._needsUpdate; 7212 7213 }, 7214 7215 set needsUpdate( value ) { 7216 7217 if ( value === true ) this.update(); 7218 this._needsUpdate = value; 7219 7220 }, 7221 7222 setValues: function ( values ) { 7223 7224 if ( values === undefined ) return; 7225 7226 for ( var key in values ) { 7227 7228 var newValue = values[ key ]; 7229 7230 if ( newValue === undefined ) { 7231 7232 console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); 7233 continue; 7234 7235 } 7236 7237 var currentValue = this[ key ]; 7238 7239 if ( currentValue === undefined ) { 7240 7241 console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); 7242 continue; 7243 7244 } 7245 7246 if ( currentValue && currentValue.isColor ) { 7247 7248 currentValue.set( newValue ); 7249 7250 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { 7251 7252 currentValue.copy( newValue ); 7253 7254 } else if ( key === 'overdraw' ) { 7255 7256 // ensure overdraw is backwards-compatible with legacy boolean type 7257 this[ key ] = Number( newValue ); 7258 7259 } else { 7260 7261 this[ key ] = newValue; 7262 7263 } 7264 7265 } 7266 7267 }, 7268 7269 toJSON: function ( meta ) { 7270 7271 var isRoot = meta === undefined; 7272 7273 if ( isRoot ) { 7274 7275 meta = { 7276 textures: {}, 7277 images: {} 7278 }; 7279 7280 } 7281 7282 var data = { 7283 metadata: { 7284 version: 4.4, 7285 type: 'Material', 7286 generator: 'Material.toJSON' 7287 } 7288 }; 7289 7290 // standard Material serialization 7291 data.uuid = this.uuid; 7292 data.type = this.type; 7293 7294 if ( this.name !== '' ) data.name = this.name; 7295 7296 if ( this.color && this.color.isColor ) data.color = this.color.getHex(); 7297 7298 if ( this.roughness !== undefined ) data.roughness = this.roughness; 7299 if ( this.metalness !== undefined ) data.metalness = this.metalness; 7300 7301 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); 7302 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); 7303 if ( this.shininess !== undefined ) data.shininess = this.shininess; 7304 if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat; 7305 if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness; 7306 7307 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; 7308 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; 7309 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid; 7310 if ( this.bumpMap && this.bumpMap.isTexture ) { 7311 7312 data.bumpMap = this.bumpMap.toJSON( meta ).uuid; 7313 data.bumpScale = this.bumpScale; 7314 7315 } 7316 if ( this.normalMap && this.normalMap.isTexture ) { 7317 7318 data.normalMap = this.normalMap.toJSON( meta ).uuid; 7319 data.normalScale = this.normalScale.toArray(); 7320 7321 } 7322 if ( this.displacementMap && this.displacementMap.isTexture ) { 7323 7324 data.displacementMap = this.displacementMap.toJSON( meta ).uuid; 7325 data.displacementScale = this.displacementScale; 7326 data.displacementBias = this.displacementBias; 7327 7328 } 7329 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; 7330 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; 7331 7332 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; 7333 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; 7334 7335 if ( this.envMap && this.envMap.isTexture ) { 7336 7337 data.envMap = this.envMap.toJSON( meta ).uuid; 7338 data.reflectivity = this.reflectivity; // Scale behind envMap 7339 7340 } 7341 7342 if ( this.gradientMap && this.gradientMap.isTexture ) { 7343 7344 data.gradientMap = this.gradientMap.toJSON( meta ).uuid; 7345 7346 } 7347 7348 if ( this.size !== undefined ) data.size = this.size; 7349 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; 7350 7351 if ( this.blending !== NormalBlending ) data.blending = this.blending; 7352 if ( this.shading !== SmoothShading ) data.shading = this.shading; 7353 if ( this.side !== FrontSide ) data.side = this.side; 7354 if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors; 7355 7356 if ( this.opacity < 1 ) data.opacity = this.opacity; 7357 if ( this.transparent === true ) data.transparent = this.transparent; 7358 7359 data.depthFunc = this.depthFunc; 7360 data.depthTest = this.depthTest; 7361 data.depthWrite = this.depthWrite; 7362 7363 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; 7364 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; 7365 if ( this.wireframe === true ) data.wireframe = this.wireframe; 7366 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; 7367 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; 7368 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; 7369 7370 data.skinning = this.skinning; 7371 data.morphTargets = this.morphTargets; 7372 7373 // TODO: Copied from Object3D.toJSON 7374 7375 function extractFromCache( cache ) { 7376 7377 var values = []; 7378 7379 for ( var key in cache ) { 7380 7381 var data = cache[ key ]; 7382 delete data.metadata; 7383 values.push( data ); 7384 7385 } 7386 7387 return values; 7388 7389 } 7390 7391 if ( isRoot ) { 7392 7393 var textures = extractFromCache( meta.textures ); 7394 var images = extractFromCache( meta.images ); 7395 7396 if ( textures.length > 0 ) data.textures = textures; 7397 if ( images.length > 0 ) data.images = images; 7398 7399 } 7400 7401 return data; 7402 7403 }, 7404 7405 clone: function () { 7406 7407 return new this.constructor().copy( this ); 7408 7409 }, 7410 7411 copy: function ( source ) { 7412 7413 this.name = source.name; 7414 7415 this.fog = source.fog; 7416 this.lights = source.lights; 7417 7418 this.blending = source.blending; 7419 this.side = source.side; 7420 this.shading = source.shading; 7421 this.vertexColors = source.vertexColors; 7422 7423 this.opacity = source.opacity; 7424 this.transparent = source.transparent; 7425 7426 this.blendSrc = source.blendSrc; 7427 this.blendDst = source.blendDst; 7428 this.blendEquation = source.blendEquation; 7429 this.blendSrcAlpha = source.blendSrcAlpha; 7430 this.blendDstAlpha = source.blendDstAlpha; 7431 this.blendEquationAlpha = source.blendEquationAlpha; 7432 7433 this.depthFunc = source.depthFunc; 7434 this.depthTest = source.depthTest; 7435 this.depthWrite = source.depthWrite; 7436 7437 this.colorWrite = source.colorWrite; 7438 7439 this.precision = source.precision; 7440 7441 this.polygonOffset = source.polygonOffset; 7442 this.polygonOffsetFactor = source.polygonOffsetFactor; 7443 this.polygonOffsetUnits = source.polygonOffsetUnits; 7444 7445 this.alphaTest = source.alphaTest; 7446 7447 this.premultipliedAlpha = source.premultipliedAlpha; 7448 7449 this.overdraw = source.overdraw; 7450 7451 this.visible = source.visible; 7452 this.clipShadows = source.clipShadows; 7453 this.clipIntersection = source.clipIntersection; 7454 7455 var srcPlanes = source.clippingPlanes, 7456 dstPlanes = null; 7457 7458 if ( srcPlanes !== null ) { 7459 7460 var n = srcPlanes.length; 7461 dstPlanes = new Array( n ); 7462 7463 for ( var i = 0; i !== n; ++ i ) 7464 dstPlanes[ i ] = srcPlanes[ i ].clone(); 7465 7466 } 7467 7468 this.clippingPlanes = dstPlanes; 7469 7470 return this; 7471 7472 }, 7473 7474 update: function () { 7475 7476 this.dispatchEvent( { type: 'update' } ); 7477 7478 }, 7479 7480 dispose: function () { 7481 7482 this.dispatchEvent( { type: 'dispose' } ); 7483 7484 } 7485 7486 }; 7487 7488 Object.assign( Material.prototype, EventDispatcher.prototype ); 7489 7490 /** 7491 * @author alteredq / http://alteredqualia.com/ 7492 * 7493 * parameters = { 7494 * defines: { "label" : "value" }, 7495 * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, 7496 * 7497 * fragmentShader: <string>, 7498 * vertexShader: <string>, 7499 * 7500 * wireframe: <boolean>, 7501 * wireframeLinewidth: <float>, 7502 * 7503 * lights: <bool>, 7504 * 7505 * skinning: <bool>, 7506 * morphTargets: <bool>, 7507 * morphNormals: <bool> 7508 * } 7509 */ 7510 7511 function ShaderMaterial( parameters ) { 7512 7513 Material.call( this ); 7514 7515 this.type = 'ShaderMaterial'; 7516 7517 this.defines = {}; 7518 this.uniforms = {}; 7519 7520 this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; 7521 this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; 7522 7523 this.linewidth = 1; 7524 7525 this.wireframe = false; 7526 this.wireframeLinewidth = 1; 7527 7528 this.fog = false; // set to use scene fog 7529 this.lights = false; // set to use scene lights 7530 this.clipping = false; // set to use user-defined clipping planes 7531 7532 this.skinning = false; // set to use skinning attribute streams 7533 this.morphTargets = false; // set to use morph targets 7534 this.morphNormals = false; // set to use morph normals 7535 7536 this.extensions = { 7537 derivatives: false, // set to use derivatives 7538 fragDepth: false, // set to use fragment depth values 7539 drawBuffers: false, // set to use draw buffers 7540 shaderTextureLOD: false // set to use shader texture LOD 7541 }; 7542 7543 // When rendered geometry doesn't include these attributes but the material does, 7544 // use these default values in WebGL. This avoids errors when buffer data is missing. 7545 this.defaultAttributeValues = { 7546 'color': [ 1, 1, 1 ], 7547 'uv': [ 0, 0 ], 7548 'uv2': [ 0, 0 ] 7549 }; 7550 7551 this.index0AttributeName = undefined; 7552 7553 if ( parameters !== undefined ) { 7554 7555 if ( parameters.attributes !== undefined ) { 7556 7557 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); 7558 7559 } 7560 7561 this.setValues( parameters ); 7562 7563 } 7564 7565 } 7566 7567 ShaderMaterial.prototype = Object.create( Material.prototype ); 7568 ShaderMaterial.prototype.constructor = ShaderMaterial; 7569 7570 ShaderMaterial.prototype.isShaderMaterial = true; 7571 7572 ShaderMaterial.prototype.copy = function ( source ) { 7573 7574 Material.prototype.copy.call( this, source ); 7575 7576 this.fragmentShader = source.fragmentShader; 7577 this.vertexShader = source.vertexShader; 7578 7579 this.uniforms = UniformsUtils.clone( source.uniforms ); 7580 7581 this.defines = source.defines; 7582 7583 this.wireframe = source.wireframe; 7584 this.wireframeLinewidth = source.wireframeLinewidth; 7585 7586 this.lights = source.lights; 7587 this.clipping = source.clipping; 7588 7589 this.skinning = source.skinning; 7590 7591 this.morphTargets = source.morphTargets; 7592 this.morphNormals = source.morphNormals; 7593 7594 this.extensions = source.extensions; 7595 7596 return this; 7597 7598 }; 7599 7600 ShaderMaterial.prototype.toJSON = function ( meta ) { 7601 7602 var data = Material.prototype.toJSON.call( this, meta ); 7603 7604 data.uniforms = this.uniforms; 7605 data.vertexShader = this.vertexShader; 7606 data.fragmentShader = this.fragmentShader; 7607 7608 return data; 7609 7610 }; 7611 7612 /** 7613 * @author mrdoob / http://mrdoob.com/ 7614 * @author alteredq / http://alteredqualia.com/ 7615 * @author bhouston / https://clara.io 7616 * @author WestLangley / http://github.com/WestLangley 7617 * 7618 * parameters = { 7619 * 7620 * opacity: <float>, 7621 * 7622 * map: new THREE.Texture( <Image> ), 7623 * 7624 * alphaMap: new THREE.Texture( <Image> ), 7625 * 7626 * displacementMap: new THREE.Texture( <Image> ), 7627 * displacementScale: <float>, 7628 * displacementBias: <float>, 7629 * 7630 * wireframe: <boolean>, 7631 * wireframeLinewidth: <float> 7632 * } 7633 */ 7634 7635 function MeshDepthMaterial( parameters ) { 7636 7637 Material.call( this ); 7638 7639 this.type = 'MeshDepthMaterial'; 7640 7641 this.depthPacking = BasicDepthPacking; 7642 7643 this.skinning = false; 7644 this.morphTargets = false; 7645 7646 this.map = null; 7647 7648 this.alphaMap = null; 7649 7650 this.displacementMap = null; 7651 this.displacementScale = 1; 7652 this.displacementBias = 0; 7653 7654 this.wireframe = false; 7655 this.wireframeLinewidth = 1; 7656 7657 this.fog = false; 7658 this.lights = false; 7659 7660 this.setValues( parameters ); 7661 7662 } 7663 7664 MeshDepthMaterial.prototype = Object.create( Material.prototype ); 7665 MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; 7666 7667 MeshDepthMaterial.prototype.isMeshDepthMaterial = true; 7668 7669 MeshDepthMaterial.prototype.copy = function ( source ) { 7670 7671 Material.prototype.copy.call( this, source ); 7672 7673 this.depthPacking = source.depthPacking; 7674 7675 this.skinning = source.skinning; 7676 this.morphTargets = source.morphTargets; 7677 7678 this.map = source.map; 7679 7680 this.alphaMap = source.alphaMap; 7681 7682 this.displacementMap = source.displacementMap; 7683 this.displacementScale = source.displacementScale; 7684 this.displacementBias = source.displacementBias; 7685 7686 this.wireframe = source.wireframe; 7687 this.wireframeLinewidth = source.wireframeLinewidth; 7688 7689 return this; 7690 7691 }; 7692 7693 /** 7694 * @author bhouston / http://clara.io 7695 * @author WestLangley / http://github.com/WestLangley 7696 */ 7697 7698 function Box3( min, max ) { 7699 7700 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); 7701 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); 7702 7703 } 7704 7705 Box3.prototype = { 7706 7707 constructor: Box3, 7708 7709 isBox3: true, 7710 7711 set: function ( min, max ) { 7712 7713 this.min.copy( min ); 7714 this.max.copy( max ); 7715 7716 return this; 7717 7718 }, 7719 7720 setFromArray: function ( array ) { 7721 7722 var minX = + Infinity; 7723 var minY = + Infinity; 7724 var minZ = + Infinity; 7725 7726 var maxX = - Infinity; 7727 var maxY = - Infinity; 7728 var maxZ = - Infinity; 7729 7730 for ( var i = 0, l = array.length; i < l; i += 3 ) { 7731 7732 var x = array[ i ]; 7733 var y = array[ i + 1 ]; 7734 var z = array[ i + 2 ]; 7735 7736 if ( x < minX ) minX = x; 7737 if ( y < minY ) minY = y; 7738 if ( z < minZ ) minZ = z; 7739 7740 if ( x > maxX ) maxX = x; 7741 if ( y > maxY ) maxY = y; 7742 if ( z > maxZ ) maxZ = z; 7743 7744 } 7745 7746 this.min.set( minX, minY, minZ ); 7747 this.max.set( maxX, maxY, maxZ ); 7748 7749 return this; 7750 7751 }, 7752 7753 setFromBufferAttribute: function ( attribute ) { 7754 7755 var minX = + Infinity; 7756 var minY = + Infinity; 7757 var minZ = + Infinity; 7758 7759 var maxX = - Infinity; 7760 var maxY = - Infinity; 7761 var maxZ = - Infinity; 7762 7763 for ( var i = 0, l = attribute.count; i < l; i ++ ) { 7764 7765 var x = attribute.getX( i ); 7766 var y = attribute.getY( i ); 7767 var z = attribute.getZ( i ); 7768 7769 if ( x < minX ) minX = x; 7770 if ( y < minY ) minY = y; 7771 if ( z < minZ ) minZ = z; 7772 7773 if ( x > maxX ) maxX = x; 7774 if ( y > maxY ) maxY = y; 7775 if ( z > maxZ ) maxZ = z; 7776 7777 } 7778 7779 this.min.set( minX, minY, minZ ); 7780 this.max.set( maxX, maxY, maxZ ); 7781 7782 return this; 7783 7784 }, 7785 7786 setFromPoints: function ( points ) { 7787 7788 this.makeEmpty(); 7789 7790 for ( var i = 0, il = points.length; i < il; i ++ ) { 7791 7792 this.expandByPoint( points[ i ] ); 7793 7794 } 7795 7796 return this; 7797 7798 }, 7799 7800 setFromCenterAndSize: function () { 7801 7802 var v1 = new Vector3(); 7803 7804 return function setFromCenterAndSize( center, size ) { 7805 7806 var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); 7807 7808 this.min.copy( center ).sub( halfSize ); 7809 this.max.copy( center ).add( halfSize ); 7810 7811 return this; 7812 7813 }; 7814 7815 }(), 7816 7817 setFromObject: function ( object ) { 7818 7819 this.makeEmpty(); 7820 7821 return this.expandByObject( object ); 7822 7823 }, 7824 7825 clone: function () { 7826 7827 return new this.constructor().copy( this ); 7828 7829 }, 7830 7831 copy: function ( box ) { 7832 7833 this.min.copy( box.min ); 7834 this.max.copy( box.max ); 7835 7836 return this; 7837 7838 }, 7839 7840 makeEmpty: function () { 7841 7842 this.min.x = this.min.y = this.min.z = + Infinity; 7843 this.max.x = this.max.y = this.max.z = - Infinity; 7844 7845 return this; 7846 7847 }, 7848 7849 isEmpty: function () { 7850 7851 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 7852 7853 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); 7854 7855 }, 7856 7857 getCenter: function ( optionalTarget ) { 7858 7859 var result = optionalTarget || new Vector3(); 7860 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 7861 7862 }, 7863 7864 getSize: function ( optionalTarget ) { 7865 7866 var result = optionalTarget || new Vector3(); 7867 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min ); 7868 7869 }, 7870 7871 expandByPoint: function ( point ) { 7872 7873 this.min.min( point ); 7874 this.max.max( point ); 7875 7876 return this; 7877 7878 }, 7879 7880 expandByVector: function ( vector ) { 7881 7882 this.min.sub( vector ); 7883 this.max.add( vector ); 7884 7885 return this; 7886 7887 }, 7888 7889 expandByScalar: function ( scalar ) { 7890 7891 this.min.addScalar( - scalar ); 7892 this.max.addScalar( scalar ); 7893 7894 return this; 7895 7896 }, 7897 7898 expandByObject: function () { 7899 7900 // Computes the world-axis-aligned bounding box of an object (including its children), 7901 // accounting for both the object's, and children's, world transforms 7902 7903 var v1 = new Vector3(); 7904 7905 return function expandByObject( object ) { 7906 7907 var scope = this; 7908 7909 object.updateMatrixWorld( true ); 7910 7911 object.traverse( function ( node ) { 7912 7913 var i, l; 7914 7915 var geometry = node.geometry; 7916 7917 if ( geometry !== undefined ) { 7918 7919 if ( geometry.isGeometry ) { 7920 7921 var vertices = geometry.vertices; 7922 7923 for ( i = 0, l = vertices.length; i < l; i ++ ) { 7924 7925 v1.copy( vertices[ i ] ); 7926 v1.applyMatrix4( node.matrixWorld ); 7927 7928 scope.expandByPoint( v1 ); 7929 7930 } 7931 7932 } else if ( geometry.isBufferGeometry ) { 7933 7934 var attribute = geometry.attributes.position; 7935 7936 if ( attribute !== undefined ) { 7937 7938 for ( i = 0, l = attribute.count; i < l; i ++ ) { 7939 7940 v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); 7941 7942 scope.expandByPoint( v1 ); 7943 7944 } 7945 7946 } 7947 7948 } 7949 7950 } 7951 7952 } ); 7953 7954 return this; 7955 7956 }; 7957 7958 }(), 7959 7960 containsPoint: function ( point ) { 7961 7962 return point.x < this.min.x || point.x > this.max.x || 7963 point.y < this.min.y || point.y > this.max.y || 7964 point.z < this.min.z || point.z > this.max.z ? false : true; 7965 7966 }, 7967 7968 containsBox: function ( box ) { 7969 7970 return this.min.x <= box.min.x && box.max.x <= this.max.x && 7971 this.min.y <= box.min.y && box.max.y <= this.max.y && 7972 this.min.z <= box.min.z && box.max.z <= this.max.z; 7973 7974 }, 7975 7976 getParameter: function ( point, optionalTarget ) { 7977 7978 // This can potentially have a divide by zero if the box 7979 // has a size dimension of 0. 7980 7981 var result = optionalTarget || new Vector3(); 7982 7983 return result.set( 7984 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 7985 ( point.y - this.min.y ) / ( this.max.y - this.min.y ), 7986 ( point.z - this.min.z ) / ( this.max.z - this.min.z ) 7987 ); 7988 7989 }, 7990 7991 intersectsBox: function ( box ) { 7992 7993 // using 6 splitting planes to rule out intersections. 7994 return box.max.x < this.min.x || box.min.x > this.max.x || 7995 box.max.y < this.min.y || box.min.y > this.max.y || 7996 box.max.z < this.min.z || box.min.z > this.max.z ? false : true; 7997 7998 }, 7999 8000 intersectsSphere: ( function () { 8001 8002 var closestPoint; 8003 8004 return function intersectsSphere( sphere ) { 8005 8006 if ( closestPoint === undefined ) closestPoint = new Vector3(); 8007 8008 // Find the point on the AABB closest to the sphere center. 8009 this.clampPoint( sphere.center, closestPoint ); 8010 8011 // If that point is inside the sphere, the AABB and sphere intersect. 8012 return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); 8013 8014 }; 8015 8016 } )(), 8017 8018 intersectsPlane: function ( plane ) { 8019 8020 // We compute the minimum and maximum dot product values. If those values 8021 // are on the same side (back or front) of the plane, then there is no intersection. 8022 8023 var min, max; 8024 8025 if ( plane.normal.x > 0 ) { 8026 8027 min = plane.normal.x * this.min.x; 8028 max = plane.normal.x * this.max.x; 8029 8030 } else { 8031 8032 min = plane.normal.x * this.max.x; 8033 max = plane.normal.x * this.min.x; 8034 8035 } 8036 8037 if ( plane.normal.y > 0 ) { 8038 8039 min += plane.normal.y * this.min.y; 8040 max += plane.normal.y * this.max.y; 8041 8042 } else { 8043 8044 min += plane.normal.y * this.max.y; 8045 max += plane.normal.y * this.min.y; 8046 8047 } 8048 8049 if ( plane.normal.z > 0 ) { 8050 8051 min += plane.normal.z * this.min.z; 8052 max += plane.normal.z * this.max.z; 8053 8054 } else { 8055 8056 min += plane.normal.z * this.max.z; 8057 max += plane.normal.z * this.min.z; 8058 8059 } 8060 8061 return ( min <= plane.constant && max >= plane.constant ); 8062 8063 }, 8064 8065 clampPoint: function ( point, optionalTarget ) { 8066 8067 var result = optionalTarget || new Vector3(); 8068 return result.copy( point ).clamp( this.min, this.max ); 8069 8070 }, 8071 8072 distanceToPoint: function () { 8073 8074 var v1 = new Vector3(); 8075 8076 return function distanceToPoint( point ) { 8077 8078 var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); 8079 return clampedPoint.sub( point ).length(); 8080 8081 }; 8082 8083 }(), 8084 8085 getBoundingSphere: function () { 8086 8087 var v1 = new Vector3(); 8088 8089 return function getBoundingSphere( optionalTarget ) { 8090 8091 var result = optionalTarget || new Sphere(); 8092 8093 this.getCenter( result.center ); 8094 8095 result.radius = this.getSize( v1 ).length() * 0.5; 8096 8097 return result; 8098 8099 }; 8100 8101 }(), 8102 8103 intersect: function ( box ) { 8104 8105 this.min.max( box.min ); 8106 this.max.min( box.max ); 8107 8108 // 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. 8109 if( this.isEmpty() ) this.makeEmpty(); 8110 8111 return this; 8112 8113 }, 8114 8115 union: function ( box ) { 8116 8117 this.min.min( box.min ); 8118 this.max.max( box.max ); 8119 8120 return this; 8121 8122 }, 8123 8124 applyMatrix4: function () { 8125 8126 var points = [ 8127 new Vector3(), 8128 new Vector3(), 8129 new Vector3(), 8130 new Vector3(), 8131 new Vector3(), 8132 new Vector3(), 8133 new Vector3(), 8134 new Vector3() 8135 ]; 8136 8137 return function applyMatrix4( matrix ) { 8138 8139 // transform of empty box is an empty box. 8140 if( this.isEmpty() ) return this; 8141 8142 // NOTE: I am using a binary pattern to specify all 2^3 combinations below 8143 points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 8144 points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 8145 points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 8146 points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 8147 points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 8148 points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 8149 points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 8150 points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 8151 8152 this.setFromPoints( points ); 8153 8154 return this; 8155 8156 }; 8157 8158 }(), 8159 8160 translate: function ( offset ) { 8161 8162 this.min.add( offset ); 8163 this.max.add( offset ); 8164 8165 return this; 8166 8167 }, 8168 8169 equals: function ( box ) { 8170 8171 return box.min.equals( this.min ) && box.max.equals( this.max ); 8172 8173 } 8174 8175 }; 8176 8177 /** 8178 * @author bhouston / http://clara.io 8179 * @author mrdoob / http://mrdoob.com/ 8180 */ 8181 8182 function Sphere( center, radius ) { 8183 8184 this.center = ( center !== undefined ) ? center : new Vector3(); 8185 this.radius = ( radius !== undefined ) ? radius : 0; 8186 8187 } 8188 8189 Sphere.prototype = { 8190 8191 constructor: Sphere, 8192 8193 set: function ( center, radius ) { 8194 8195 this.center.copy( center ); 8196 this.radius = radius; 8197 8198 return this; 8199 8200 }, 8201 8202 setFromPoints: function () { 8203 8204 var box; 8205 8206 return function setFromPoints( points, optionalCenter ) { 8207 8208 if ( box === undefined ) box = new Box3(); // see #10547 8209 8210 var center = this.center; 8211 8212 if ( optionalCenter !== undefined ) { 8213 8214 center.copy( optionalCenter ); 8215 8216 } else { 8217 8218 box.setFromPoints( points ).getCenter( center ); 8219 8220 } 8221 8222 var maxRadiusSq = 0; 8223 8224 for ( var i = 0, il = points.length; i < il; i ++ ) { 8225 8226 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); 8227 8228 } 8229 8230 this.radius = Math.sqrt( maxRadiusSq ); 8231 8232 return this; 8233 8234 }; 8235 8236 }(), 8237 8238 clone: function () { 8239 8240 return new this.constructor().copy( this ); 8241 8242 }, 8243 8244 copy: function ( sphere ) { 8245 8246 this.center.copy( sphere.center ); 8247 this.radius = sphere.radius; 8248 8249 return this; 8250 8251 }, 8252 8253 empty: function () { 8254 8255 return ( this.radius <= 0 ); 8256 8257 }, 8258 8259 containsPoint: function ( point ) { 8260 8261 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); 8262 8263 }, 8264 8265 distanceToPoint: function ( point ) { 8266 8267 return ( point.distanceTo( this.center ) - this.radius ); 8268 8269 }, 8270 8271 intersectsSphere: function ( sphere ) { 8272 8273 var radiusSum = this.radius + sphere.radius; 8274 8275 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); 8276 8277 }, 8278 8279 intersectsBox: function ( box ) { 8280 8281 return box.intersectsSphere( this ); 8282 8283 }, 8284 8285 intersectsPlane: function ( plane ) { 8286 8287 // We use the following equation to compute the signed distance from 8288 // the center of the sphere to the plane. 8289 // 8290 // distance = q * n - d 8291 // 8292 // If this distance is greater than the radius of the sphere, 8293 // then there is no intersection. 8294 8295 return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius; 8296 8297 }, 8298 8299 clampPoint: function ( point, optionalTarget ) { 8300 8301 var deltaLengthSq = this.center.distanceToSquared( point ); 8302 8303 var result = optionalTarget || new Vector3(); 8304 8305 result.copy( point ); 8306 8307 if ( deltaLengthSq > ( this.radius * this.radius ) ) { 8308 8309 result.sub( this.center ).normalize(); 8310 result.multiplyScalar( this.radius ).add( this.center ); 8311 8312 } 8313 8314 return result; 8315 8316 }, 8317 8318 getBoundingBox: function ( optionalTarget ) { 8319 8320 var box = optionalTarget || new Box3(); 8321 8322 box.set( this.center, this.center ); 8323 box.expandByScalar( this.radius ); 8324 8325 return box; 8326 8327 }, 8328 8329 applyMatrix4: function ( matrix ) { 8330 8331 this.center.applyMatrix4( matrix ); 8332 this.radius = this.radius * matrix.getMaxScaleOnAxis(); 8333 8334 return this; 8335 8336 }, 8337 8338 translate: function ( offset ) { 8339 8340 this.center.add( offset ); 8341 8342 return this; 8343 8344 }, 8345 8346 equals: function ( sphere ) { 8347 8348 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); 8349 8350 } 8351 8352 }; 8353 8354 /** 8355 * @author alteredq / http://alteredqualia.com/ 8356 * @author WestLangley / http://github.com/WestLangley 8357 * @author bhouston / http://clara.io 8358 * @author tschw 8359 */ 8360 8361 function Matrix3() { 8362 8363 this.elements = new Float32Array( [ 8364 8365 1, 0, 0, 8366 0, 1, 0, 8367 0, 0, 1 8368 8369 ] ); 8370 8371 if ( arguments.length > 0 ) { 8372 8373 console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); 8374 8375 } 8376 8377 } 8378 8379 Matrix3.prototype = { 8380 8381 constructor: Matrix3, 8382 8383 isMatrix3: true, 8384 8385 set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 8386 8387 var te = this.elements; 8388 8389 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; 8390 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; 8391 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; 8392 8393 return this; 8394 8395 }, 8396 8397 identity: function () { 8398 8399 this.set( 8400 8401 1, 0, 0, 8402 0, 1, 0, 8403 0, 0, 1 8404 8405 ); 8406 8407 return this; 8408 8409 }, 8410 8411 clone: function () { 8412 8413 return new this.constructor().fromArray( this.elements ); 8414 8415 }, 8416 8417 copy: function ( m ) { 8418 8419 var me = m.elements; 8420 8421 this.set( 8422 8423 me[ 0 ], me[ 3 ], me[ 6 ], 8424 me[ 1 ], me[ 4 ], me[ 7 ], 8425 me[ 2 ], me[ 5 ], me[ 8 ] 8426 8427 ); 8428 8429 return this; 8430 8431 }, 8432 8433 setFromMatrix4: function( m ) { 8434 8435 var me = m.elements; 8436 8437 this.set( 8438 8439 me[ 0 ], me[ 4 ], me[ 8 ], 8440 me[ 1 ], me[ 5 ], me[ 9 ], 8441 me[ 2 ], me[ 6 ], me[ 10 ] 8442 8443 ); 8444 8445 return this; 8446 8447 }, 8448 8449 applyToBufferAttribute: function () { 8450 8451 var v1; 8452 8453 return function applyToBufferAttribute( attribute ) { 8454 8455 if ( v1 === undefined ) v1 = new Vector3(); 8456 8457 for ( var i = 0, l = attribute.count; i < l; i ++ ) { 8458 8459 v1.x = attribute.getX( i ); 8460 v1.y = attribute.getY( i ); 8461 v1.z = attribute.getZ( i ); 8462 8463 v1.applyMatrix3( this ); 8464 8465 attribute.setXYZ( i, v1.x, v1.y, v1.z ); 8466 8467 } 8468 8469 return attribute; 8470 8471 }; 8472 8473 }(), 8474 8475 multiplyScalar: function ( s ) { 8476 8477 var te = this.elements; 8478 8479 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; 8480 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; 8481 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; 8482 8483 return this; 8484 8485 }, 8486 8487 determinant: function () { 8488 8489 var te = this.elements; 8490 8491 var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], 8492 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], 8493 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; 8494 8495 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; 8496 8497 }, 8498 8499 getInverse: function ( matrix, throwOnDegenerate ) { 8500 8501 if ( matrix && matrix.isMatrix4 ) { 8502 8503 console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." ); 8504 8505 } 8506 8507 var me = matrix.elements, 8508 te = this.elements, 8509 8510 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], 8511 n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ], 8512 n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ], 8513 8514 t11 = n33 * n22 - n32 * n23, 8515 t12 = n32 * n13 - n33 * n12, 8516 t13 = n23 * n12 - n22 * n13, 8517 8518 det = n11 * t11 + n21 * t12 + n31 * t13; 8519 8520 if ( det === 0 ) { 8521 8522 var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0"; 8523 8524 if ( throwOnDegenerate === true ) { 8525 8526 throw new Error( msg ); 8527 8528 } else { 8529 8530 console.warn( msg ); 8531 8532 } 8533 8534 return this.identity(); 8535 } 8536 8537 var detInv = 1 / det; 8538 8539 te[ 0 ] = t11 * detInv; 8540 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; 8541 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; 8542 8543 te[ 3 ] = t12 * detInv; 8544 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; 8545 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; 8546 8547 te[ 6 ] = t13 * detInv; 8548 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; 8549 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; 8550 8551 return this; 8552 8553 }, 8554 8555 transpose: function () { 8556 8557 var tmp, m = this.elements; 8558 8559 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; 8560 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; 8561 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; 8562 8563 return this; 8564 8565 }, 8566 8567 getNormalMatrix: function ( matrix4 ) { 8568 8569 return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose(); 8570 8571 }, 8572 8573 transposeIntoArray: function ( r ) { 8574 8575 var m = this.elements; 8576 8577 r[ 0 ] = m[ 0 ]; 8578 r[ 1 ] = m[ 3 ]; 8579 r[ 2 ] = m[ 6 ]; 8580 r[ 3 ] = m[ 1 ]; 8581 r[ 4 ] = m[ 4 ]; 8582 r[ 5 ] = m[ 7 ]; 8583 r[ 6 ] = m[ 2 ]; 8584 r[ 7 ] = m[ 5 ]; 8585 r[ 8 ] = m[ 8 ]; 8586 8587 return this; 8588 8589 }, 8590 8591 fromArray: function ( array, offset ) { 8592 8593 if ( offset === undefined ) offset = 0; 8594 8595 for( var i = 0; i < 9; i ++ ) { 8596 8597 this.elements[ i ] = array[ i + offset ]; 8598 8599 } 8600 8601 return this; 8602 8603 }, 8604 8605 toArray: function ( array, offset ) { 8606 8607 if ( array === undefined ) array = []; 8608 if ( offset === undefined ) offset = 0; 8609 8610 var te = this.elements; 8611 8612 array[ offset ] = te[ 0 ]; 8613 array[ offset + 1 ] = te[ 1 ]; 8614 array[ offset + 2 ] = te[ 2 ]; 8615 8616 array[ offset + 3 ] = te[ 3 ]; 8617 array[ offset + 4 ] = te[ 4 ]; 8618 array[ offset + 5 ] = te[ 5 ]; 8619 8620 array[ offset + 6 ] = te[ 6 ]; 8621 array[ offset + 7 ] = te[ 7 ]; 8622 array[ offset + 8 ] = te[ 8 ]; 8623 8624 return array; 8625 8626 } 8627 8628 }; 8629 8630 /** 8631 * @author bhouston / http://clara.io 8632 */ 8633 8634 function Plane( normal, constant ) { 8635 8636 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); 8637 this.constant = ( constant !== undefined ) ? constant : 0; 8638 8639 } 8640 8641 Plane.prototype = { 8642 8643 constructor: Plane, 8644 8645 set: function ( normal, constant ) { 8646 8647 this.normal.copy( normal ); 8648 this.constant = constant; 8649 8650 return this; 8651 8652 }, 8653 8654 setComponents: function ( x, y, z, w ) { 8655 8656 this.normal.set( x, y, z ); 8657 this.constant = w; 8658 8659 return this; 8660 8661 }, 8662 8663 setFromNormalAndCoplanarPoint: function ( normal, point ) { 8664 8665 this.normal.copy( normal ); 8666 this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized 8667 8668 return this; 8669 8670 }, 8671 8672 setFromCoplanarPoints: function () { 8673 8674 var v1 = new Vector3(); 8675 var v2 = new Vector3(); 8676 8677 return function setFromCoplanarPoints( a, b, c ) { 8678 8679 var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); 8680 8681 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? 8682 8683 this.setFromNormalAndCoplanarPoint( normal, a ); 8684 8685 return this; 8686 8687 }; 8688 8689 }(), 8690 8691 clone: function () { 8692 8693 return new this.constructor().copy( this ); 8694 8695 }, 8696 8697 copy: function ( plane ) { 8698 8699 this.normal.copy( plane.normal ); 8700 this.constant = plane.constant; 8701 8702 return this; 8703 8704 }, 8705 8706 normalize: function () { 8707 8708 // Note: will lead to a divide by zero if the plane is invalid. 8709 8710 var inverseNormalLength = 1.0 / this.normal.length(); 8711 this.normal.multiplyScalar( inverseNormalLength ); 8712 this.constant *= inverseNormalLength; 8713 8714 return this; 8715 8716 }, 8717 8718 negate: function () { 8719 8720 this.constant *= - 1; 8721 this.normal.negate(); 8722 8723 return this; 8724 8725 }, 8726 8727 distanceToPoint: function ( point ) { 8728 8729 return this.normal.dot( point ) + this.constant; 8730 8731 }, 8732 8733 distanceToSphere: function ( sphere ) { 8734 8735 return this.distanceToPoint( sphere.center ) - sphere.radius; 8736 8737 }, 8738 8739 projectPoint: function ( point, optionalTarget ) { 8740 8741 return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); 8742 8743 }, 8744 8745 orthoPoint: function ( point, optionalTarget ) { 8746 8747 var perpendicularMagnitude = this.distanceToPoint( point ); 8748 8749 var result = optionalTarget || new Vector3(); 8750 return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); 8751 8752 }, 8753 8754 intersectLine: function () { 8755 8756 var v1 = new Vector3(); 8757 8758 return function intersectLine( line, optionalTarget ) { 8759 8760 var result = optionalTarget || new Vector3(); 8761 8762 var direction = line.delta( v1 ); 8763 8764 var denominator = this.normal.dot( direction ); 8765 8766 if ( denominator === 0 ) { 8767 8768 // line is coplanar, return origin 8769 if ( this.distanceToPoint( line.start ) === 0 ) { 8770 8771 return result.copy( line.start ); 8772 8773 } 8774 8775 // Unsure if this is the correct method to handle this case. 8776 return undefined; 8777 8778 } 8779 8780 var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; 8781 8782 if ( t < 0 || t > 1 ) { 8783 8784 return undefined; 8785 8786 } 8787 8788 return result.copy( direction ).multiplyScalar( t ).add( line.start ); 8789 8790 }; 8791 8792 }(), 8793 8794 intersectsLine: function ( line ) { 8795 8796 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. 8797 8798 var startSign = this.distanceToPoint( line.start ); 8799 var endSign = this.distanceToPoint( line.end ); 8800 8801 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); 8802 8803 }, 8804 8805 intersectsBox: function ( box ) { 8806 8807 return box.intersectsPlane( this ); 8808 8809 }, 8810 8811 intersectsSphere: function ( sphere ) { 8812 8813 return sphere.intersectsPlane( this ); 8814 8815 }, 8816 8817 coplanarPoint: function ( optionalTarget ) { 8818 8819 var result = optionalTarget || new Vector3(); 8820 return result.copy( this.normal ).multiplyScalar( - this.constant ); 8821 8822 }, 8823 8824 applyMatrix4: function () { 8825 8826 var v1 = new Vector3(); 8827 var m1 = new Matrix3(); 8828 8829 return function applyMatrix4( matrix, optionalNormalMatrix ) { 8830 8831 var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); 8832 8833 // transform normal based on theory here: 8834 // http://www.songho.ca/opengl/gl_normaltransform.html 8835 var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); 8836 var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); 8837 8838 // recalculate constant (like in setFromNormalAndCoplanarPoint) 8839 this.constant = - referencePoint.dot( normal ); 8840 8841 return this; 8842 8843 }; 8844 8845 }(), 8846 8847 translate: function ( offset ) { 8848 8849 this.constant = this.constant - offset.dot( this.normal ); 8850 8851 return this; 8852 8853 }, 8854 8855 equals: function ( plane ) { 8856 8857 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); 8858 8859 } 8860 8861 }; 8862 8863 /** 8864 * @author mrdoob / http://mrdoob.com/ 8865 * @author alteredq / http://alteredqualia.com/ 8866 * @author bhouston / http://clara.io 8867 */ 8868 8869 function Frustum( p0, p1, p2, p3, p4, p5 ) { 8870 8871 this.planes = [ 8872 8873 ( p0 !== undefined ) ? p0 : new Plane(), 8874 ( p1 !== undefined ) ? p1 : new Plane(), 8875 ( p2 !== undefined ) ? p2 : new Plane(), 8876 ( p3 !== undefined ) ? p3 : new Plane(), 8877 ( p4 !== undefined ) ? p4 : new Plane(), 8878 ( p5 !== undefined ) ? p5 : new Plane() 8879 8880 ]; 8881 8882 } 8883 8884 Frustum.prototype = { 8885 8886 constructor: Frustum, 8887 8888 set: function ( p0, p1, p2, p3, p4, p5 ) { 8889 8890 var planes = this.planes; 8891 8892 planes[ 0 ].copy( p0 ); 8893 planes[ 1 ].copy( p1 ); 8894 planes[ 2 ].copy( p2 ); 8895 planes[ 3 ].copy( p3 ); 8896 planes[ 4 ].copy( p4 ); 8897 planes[ 5 ].copy( p5 ); 8898 8899 return this; 8900 8901 }, 8902 8903 clone: function () { 8904 8905 return new this.constructor().copy( this ); 8906 8907 }, 8908 8909 copy: function ( frustum ) { 8910 8911 var planes = this.planes; 8912 8913 for ( var i = 0; i < 6; i ++ ) { 8914 8915 planes[ i ].copy( frustum.planes[ i ] ); 8916 8917 } 8918 8919 return this; 8920 8921 }, 8922 8923 setFromMatrix: function ( m ) { 8924 8925 var planes = this.planes; 8926 var me = m.elements; 8927 var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; 8928 var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; 8929 var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; 8930 var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; 8931 8932 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); 8933 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); 8934 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); 8935 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); 8936 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); 8937 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); 8938 8939 return this; 8940 8941 }, 8942 8943 intersectsObject: function () { 8944 8945 var sphere = new Sphere(); 8946 8947 return function intersectsObject( object ) { 8948 8949 var geometry = object.geometry; 8950 8951 if ( geometry.boundingSphere === null ) 8952 geometry.computeBoundingSphere(); 8953 8954 sphere.copy( geometry.boundingSphere ) 8955 .applyMatrix4( object.matrixWorld ); 8956 8957 return this.intersectsSphere( sphere ); 8958 8959 }; 8960 8961 }(), 8962 8963 intersectsSprite: function () { 8964 8965 var sphere = new Sphere(); 8966 8967 return function intersectsSprite( sprite ) { 8968 8969 sphere.center.set( 0, 0, 0 ); 8970 sphere.radius = 0.7071067811865476; 8971 sphere.applyMatrix4( sprite.matrixWorld ); 8972 8973 return this.intersectsSphere( sphere ); 8974 8975 }; 8976 8977 }(), 8978 8979 intersectsSphere: function ( sphere ) { 8980 8981 var planes = this.planes; 8982 var center = sphere.center; 8983 var negRadius = - sphere.radius; 8984 8985 for ( var i = 0; i < 6; i ++ ) { 8986 8987 var distance = planes[ i ].distanceToPoint( center ); 8988 8989 if ( distance < negRadius ) { 8990 8991 return false; 8992 8993 } 8994 8995 } 8996 8997 return true; 8998 8999 }, 9000 9001 intersectsBox: function () { 9002 9003 var p1 = new Vector3(), 9004 p2 = new Vector3(); 9005 9006 return function intersectsBox( box ) { 9007 9008 var planes = this.planes; 9009 9010 for ( var i = 0; i < 6 ; i ++ ) { 9011 9012 var plane = planes[ i ]; 9013 9014 p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; 9015 p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; 9016 p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; 9017 p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; 9018 p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; 9019 p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; 9020 9021 var d1 = plane.distanceToPoint( p1 ); 9022 var d2 = plane.distanceToPoint( p2 ); 9023 9024 // if both outside plane, no intersection 9025 9026 if ( d1 < 0 && d2 < 0 ) { 9027 9028 return false; 9029 9030 } 9031 9032 } 9033 9034 return true; 9035 9036 }; 9037 9038 }(), 9039 9040 9041 containsPoint: function ( point ) { 9042 9043 var planes = this.planes; 9044 9045 for ( var i = 0; i < 6; i ++ ) { 9046 9047 if ( planes[ i ].distanceToPoint( point ) < 0 ) { 9048 9049 return false; 9050 9051 } 9052 9053 } 9054 9055 return true; 9056 9057 } 9058 9059 }; 9060 9061 /** 9062 * @author alteredq / http://alteredqualia.com/ 9063 * @author mrdoob / http://mrdoob.com/ 9064 */ 9065 9066 function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) { 9067 9068 var _gl = _renderer.context, 9069 _state = _renderer.state, 9070 _frustum = new Frustum(), 9071 _projScreenMatrix = new Matrix4(), 9072 9073 _lightShadows = _lights.shadows, 9074 9075 _shadowMapSize = new Vector2(), 9076 _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ), 9077 9078 _lookTarget = new Vector3(), 9079 _lightPositionWorld = new Vector3(), 9080 9081 _renderList = [], 9082 9083 _MorphingFlag = 1, 9084 _SkinningFlag = 2, 9085 9086 _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, 9087 9088 _depthMaterials = new Array( _NumberOfMaterialVariants ), 9089 _distanceMaterials = new Array( _NumberOfMaterialVariants ), 9090 9091 _materialCache = {}; 9092 9093 var cubeDirections = [ 9094 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), 9095 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) 9096 ]; 9097 9098 var cubeUps = [ 9099 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), 9100 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) 9101 ]; 9102 9103 var cube2DViewPorts = [ 9104 new Vector4(), new Vector4(), new Vector4(), 9105 new Vector4(), new Vector4(), new Vector4() 9106 ]; 9107 9108 // init 9109 9110 var depthMaterialTemplate = new MeshDepthMaterial(); 9111 depthMaterialTemplate.depthPacking = RGBADepthPacking; 9112 depthMaterialTemplate.clipping = true; 9113 9114 var distanceShader = ShaderLib[ "distanceRGBA" ]; 9115 var distanceUniforms = UniformsUtils.clone( distanceShader.uniforms ); 9116 9117 for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { 9118 9119 var useMorphing = ( i & _MorphingFlag ) !== 0; 9120 var useSkinning = ( i & _SkinningFlag ) !== 0; 9121 9122 var depthMaterial = depthMaterialTemplate.clone(); 9123 depthMaterial.morphTargets = useMorphing; 9124 depthMaterial.skinning = useSkinning; 9125 9126 _depthMaterials[ i ] = depthMaterial; 9127 9128 var distanceMaterial = new ShaderMaterial( { 9129 defines: { 9130 'USE_SHADOWMAP': '' 9131 }, 9132 uniforms: distanceUniforms, 9133 vertexShader: distanceShader.vertexShader, 9134 fragmentShader: distanceShader.fragmentShader, 9135 morphTargets: useMorphing, 9136 skinning: useSkinning, 9137 clipping: true 9138 } ); 9139 9140 _distanceMaterials[ i ] = distanceMaterial; 9141 9142 } 9143 9144 // 9145 9146 var scope = this; 9147 9148 this.enabled = false; 9149 9150 this.autoUpdate = true; 9151 this.needsUpdate = false; 9152 9153 this.type = PCFShadowMap; 9154 9155 this.renderReverseSided = true; 9156 this.renderSingleSided = true; 9157 9158 this.render = function ( scene, camera ) { 9159 9160 if ( scope.enabled === false ) return; 9161 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; 9162 9163 if ( _lightShadows.length === 0 ) return; 9164 9165 // Set GL state for depth map. 9166 _state.buffers.color.setClear( 1, 1, 1, 1 ); 9167 _state.disable( _gl.BLEND ); 9168 _state.setDepthTest( true ); 9169 _state.setScissorTest( false ); 9170 9171 // render depth map 9172 9173 var faceCount, isPointLight; 9174 9175 for ( var i = 0, il = _lightShadows.length; i < il; i ++ ) { 9176 9177 var light = _lightShadows[ i ]; 9178 var shadow = light.shadow; 9179 9180 if ( shadow === undefined ) { 9181 9182 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); 9183 continue; 9184 9185 } 9186 9187 var shadowCamera = shadow.camera; 9188 9189 _shadowMapSize.copy( shadow.mapSize ); 9190 _shadowMapSize.min( _maxShadowMapSize ); 9191 9192 if ( light && light.isPointLight ) { 9193 9194 faceCount = 6; 9195 isPointLight = true; 9196 9197 var vpWidth = _shadowMapSize.x; 9198 var vpHeight = _shadowMapSize.y; 9199 9200 // These viewports map a cube-map onto a 2D texture with the 9201 // following orientation: 9202 // 9203 // xzXZ 9204 // y Y 9205 // 9206 // X - Positive x direction 9207 // x - Negative x direction 9208 // Y - Positive y direction 9209 // y - Negative y direction 9210 // Z - Positive z direction 9211 // z - Negative z direction 9212 9213 // positive X 9214 cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); 9215 // negative X 9216 cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); 9217 // positive Z 9218 cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); 9219 // negative Z 9220 cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); 9221 // positive Y 9222 cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); 9223 // negative Y 9224 cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); 9225 9226 _shadowMapSize.x *= 4.0; 9227 _shadowMapSize.y *= 2.0; 9228 9229 } else { 9230 9231 faceCount = 1; 9232 isPointLight = false; 9233 9234 } 9235 9236 if ( shadow.map === null ) { 9237 9238 var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; 9239 9240 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); 9241 9242 shadowCamera.updateProjectionMatrix(); 9243 9244 } 9245 9246 if ( shadow.isSpotLightShadow ) { 9247 9248 shadow.update( light ); 9249 9250 } 9251 9252 // TODO (abelnation / sam-g-steel): is this needed? 9253 if (shadow && shadow.isRectAreaLightShadow ) { 9254 9255 shadow.update( light ); 9256 9257 } 9258 9259 var shadowMap = shadow.map; 9260 var shadowMatrix = shadow.matrix; 9261 9262 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); 9263 shadowCamera.position.copy( _lightPositionWorld ); 9264 9265 _renderer.setRenderTarget( shadowMap ); 9266 _renderer.clear(); 9267 9268 // render shadow map for each cube face (if omni-directional) or 9269 // run a single pass if not 9270 9271 for ( var face = 0; face < faceCount; face ++ ) { 9272 9273 if ( isPointLight ) { 9274 9275 _lookTarget.copy( shadowCamera.position ); 9276 _lookTarget.add( cubeDirections[ face ] ); 9277 shadowCamera.up.copy( cubeUps[ face ] ); 9278 shadowCamera.lookAt( _lookTarget ); 9279 9280 var vpDimensions = cube2DViewPorts[ face ]; 9281 _state.viewport( vpDimensions ); 9282 9283 } else { 9284 9285 _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); 9286 shadowCamera.lookAt( _lookTarget ); 9287 9288 } 9289 9290 shadowCamera.updateMatrixWorld(); 9291 shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); 9292 9293 // compute shadow matrix 9294 9295 shadowMatrix.set( 9296 0.5, 0.0, 0.0, 0.5, 9297 0.0, 0.5, 0.0, 0.5, 9298 0.0, 0.0, 0.5, 0.5, 9299 0.0, 0.0, 0.0, 1.0 9300 ); 9301 9302 shadowMatrix.multiply( shadowCamera.projectionMatrix ); 9303 shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); 9304 9305 // update camera matrices and frustum 9306 9307 _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); 9308 _frustum.setFromMatrix( _projScreenMatrix ); 9309 9310 // set object matrices & frustum culling 9311 9312 _renderList.length = 0; 9313 9314 projectObject( scene, camera, shadowCamera ); 9315 9316 // render shadow map 9317 // render regular objects 9318 9319 for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { 9320 9321 var object = _renderList[ j ]; 9322 var geometry = _objects.update( object ); 9323 var material = object.material; 9324 9325 if ( material && material.isMultiMaterial ) { 9326 9327 var groups = geometry.groups; 9328 var materials = material.materials; 9329 9330 for ( var k = 0, kl = groups.length; k < kl; k ++ ) { 9331 9332 var group = groups[ k ]; 9333 var groupMaterial = materials[ group.materialIndex ]; 9334 9335 if ( groupMaterial.visible === true ) { 9336 9337 var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); 9338 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); 9339 9340 } 9341 9342 } 9343 9344 } else { 9345 9346 var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); 9347 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); 9348 9349 } 9350 9351 } 9352 9353 } 9354 9355 } 9356 9357 // Restore GL state. 9358 var clearColor = _renderer.getClearColor(), 9359 clearAlpha = _renderer.getClearAlpha(); 9360 _renderer.setClearColor( clearColor, clearAlpha ); 9361 9362 scope.needsUpdate = false; 9363 9364 }; 9365 9366 function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) { 9367 9368 var geometry = object.geometry; 9369 9370 var result = null; 9371 9372 var materialVariants = _depthMaterials; 9373 var customMaterial = object.customDepthMaterial; 9374 9375 if ( isPointLight ) { 9376 9377 materialVariants = _distanceMaterials; 9378 customMaterial = object.customDistanceMaterial; 9379 9380 } 9381 9382 if ( ! customMaterial ) { 9383 9384 var useMorphing = false; 9385 9386 if ( material.morphTargets ) { 9387 9388 if ( geometry && geometry.isBufferGeometry ) { 9389 9390 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; 9391 9392 } else if ( geometry && geometry.isGeometry ) { 9393 9394 useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; 9395 9396 } 9397 9398 } 9399 9400 var useSkinning = object.isSkinnedMesh && material.skinning; 9401 9402 var variantIndex = 0; 9403 9404 if ( useMorphing ) variantIndex |= _MorphingFlag; 9405 if ( useSkinning ) variantIndex |= _SkinningFlag; 9406 9407 result = materialVariants[ variantIndex ]; 9408 9409 } else { 9410 9411 result = customMaterial; 9412 9413 } 9414 9415 if ( _renderer.localClippingEnabled && 9416 material.clipShadows === true && 9417 material.clippingPlanes.length !== 0 ) { 9418 9419 // in this case we need a unique material instance reflecting the 9420 // appropriate state 9421 9422 var keyA = result.uuid, keyB = material.uuid; 9423 9424 var materialsForVariant = _materialCache[ keyA ]; 9425 9426 if ( materialsForVariant === undefined ) { 9427 9428 materialsForVariant = {}; 9429 _materialCache[ keyA ] = materialsForVariant; 9430 9431 } 9432 9433 var cachedMaterial = materialsForVariant[ keyB ]; 9434 9435 if ( cachedMaterial === undefined ) { 9436 9437 cachedMaterial = result.clone(); 9438 materialsForVariant[ keyB ] = cachedMaterial; 9439 9440 } 9441 9442 result = cachedMaterial; 9443 9444 } 9445 9446 result.visible = material.visible; 9447 result.wireframe = material.wireframe; 9448 9449 var side = material.side; 9450 9451 if ( scope.renderSingleSided && side == DoubleSide ) { 9452 9453 side = FrontSide; 9454 9455 } 9456 9457 if ( scope.renderReverseSided ) { 9458 9459 if ( side === FrontSide ) side = BackSide; 9460 else if ( side === BackSide ) side = FrontSide; 9461 9462 } 9463 9464 result.side = side; 9465 9466 result.clipShadows = material.clipShadows; 9467 result.clippingPlanes = material.clippingPlanes; 9468 9469 result.wireframeLinewidth = material.wireframeLinewidth; 9470 result.linewidth = material.linewidth; 9471 9472 if ( isPointLight && result.uniforms.lightPos !== undefined ) { 9473 9474 result.uniforms.lightPos.value.copy( lightPositionWorld ); 9475 9476 } 9477 9478 return result; 9479 9480 } 9481 9482 function projectObject( object, camera, shadowCamera ) { 9483 9484 if ( object.visible === false ) return; 9485 9486 var visible = ( object.layers.mask & camera.layers.mask ) !== 0; 9487 9488 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { 9489 9490 if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { 9491 9492 var material = object.material; 9493 9494 if ( material.visible === true ) { 9495 9496 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); 9497 _renderList.push( object ); 9498 9499 } 9500 9501 } 9502 9503 } 9504 9505 var children = object.children; 9506 9507 for ( var i = 0, l = children.length; i < l; i ++ ) { 9508 9509 projectObject( children[ i ], camera, shadowCamera ); 9510 9511 } 9512 9513 } 9514 9515 } 9516 9517 /** 9518 * @author bhouston / http://clara.io 9519 */ 9520 9521 function Ray( origin, direction ) { 9522 9523 this.origin = ( origin !== undefined ) ? origin : new Vector3(); 9524 this.direction = ( direction !== undefined ) ? direction : new Vector3(); 9525 9526 } 9527 9528 Ray.prototype = { 9529 9530 constructor: Ray, 9531 9532 set: function ( origin, direction ) { 9533 9534 this.origin.copy( origin ); 9535 this.direction.copy( direction ); 9536 9537 return this; 9538 9539 }, 9540 9541 clone: function () { 9542 9543 return new this.constructor().copy( this ); 9544 9545 }, 9546 9547 copy: function ( ray ) { 9548 9549 this.origin.copy( ray.origin ); 9550 this.direction.copy( ray.direction ); 9551 9552 return this; 9553 9554 }, 9555 9556 at: function ( t, optionalTarget ) { 9557 9558 var result = optionalTarget || new Vector3(); 9559 9560 return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); 9561 9562 }, 9563 9564 lookAt: function ( v ) { 9565 9566 this.direction.copy( v ).sub( this.origin ).normalize(); 9567 9568 return this; 9569 9570 }, 9571 9572 recast: function () { 9573 9574 var v1 = new Vector3(); 9575 9576 return function recast( t ) { 9577 9578 this.origin.copy( this.at( t, v1 ) ); 9579 9580 return this; 9581 9582 }; 9583 9584 }(), 9585 9586 closestPointToPoint: function ( point, optionalTarget ) { 9587 9588 var result = optionalTarget || new Vector3(); 9589 result.subVectors( point, this.origin ); 9590 var directionDistance = result.dot( this.direction ); 9591 9592 if ( directionDistance < 0 ) { 9593 9594 return result.copy( this.origin ); 9595 9596 } 9597 9598 return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); 9599 9600 }, 9601 9602 distanceToPoint: function ( point ) { 9603 9604 return Math.sqrt( this.distanceSqToPoint( point ) ); 9605 9606 }, 9607 9608 distanceSqToPoint: function () { 9609 9610 var v1 = new Vector3(); 9611 9612 return function distanceSqToPoint( point ) { 9613 9614 var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); 9615 9616 // point behind the ray 9617 9618 if ( directionDistance < 0 ) { 9619 9620 return this.origin.distanceToSquared( point ); 9621 9622 } 9623 9624 v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); 9625 9626 return v1.distanceToSquared( point ); 9627 9628 }; 9629 9630 }(), 9631 9632 distanceSqToSegment: function () { 9633 9634 var segCenter = new Vector3(); 9635 var segDir = new Vector3(); 9636 var diff = new Vector3(); 9637 9638 return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { 9639 9640 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h 9641 // It returns the min distance between the ray and the segment 9642 // defined by v0 and v1 9643 // It can also set two optional targets : 9644 // - The closest point on the ray 9645 // - The closest point on the segment 9646 9647 segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); 9648 segDir.copy( v1 ).sub( v0 ).normalize(); 9649 diff.copy( this.origin ).sub( segCenter ); 9650 9651 var segExtent = v0.distanceTo( v1 ) * 0.5; 9652 var a01 = - this.direction.dot( segDir ); 9653 var b0 = diff.dot( this.direction ); 9654 var b1 = - diff.dot( segDir ); 9655 var c = diff.lengthSq(); 9656 var det = Math.abs( 1 - a01 * a01 ); 9657 var s0, s1, sqrDist, extDet; 9658 9659 if ( det > 0 ) { 9660 9661 // The ray and segment are not parallel. 9662 9663 s0 = a01 * b1 - b0; 9664 s1 = a01 * b0 - b1; 9665 extDet = segExtent * det; 9666 9667 if ( s0 >= 0 ) { 9668 9669 if ( s1 >= - extDet ) { 9670 9671 if ( s1 <= extDet ) { 9672 9673 // region 0 9674 // Minimum at interior points of ray and segment. 9675 9676 var invDet = 1 / det; 9677 s0 *= invDet; 9678 s1 *= invDet; 9679 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; 9680 9681 } else { 9682 9683 // region 1 9684 9685 s1 = segExtent; 9686 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 9687 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 9688 9689 } 9690 9691 } else { 9692 9693 // region 5 9694 9695 s1 = - segExtent; 9696 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 9697 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 9698 9699 } 9700 9701 } else { 9702 9703 if ( s1 <= - extDet ) { 9704 9705 // region 4 9706 9707 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); 9708 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 9709 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 9710 9711 } else if ( s1 <= extDet ) { 9712 9713 // region 3 9714 9715 s0 = 0; 9716 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); 9717 sqrDist = s1 * ( s1 + 2 * b1 ) + c; 9718 9719 } else { 9720 9721 // region 2 9722 9723 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); 9724 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 9725 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 9726 9727 } 9728 9729 } 9730 9731 } else { 9732 9733 // Ray and segment are parallel. 9734 9735 s1 = ( a01 > 0 ) ? - segExtent : segExtent; 9736 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 9737 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 9738 9739 } 9740 9741 if ( optionalPointOnRay ) { 9742 9743 optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); 9744 9745 } 9746 9747 if ( optionalPointOnSegment ) { 9748 9749 optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); 9750 9751 } 9752 9753 return sqrDist; 9754 9755 }; 9756 9757 }(), 9758 9759 intersectSphere: function () { 9760 9761 var v1 = new Vector3(); 9762 9763 return function intersectSphere( sphere, optionalTarget ) { 9764 9765 v1.subVectors( sphere.center, this.origin ); 9766 var tca = v1.dot( this.direction ); 9767 var d2 = v1.dot( v1 ) - tca * tca; 9768 var radius2 = sphere.radius * sphere.radius; 9769 9770 if ( d2 > radius2 ) return null; 9771 9772 var thc = Math.sqrt( radius2 - d2 ); 9773 9774 // t0 = first intersect point - entrance on front of sphere 9775 var t0 = tca - thc; 9776 9777 // t1 = second intersect point - exit point on back of sphere 9778 var t1 = tca + thc; 9779 9780 // test to see if both t0 and t1 are behind the ray - if so, return null 9781 if ( t0 < 0 && t1 < 0 ) return null; 9782 9783 // test to see if t0 is behind the ray: 9784 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, 9785 // in order to always return an intersect point that is in front of the ray. 9786 if ( t0 < 0 ) return this.at( t1, optionalTarget ); 9787 9788 // else t0 is in front of the ray, so return the first collision point scaled by t0 9789 return this.at( t0, optionalTarget ); 9790 9791 }; 9792 9793 }(), 9794 9795 intersectsSphere: function ( sphere ) { 9796 9797 return this.distanceToPoint( sphere.center ) <= sphere.radius; 9798 9799 }, 9800 9801 distanceToPlane: function ( plane ) { 9802 9803 var denominator = plane.normal.dot( this.direction ); 9804 9805 if ( denominator === 0 ) { 9806 9807 // line is coplanar, return origin 9808 if ( plane.distanceToPoint( this.origin ) === 0 ) { 9809 9810 return 0; 9811 9812 } 9813 9814 // Null is preferable to undefined since undefined means.... it is undefined 9815 9816 return null; 9817 9818 } 9819 9820 var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; 9821 9822 // Return if the ray never intersects the plane 9823 9824 return t >= 0 ? t : null; 9825 9826 }, 9827 9828 intersectPlane: function ( plane, optionalTarget ) { 9829 9830 var t = this.distanceToPlane( plane ); 9831 9832 if ( t === null ) { 9833 9834 return null; 9835 9836 } 9837 9838 return this.at( t, optionalTarget ); 9839 9840 }, 9841 9842 9843 9844 intersectsPlane: function ( plane ) { 9845 9846 // check if the ray lies on the plane first 9847 9848 var distToPoint = plane.distanceToPoint( this.origin ); 9849 9850 if ( distToPoint === 0 ) { 9851 9852 return true; 9853 9854 } 9855 9856 var denominator = plane.normal.dot( this.direction ); 9857 9858 if ( denominator * distToPoint < 0 ) { 9859 9860 return true; 9861 9862 } 9863 9864 // ray origin is behind the plane (and is pointing behind it) 9865 9866 return false; 9867 9868 }, 9869 9870 intersectBox: function ( box, optionalTarget ) { 9871 9872 var tmin, tmax, tymin, tymax, tzmin, tzmax; 9873 9874 var invdirx = 1 / this.direction.x, 9875 invdiry = 1 / this.direction.y, 9876 invdirz = 1 / this.direction.z; 9877 9878 var origin = this.origin; 9879 9880 if ( invdirx >= 0 ) { 9881 9882 tmin = ( box.min.x - origin.x ) * invdirx; 9883 tmax = ( box.max.x - origin.x ) * invdirx; 9884 9885 } else { 9886 9887 tmin = ( box.max.x - origin.x ) * invdirx; 9888 tmax = ( box.min.x - origin.x ) * invdirx; 9889 9890 } 9891 9892 if ( invdiry >= 0 ) { 9893 9894 tymin = ( box.min.y - origin.y ) * invdiry; 9895 tymax = ( box.max.y - origin.y ) * invdiry; 9896 9897 } else { 9898 9899 tymin = ( box.max.y - origin.y ) * invdiry; 9900 tymax = ( box.min.y - origin.y ) * invdiry; 9901 9902 } 9903 9904 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; 9905 9906 // These lines also handle the case where tmin or tmax is NaN 9907 // (result of 0 * Infinity). x !== x returns true if x is NaN 9908 9909 if ( tymin > tmin || tmin !== tmin ) tmin = tymin; 9910 9911 if ( tymax < tmax || tmax !== tmax ) tmax = tymax; 9912 9913 if ( invdirz >= 0 ) { 9914 9915 tzmin = ( box.min.z - origin.z ) * invdirz; 9916 tzmax = ( box.max.z - origin.z ) * invdirz; 9917 9918 } else { 9919 9920 tzmin = ( box.max.z - origin.z ) * invdirz; 9921 tzmax = ( box.min.z - origin.z ) * invdirz; 9922 9923 } 9924 9925 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; 9926 9927 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; 9928 9929 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; 9930 9931 //return point closest to the ray (positive side) 9932 9933 if ( tmax < 0 ) return null; 9934 9935 return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); 9936 9937 }, 9938 9939 intersectsBox: ( function () { 9940 9941 var v = new Vector3(); 9942 9943 return function intersectsBox( box ) { 9944 9945 return this.intersectBox( box, v ) !== null; 9946 9947 }; 9948 9949 } )(), 9950 9951 intersectTriangle: function () { 9952 9953 // Compute the offset origin, edges, and normal. 9954 var diff = new Vector3(); 9955 var edge1 = new Vector3(); 9956 var edge2 = new Vector3(); 9957 var normal = new Vector3(); 9958 9959 return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) { 9960 9961 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h 9962 9963 edge1.subVectors( b, a ); 9964 edge2.subVectors( c, a ); 9965 normal.crossVectors( edge1, edge2 ); 9966 9967 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, 9968 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by 9969 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) 9970 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) 9971 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) 9972 var DdN = this.direction.dot( normal ); 9973 var sign; 9974 9975 if ( DdN > 0 ) { 9976 9977 if ( backfaceCulling ) return null; 9978 sign = 1; 9979 9980 } else if ( DdN < 0 ) { 9981 9982 sign = - 1; 9983 DdN = - DdN; 9984 9985 } else { 9986 9987 return null; 9988 9989 } 9990 9991 diff.subVectors( this.origin, a ); 9992 var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); 9993 9994 // b1 < 0, no intersection 9995 if ( DdQxE2 < 0 ) { 9996 9997 return null; 9998 9999 } 10000 10001 var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); 10002 10003 // b2 < 0, no intersection 10004 if ( DdE1xQ < 0 ) { 10005 10006 return null; 10007 10008 } 10009 10010 // b1+b2 > 1, no intersection 10011 if ( DdQxE2 + DdE1xQ > DdN ) { 10012 10013 return null; 10014 10015 } 10016 10017 // Line intersects triangle, check if ray does. 10018 var QdN = - sign * diff.dot( normal ); 10019 10020 // t < 0, no intersection 10021 if ( QdN < 0 ) { 10022 10023 return null; 10024 10025 } 10026 10027 // Ray intersects triangle. 10028 return this.at( QdN / DdN, optionalTarget ); 10029 10030 }; 10031 10032 }(), 10033 10034 applyMatrix4: function ( matrix4 ) { 10035 10036 this.direction.add( this.origin ).applyMatrix4( matrix4 ); 10037 this.origin.applyMatrix4( matrix4 ); 10038 this.direction.sub( this.origin ); 10039 this.direction.normalize(); 10040 10041 return this; 10042 10043 }, 10044 10045 equals: function ( ray ) { 10046 10047 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); 10048 10049 } 10050 10051 }; 10052 10053 /** 10054 * @author mrdoob / http://mrdoob.com/ 10055 * @author WestLangley / http://github.com/WestLangley 10056 * @author bhouston / http://clara.io 10057 */ 10058 10059 function Euler( x, y, z, order ) { 10060 10061 this._x = x || 0; 10062 this._y = y || 0; 10063 this._z = z || 0; 10064 this._order = order || Euler.DefaultOrder; 10065 10066 } 10067 10068 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; 10069 10070 Euler.DefaultOrder = 'XYZ'; 10071 10072 Euler.prototype = { 10073 10074 constructor: Euler, 10075 10076 isEuler: true, 10077 10078 get x () { 10079 10080 return this._x; 10081 10082 }, 10083 10084 set x ( value ) { 10085 10086 this._x = value; 10087 this.onChangeCallback(); 10088 10089 }, 10090 10091 get y () { 10092 10093 return this._y; 10094 10095 }, 10096 10097 set y ( value ) { 10098 10099 this._y = value; 10100 this.onChangeCallback(); 10101 10102 }, 10103 10104 get z () { 10105 10106 return this._z; 10107 10108 }, 10109 10110 set z ( value ) { 10111 10112 this._z = value; 10113 this.onChangeCallback(); 10114 10115 }, 10116 10117 get order () { 10118 10119 return this._order; 10120 10121 }, 10122 10123 set order ( value ) { 10124 10125 this._order = value; 10126 this.onChangeCallback(); 10127 10128 }, 10129 10130 set: function ( x, y, z, order ) { 10131 10132 this._x = x; 10133 this._y = y; 10134 this._z = z; 10135 this._order = order || this._order; 10136 10137 this.onChangeCallback(); 10138 10139 return this; 10140 10141 }, 10142 10143 clone: function () { 10144 10145 return new this.constructor( this._x, this._y, this._z, this._order ); 10146 10147 }, 10148 10149 copy: function ( euler ) { 10150 10151 this._x = euler._x; 10152 this._y = euler._y; 10153 this._z = euler._z; 10154 this._order = euler._order; 10155 10156 this.onChangeCallback(); 10157 10158 return this; 10159 10160 }, 10161 10162 setFromRotationMatrix: function ( m, order, update ) { 10163 10164 var clamp = _Math.clamp; 10165 10166 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 10167 10168 var te = m.elements; 10169 var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; 10170 var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; 10171 var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 10172 10173 order = order || this._order; 10174 10175 if ( order === 'XYZ' ) { 10176 10177 this._y = Math.asin( clamp( m13, - 1, 1 ) ); 10178 10179 if ( Math.abs( m13 ) < 0.99999 ) { 10180 10181 this._x = Math.atan2( - m23, m33 ); 10182 this._z = Math.atan2( - m12, m11 ); 10183 10184 } else { 10185 10186 this._x = Math.atan2( m32, m22 ); 10187 this._z = 0; 10188 10189 } 10190 10191 } else if ( order === 'YXZ' ) { 10192 10193 this._x = Math.asin( - clamp( m23, - 1, 1 ) ); 10194 10195 if ( Math.abs( m23 ) < 0.99999 ) { 10196 10197 this._y = Math.atan2( m13, m33 ); 10198 this._z = Math.atan2( m21, m22 ); 10199 10200 } else { 10201 10202 this._y = Math.atan2( - m31, m11 ); 10203 this._z = 0; 10204 10205 } 10206 10207 } else if ( order === 'ZXY' ) { 10208 10209 this._x = Math.asin( clamp( m32, - 1, 1 ) ); 10210 10211 if ( Math.abs( m32 ) < 0.99999 ) { 10212 10213 this._y = Math.atan2( - m31, m33 ); 10214 this._z = Math.atan2( - m12, m22 ); 10215 10216 } else { 10217 10218 this._y = 0; 10219 this._z = Math.atan2( m21, m11 ); 10220 10221 } 10222 10223 } else if ( order === 'ZYX' ) { 10224 10225 this._y = Math.asin( - clamp( m31, - 1, 1 ) ); 10226 10227 if ( Math.abs( m31 ) < 0.99999 ) { 10228 10229 this._x = Math.atan2( m32, m33 ); 10230 this._z = Math.atan2( m21, m11 ); 10231 10232 } else { 10233 10234 this._x = 0; 10235 this._z = Math.atan2( - m12, m22 ); 10236 10237 } 10238 10239 } else if ( order === 'YZX' ) { 10240 10241 this._z = Math.asin( clamp( m21, - 1, 1 ) ); 10242 10243 if ( Math.abs( m21 ) < 0.99999 ) { 10244 10245 this._x = Math.atan2( - m23, m22 ); 10246 this._y = Math.atan2( - m31, m11 ); 10247 10248 } else { 10249 10250 this._x = 0; 10251 this._y = Math.atan2( m13, m33 ); 10252 10253 } 10254 10255 } else if ( order === 'XZY' ) { 10256 10257 this._z = Math.asin( - clamp( m12, - 1, 1 ) ); 10258 10259 if ( Math.abs( m12 ) < 0.99999 ) { 10260 10261 this._x = Math.atan2( m32, m22 ); 10262 this._y = Math.atan2( m13, m11 ); 10263 10264 } else { 10265 10266 this._x = Math.atan2( - m23, m33 ); 10267 this._y = 0; 10268 10269 } 10270 10271 } else { 10272 10273 console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); 10274 10275 } 10276 10277 this._order = order; 10278 10279 if ( update !== false ) this.onChangeCallback(); 10280 10281 return this; 10282 10283 }, 10284 10285 setFromQuaternion: function () { 10286 10287 var matrix; 10288 10289 return function setFromQuaternion( q, order, update ) { 10290 10291 if ( matrix === undefined ) matrix = new Matrix4(); 10292 10293 matrix.makeRotationFromQuaternion( q ); 10294 10295 return this.setFromRotationMatrix( matrix, order, update ); 10296 10297 }; 10298 10299 }(), 10300 10301 setFromVector3: function ( v, order ) { 10302 10303 return this.set( v.x, v.y, v.z, order || this._order ); 10304 10305 }, 10306 10307 reorder: function () { 10308 10309 // WARNING: this discards revolution information -bhouston 10310 10311 var q = new Quaternion(); 10312 10313 return function reorder( newOrder ) { 10314 10315 q.setFromEuler( this ); 10316 10317 return this.setFromQuaternion( q, newOrder ); 10318 10319 }; 10320 10321 }(), 10322 10323 equals: function ( euler ) { 10324 10325 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); 10326 10327 }, 10328 10329 fromArray: function ( array ) { 10330 10331 this._x = array[ 0 ]; 10332 this._y = array[ 1 ]; 10333 this._z = array[ 2 ]; 10334 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; 10335 10336 this.onChangeCallback(); 10337 10338 return this; 10339 10340 }, 10341 10342 toArray: function ( array, offset ) { 10343 10344 if ( array === undefined ) array = []; 10345 if ( offset === undefined ) offset = 0; 10346 10347 array[ offset ] = this._x; 10348 array[ offset + 1 ] = this._y; 10349 array[ offset + 2 ] = this._z; 10350 array[ offset + 3 ] = this._order; 10351 10352 return array; 10353 10354 }, 10355 10356 toVector3: function ( optionalResult ) { 10357 10358 if ( optionalResult ) { 10359 10360 return optionalResult.set( this._x, this._y, this._z ); 10361 10362 } else { 10363 10364 return new Vector3( this._x, this._y, this._z ); 10365 10366 } 10367 10368 }, 10369 10370 onChange: function ( callback ) { 10371 10372 this.onChangeCallback = callback; 10373 10374 return this; 10375 10376 }, 10377 10378 onChangeCallback: function () {} 10379 10380 }; 10381 10382 /** 10383 * @author mrdoob / http://mrdoob.com/ 10384 */ 10385 10386 function Layers() { 10387 10388 this.mask = 1; 10389 10390 } 10391 10392 Layers.prototype = { 10393 10394 constructor: Layers, 10395 10396 set: function ( channel ) { 10397 10398 this.mask = 1 << channel; 10399 10400 }, 10401 10402 enable: function ( channel ) { 10403 10404 this.mask |= 1 << channel; 10405 10406 }, 10407 10408 toggle: function ( channel ) { 10409 10410 this.mask ^= 1 << channel; 10411 10412 }, 10413 10414 disable: function ( channel ) { 10415 10416 this.mask &= ~ ( 1 << channel ); 10417 10418 }, 10419 10420 test: function ( layers ) { 10421 10422 return ( this.mask & layers.mask ) !== 0; 10423 10424 } 10425 10426 }; 10427 10428 /** 10429 * @author mrdoob / http://mrdoob.com/ 10430 * @author mikael emtinger / http://gomo.se/ 10431 * @author alteredq / http://alteredqualia.com/ 10432 * @author WestLangley / http://github.com/WestLangley 10433 * @author elephantatwork / www.elephantatwork.ch 10434 */ 10435 10436 var object3DId = 0; 10437 10438 function Object3D() { 10439 10440 Object.defineProperty( this, 'id', { value: object3DId ++ } ); 10441 10442 this.uuid = _Math.generateUUID(); 10443 10444 this.name = ''; 10445 this.type = 'Object3D'; 10446 10447 this.parent = null; 10448 this.children = []; 10449 10450 this.up = Object3D.DefaultUp.clone(); 10451 10452 var position = new Vector3(); 10453 var rotation = new Euler(); 10454 var quaternion = new Quaternion(); 10455 var scale = new Vector3( 1, 1, 1 ); 10456 10457 function onRotationChange() { 10458 10459 quaternion.setFromEuler( rotation, false ); 10460 10461 } 10462 10463 function onQuaternionChange() { 10464 10465 rotation.setFromQuaternion( quaternion, undefined, false ); 10466 10467 } 10468 10469 rotation.onChange( onRotationChange ); 10470 quaternion.onChange( onQuaternionChange ); 10471 10472 Object.defineProperties( this, { 10473 position: { 10474 enumerable: true, 10475 value: position 10476 }, 10477 rotation: { 10478 enumerable: true, 10479 value: rotation 10480 }, 10481 quaternion: { 10482 enumerable: true, 10483 value: quaternion 10484 }, 10485 scale: { 10486 enumerable: true, 10487 value: scale 10488 }, 10489 modelViewMatrix: { 10490 value: new Matrix4() 10491 }, 10492 normalMatrix: { 10493 value: new Matrix3() 10494 } 10495 } ); 10496 10497 this.matrix = new Matrix4(); 10498 this.matrixWorld = new Matrix4(); 10499 10500 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; 10501 this.matrixWorldNeedsUpdate = false; 10502 10503 this.layers = new Layers(); 10504 this.visible = true; 10505 10506 this.castShadow = false; 10507 this.receiveShadow = false; 10508 10509 this.frustumCulled = true; 10510 this.renderOrder = 0; 10511 10512 this.userData = {}; 10513 10514 this.onBeforeRender = function () {}; 10515 this.onAfterRender = function () {}; 10516 10517 } 10518 10519 Object3D.DefaultUp = new Vector3( 0, 1, 0 ); 10520 Object3D.DefaultMatrixAutoUpdate = true; 10521 10522 Object3D.prototype = { 10523 10524 constructor: Object3D, 10525 10526 isObject3D: true, 10527 10528 applyMatrix: function ( matrix ) { 10529 10530 this.matrix.multiplyMatrices( matrix, this.matrix ); 10531 10532 this.matrix.decompose( this.position, this.quaternion, this.scale ); 10533 10534 }, 10535 10536 setRotationFromAxisAngle: function ( axis, angle ) { 10537 10538 // assumes axis is normalized 10539 10540 this.quaternion.setFromAxisAngle( axis, angle ); 10541 10542 }, 10543 10544 setRotationFromEuler: function ( euler ) { 10545 10546 this.quaternion.setFromEuler( euler, true ); 10547 10548 }, 10549 10550 setRotationFromMatrix: function ( m ) { 10551 10552 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 10553 10554 this.quaternion.setFromRotationMatrix( m ); 10555 10556 }, 10557 10558 setRotationFromQuaternion: function ( q ) { 10559 10560 // assumes q is normalized 10561 10562 this.quaternion.copy( q ); 10563 10564 }, 10565 10566 rotateOnAxis: function () { 10567 10568 // rotate object on axis in object space 10569 // axis is assumed to be normalized 10570 10571 var q1 = new Quaternion(); 10572 10573 return function rotateOnAxis( axis, angle ) { 10574 10575 q1.setFromAxisAngle( axis, angle ); 10576 10577 this.quaternion.multiply( q1 ); 10578 10579 return this; 10580 10581 }; 10582 10583 }(), 10584 10585 rotateX: function () { 10586 10587 var v1 = new Vector3( 1, 0, 0 ); 10588 10589 return function rotateX( angle ) { 10590 10591 return this.rotateOnAxis( v1, angle ); 10592 10593 }; 10594 10595 }(), 10596 10597 rotateY: function () { 10598 10599 var v1 = new Vector3( 0, 1, 0 ); 10600 10601 return function rotateY( angle ) { 10602 10603 return this.rotateOnAxis( v1, angle ); 10604 10605 }; 10606 10607 }(), 10608 10609 rotateZ: function () { 10610 10611 var v1 = new Vector3( 0, 0, 1 ); 10612 10613 return function rotateZ( angle ) { 10614 10615 return this.rotateOnAxis( v1, angle ); 10616 10617 }; 10618 10619 }(), 10620 10621 translateOnAxis: function () { 10622 10623 // translate object by distance along axis in object space 10624 // axis is assumed to be normalized 10625 10626 var v1 = new Vector3(); 10627 10628 return function translateOnAxis( axis, distance ) { 10629 10630 v1.copy( axis ).applyQuaternion( this.quaternion ); 10631 10632 this.position.add( v1.multiplyScalar( distance ) ); 10633 10634 return this; 10635 10636 }; 10637 10638 }(), 10639 10640 translateX: function () { 10641 10642 var v1 = new Vector3( 1, 0, 0 ); 10643 10644 return function translateX( distance ) { 10645 10646 return this.translateOnAxis( v1, distance ); 10647 10648 }; 10649 10650 }(), 10651 10652 translateY: function () { 10653 10654 var v1 = new Vector3( 0, 1, 0 ); 10655 10656 return function translateY( distance ) { 10657 10658 return this.translateOnAxis( v1, distance ); 10659 10660 }; 10661 10662 }(), 10663 10664 translateZ: function () { 10665 10666 var v1 = new Vector3( 0, 0, 1 ); 10667 10668 return function translateZ( distance ) { 10669 10670 return this.translateOnAxis( v1, distance ); 10671 10672 }; 10673 10674 }(), 10675 10676 localToWorld: function ( vector ) { 10677 10678 return vector.applyMatrix4( this.matrixWorld ); 10679 10680 }, 10681 10682 worldToLocal: function () { 10683 10684 var m1 = new Matrix4(); 10685 10686 return function worldToLocal( vector ) { 10687 10688 return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); 10689 10690 }; 10691 10692 }(), 10693 10694 lookAt: function () { 10695 10696 // This routine does not support objects with rotated and/or translated parent(s) 10697 10698 var m1 = new Matrix4(); 10699 10700 return function lookAt( vector ) { 10701 10702 m1.lookAt( vector, this.position, this.up ); 10703 10704 this.quaternion.setFromRotationMatrix( m1 ); 10705 10706 }; 10707 10708 }(), 10709 10710 add: function ( object ) { 10711 10712 if ( arguments.length > 1 ) { 10713 10714 for ( var i = 0; i < arguments.length; i ++ ) { 10715 10716 this.add( arguments[ i ] ); 10717 10718 } 10719 10720 return this; 10721 10722 } 10723 10724 if ( object === this ) { 10725 10726 console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); 10727 return this; 10728 10729 } 10730 10731 if ( ( object && object.isObject3D ) ) { 10732 10733 if ( object.parent !== null ) { 10734 10735 object.parent.remove( object ); 10736 10737 } 10738 10739 object.parent = this; 10740 object.dispatchEvent( { type: 'added' } ); 10741 10742 this.children.push( object ); 10743 10744 } else { 10745 10746 console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); 10747 10748 } 10749 10750 return this; 10751 10752 }, 10753 10754 remove: function ( object ) { 10755 10756 if ( arguments.length > 1 ) { 10757 10758 for ( var i = 0; i < arguments.length; i ++ ) { 10759 10760 this.remove( arguments[ i ] ); 10761 10762 } 10763 10764 } 10765 10766 var index = this.children.indexOf( object ); 10767 10768 if ( index !== - 1 ) { 10769 10770 object.parent = null; 10771 10772 object.dispatchEvent( { type: 'removed' } ); 10773 10774 this.children.splice( index, 1 ); 10775 10776 } 10777 10778 }, 10779 10780 getObjectById: function ( id ) { 10781 10782 return this.getObjectByProperty( 'id', id ); 10783 10784 }, 10785 10786 getObjectByName: function ( name ) { 10787 10788 return this.getObjectByProperty( 'name', name ); 10789 10790 }, 10791 10792 getObjectByProperty: function ( name, value ) { 10793 10794 if ( this[ name ] === value ) return this; 10795 10796 for ( var i = 0, l = this.children.length; i < l; i ++ ) { 10797 10798 var child = this.children[ i ]; 10799 var object = child.getObjectByProperty( name, value ); 10800 10801 if ( object !== undefined ) { 10802 10803 return object; 10804 10805 } 10806 10807 } 10808 10809 return undefined; 10810 10811 }, 10812 10813 getWorldPosition: function ( optionalTarget ) { 10814 10815 var result = optionalTarget || new Vector3(); 10816 10817 this.updateMatrixWorld( true ); 10818 10819 return result.setFromMatrixPosition( this.matrixWorld ); 10820 10821 }, 10822 10823 getWorldQuaternion: function () { 10824 10825 var position = new Vector3(); 10826 var scale = new Vector3(); 10827 10828 return function getWorldQuaternion( optionalTarget ) { 10829 10830 var result = optionalTarget || new Quaternion(); 10831 10832 this.updateMatrixWorld( true ); 10833 10834 this.matrixWorld.decompose( position, result, scale ); 10835 10836 return result; 10837 10838 }; 10839 10840 }(), 10841 10842 getWorldRotation: function () { 10843 10844 var quaternion = new Quaternion(); 10845 10846 return function getWorldRotation( optionalTarget ) { 10847 10848 var result = optionalTarget || new Euler(); 10849 10850 this.getWorldQuaternion( quaternion ); 10851 10852 return result.setFromQuaternion( quaternion, this.rotation.order, false ); 10853 10854 }; 10855 10856 }(), 10857 10858 getWorldScale: function () { 10859 10860 var position = new Vector3(); 10861 var quaternion = new Quaternion(); 10862 10863 return function getWorldScale( optionalTarget ) { 10864 10865 var result = optionalTarget || new Vector3(); 10866 10867 this.updateMatrixWorld( true ); 10868 10869 this.matrixWorld.decompose( position, quaternion, result ); 10870 10871 return result; 10872 10873 }; 10874 10875 }(), 10876 10877 getWorldDirection: function () { 10878 10879 var quaternion = new Quaternion(); 10880 10881 return function getWorldDirection( optionalTarget ) { 10882 10883 var result = optionalTarget || new Vector3(); 10884 10885 this.getWorldQuaternion( quaternion ); 10886 10887 return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); 10888 10889 }; 10890 10891 }(), 10892 10893 raycast: function () {}, 10894 10895 traverse: function ( callback ) { 10896 10897 callback( this ); 10898 10899 var children = this.children; 10900 10901 for ( var i = 0, l = children.length; i < l; i ++ ) { 10902 10903 children[ i ].traverse( callback ); 10904 10905 } 10906 10907 }, 10908 10909 traverseVisible: function ( callback ) { 10910 10911 if ( this.visible === false ) return; 10912 10913 callback( this ); 10914 10915 var children = this.children; 10916 10917 for ( var i = 0, l = children.length; i < l; i ++ ) { 10918 10919 children[ i ].traverseVisible( callback ); 10920 10921 } 10922 10923 }, 10924 10925 traverseAncestors: function ( callback ) { 10926 10927 var parent = this.parent; 10928 10929 if ( parent !== null ) { 10930 10931 callback( parent ); 10932 10933 parent.traverseAncestors( callback ); 10934 10935 } 10936 10937 }, 10938 10939 updateMatrix: function () { 10940 10941 this.matrix.compose( this.position, this.quaternion, this.scale ); 10942 10943 this.matrixWorldNeedsUpdate = true; 10944 10945 }, 10946 10947 updateMatrixWorld: function ( force ) { 10948 10949 if ( this.matrixAutoUpdate === true ) this.updateMatrix(); 10950 10951 if ( this.matrixWorldNeedsUpdate === true || force === true ) { 10952 10953 if ( this.parent === null ) { 10954 10955 this.matrixWorld.copy( this.matrix ); 10956 10957 } else { 10958 10959 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 10960 10961 } 10962 10963 this.matrixWorldNeedsUpdate = false; 10964 10965 force = true; 10966 10967 } 10968 10969 // update children 10970 10971 var children = this.children; 10972 10973 for ( var i = 0, l = children.length; i < l; i ++ ) { 10974 10975 children[ i ].updateMatrixWorld( force ); 10976 10977 } 10978 10979 }, 10980 10981 toJSON: function ( meta ) { 10982 10983 // meta is '' when called from JSON.stringify 10984 var isRootObject = ( meta === undefined || meta === '' ); 10985 10986 var output = {}; 10987 10988 // meta is a hash used to collect geometries, materials. 10989 // not providing it implies that this is the root object 10990 // being serialized. 10991 if ( isRootObject ) { 10992 10993 // initialize meta obj 10994 meta = { 10995 geometries: {}, 10996 materials: {}, 10997 textures: {}, 10998 images: {} 10999 }; 11000 11001 output.metadata = { 11002 version: 4.4, 11003 type: 'Object', 11004 generator: 'Object3D.toJSON' 11005 }; 11006 11007 } 11008 11009 // standard Object3D serialization 11010 11011 var object = {}; 11012 11013 object.uuid = this.uuid; 11014 object.type = this.type; 11015 11016 if ( this.name !== '' ) object.name = this.name; 11017 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; 11018 if ( this.castShadow === true ) object.castShadow = true; 11019 if ( this.receiveShadow === true ) object.receiveShadow = true; 11020 if ( this.visible === false ) object.visible = false; 11021 11022 object.matrix = this.matrix.toArray(); 11023 11024 // 11025 11026 if ( this.geometry !== undefined ) { 11027 11028 if ( meta.geometries[ this.geometry.uuid ] === undefined ) { 11029 11030 meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta ); 11031 11032 } 11033 11034 object.geometry = this.geometry.uuid; 11035 11036 } 11037 11038 if ( this.material !== undefined ) { 11039 11040 if ( meta.materials[ this.material.uuid ] === undefined ) { 11041 11042 meta.materials[ this.material.uuid ] = this.material.toJSON( meta ); 11043 11044 } 11045 11046 object.material = this.material.uuid; 11047 11048 } 11049 11050 // 11051 11052 if ( this.children.length > 0 ) { 11053 11054 object.children = []; 11055 11056 for ( var i = 0; i < this.children.length; i ++ ) { 11057 11058 object.children.push( this.children[ i ].toJSON( meta ).object ); 11059 11060 } 11061 11062 } 11063 11064 if ( isRootObject ) { 11065 11066 var geometries = extractFromCache( meta.geometries ); 11067 var materials = extractFromCache( meta.materials ); 11068 var textures = extractFromCache( meta.textures ); 11069 var images = extractFromCache( meta.images ); 11070 11071 if ( geometries.length > 0 ) output.geometries = geometries; 11072 if ( materials.length > 0 ) output.materials = materials; 11073 if ( textures.length > 0 ) output.textures = textures; 11074 if ( images.length > 0 ) output.images = images; 11075 11076 } 11077 11078 output.object = object; 11079 11080 return output; 11081 11082 // extract data from the cache hash 11083 // remove metadata on each item 11084 // and return as array 11085 function extractFromCache( cache ) { 11086 11087 var values = []; 11088 for ( var key in cache ) { 11089 11090 var data = cache[ key ]; 11091 delete data.metadata; 11092 values.push( data ); 11093 11094 } 11095 return values; 11096 11097 } 11098 11099 }, 11100 11101 clone: function ( recursive ) { 11102 11103 return new this.constructor().copy( this, recursive ); 11104 11105 }, 11106 11107 copy: function ( source, recursive ) { 11108 11109 if ( recursive === undefined ) recursive = true; 11110 11111 this.name = source.name; 11112 11113 this.up.copy( source.up ); 11114 11115 this.position.copy( source.position ); 11116 this.quaternion.copy( source.quaternion ); 11117 this.scale.copy( source.scale ); 11118 11119 this.matrix.copy( source.matrix ); 11120 this.matrixWorld.copy( source.matrixWorld ); 11121 11122 this.matrixAutoUpdate = source.matrixAutoUpdate; 11123 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 11124 11125 this.layers.mask = source.layers.mask; 11126 this.visible = source.visible; 11127 11128 this.castShadow = source.castShadow; 11129 this.receiveShadow = source.receiveShadow; 11130 11131 this.frustumCulled = source.frustumCulled; 11132 this.renderOrder = source.renderOrder; 11133 11134 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 11135 11136 if ( recursive === true ) { 11137 11138 for ( var i = 0; i < source.children.length; i ++ ) { 11139 11140 var child = source.children[ i ]; 11141 this.add( child.clone() ); 11142 11143 } 11144 11145 } 11146 11147 return this; 11148 11149 } 11150 11151 }; 11152 11153 Object.assign( Object3D.prototype, EventDispatcher.prototype ); 11154 11155 /** 11156 * @author bhouston / http://clara.io 11157 */ 11158 11159 function Line3( start, end ) { 11160 11161 this.start = ( start !== undefined ) ? start : new Vector3(); 11162 this.end = ( end !== undefined ) ? end : new Vector3(); 11163 11164 } 11165 11166 Line3.prototype = { 11167 11168 constructor: Line3, 11169 11170 set: function ( start, end ) { 11171 11172 this.start.copy( start ); 11173 this.end.copy( end ); 11174 11175 return this; 11176 11177 }, 11178 11179 clone: function () { 11180 11181 return new this.constructor().copy( this ); 11182 11183 }, 11184 11185 copy: function ( line ) { 11186 11187 this.start.copy( line.start ); 11188 this.end.copy( line.end ); 11189 11190 return this; 11191 11192 }, 11193 11194 getCenter: function ( optionalTarget ) { 11195 11196 var result = optionalTarget || new Vector3(); 11197 return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); 11198 11199 }, 11200 11201 delta: function ( optionalTarget ) { 11202 11203 var result = optionalTarget || new Vector3(); 11204 return result.subVectors( this.end, this.start ); 11205 11206 }, 11207 11208 distanceSq: function () { 11209 11210 return this.start.distanceToSquared( this.end ); 11211 11212 }, 11213 11214 distance: function () { 11215 11216 return this.start.distanceTo( this.end ); 11217 11218 }, 11219 11220 at: function ( t, optionalTarget ) { 11221 11222 var result = optionalTarget || new Vector3(); 11223 11224 return this.delta( result ).multiplyScalar( t ).add( this.start ); 11225 11226 }, 11227 11228 closestPointToPointParameter: function () { 11229 11230 var startP = new Vector3(); 11231 var startEnd = new Vector3(); 11232 11233 return function closestPointToPointParameter( point, clampToLine ) { 11234 11235 startP.subVectors( point, this.start ); 11236 startEnd.subVectors( this.end, this.start ); 11237 11238 var startEnd2 = startEnd.dot( startEnd ); 11239 var startEnd_startP = startEnd.dot( startP ); 11240 11241 var t = startEnd_startP / startEnd2; 11242 11243 if ( clampToLine ) { 11244 11245 t = _Math.clamp( t, 0, 1 ); 11246 11247 } 11248 11249 return t; 11250 11251 }; 11252 11253 }(), 11254 11255 closestPointToPoint: function ( point, clampToLine, optionalTarget ) { 11256 11257 var t = this.closestPointToPointParameter( point, clampToLine ); 11258 11259 var result = optionalTarget || new Vector3(); 11260 11261 return this.delta( result ).multiplyScalar( t ).add( this.start ); 11262 11263 }, 11264 11265 applyMatrix4: function ( matrix ) { 11266 11267 this.start.applyMatrix4( matrix ); 11268 this.end.applyMatrix4( matrix ); 11269 11270 return this; 11271 11272 }, 11273 11274 equals: function ( line ) { 11275 11276 return line.start.equals( this.start ) && line.end.equals( this.end ); 11277 11278 } 11279 11280 }; 11281 11282 /** 11283 * @author bhouston / http://clara.io 11284 * @author mrdoob / http://mrdoob.com/ 11285 */ 11286 11287 function Triangle( a, b, c ) { 11288 11289 this.a = ( a !== undefined ) ? a : new Vector3(); 11290 this.b = ( b !== undefined ) ? b : new Vector3(); 11291 this.c = ( c !== undefined ) ? c : new Vector3(); 11292 11293 } 11294 11295 Triangle.normal = function () { 11296 11297 var v0 = new Vector3(); 11298 11299 return function normal( a, b, c, optionalTarget ) { 11300 11301 var result = optionalTarget || new Vector3(); 11302 11303 result.subVectors( c, b ); 11304 v0.subVectors( a, b ); 11305 result.cross( v0 ); 11306 11307 var resultLengthSq = result.lengthSq(); 11308 if ( resultLengthSq > 0 ) { 11309 11310 return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); 11311 11312 } 11313 11314 return result.set( 0, 0, 0 ); 11315 11316 }; 11317 11318 }(); 11319 11320 // static/instance method to calculate barycentric coordinates 11321 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 11322 Triangle.barycoordFromPoint = function () { 11323 11324 var v0 = new Vector3(); 11325 var v1 = new Vector3(); 11326 var v2 = new Vector3(); 11327 11328 return function barycoordFromPoint( point, a, b, c, optionalTarget ) { 11329 11330 v0.subVectors( c, a ); 11331 v1.subVectors( b, a ); 11332 v2.subVectors( point, a ); 11333 11334 var dot00 = v0.dot( v0 ); 11335 var dot01 = v0.dot( v1 ); 11336 var dot02 = v0.dot( v2 ); 11337 var dot11 = v1.dot( v1 ); 11338 var dot12 = v1.dot( v2 ); 11339 11340 var denom = ( dot00 * dot11 - dot01 * dot01 ); 11341 11342 var result = optionalTarget || new Vector3(); 11343 11344 // collinear or singular triangle 11345 if ( denom === 0 ) { 11346 11347 // arbitrary location outside of triangle? 11348 // not sure if this is the best idea, maybe should be returning undefined 11349 return result.set( - 2, - 1, - 1 ); 11350 11351 } 11352 11353 var invDenom = 1 / denom; 11354 var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; 11355 var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; 11356 11357 // barycentric coordinates must always sum to 1 11358 return result.set( 1 - u - v, v, u ); 11359 11360 }; 11361 11362 }(); 11363 11364 Triangle.containsPoint = function () { 11365 11366 var v1 = new Vector3(); 11367 11368 return function containsPoint( point, a, b, c ) { 11369 11370 var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); 11371 11372 return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); 11373 11374 }; 11375 11376 }(); 11377 11378 Triangle.prototype = { 11379 11380 constructor: Triangle, 11381 11382 set: function ( a, b, c ) { 11383 11384 this.a.copy( a ); 11385 this.b.copy( b ); 11386 this.c.copy( c ); 11387 11388 return this; 11389 11390 }, 11391 11392 setFromPointsAndIndices: function ( points, i0, i1, i2 ) { 11393 11394 this.a.copy( points[ i0 ] ); 11395 this.b.copy( points[ i1 ] ); 11396 this.c.copy( points[ i2 ] ); 11397 11398 return this; 11399 11400 }, 11401 11402 clone: function () { 11403 11404 return new this.constructor().copy( this ); 11405 11406 }, 11407 11408 copy: function ( triangle ) { 11409 11410 this.a.copy( triangle.a ); 11411 this.b.copy( triangle.b ); 11412 this.c.copy( triangle.c ); 11413 11414 return this; 11415 11416 }, 11417 11418 area: function () { 11419 11420 var v0 = new Vector3(); 11421 var v1 = new Vector3(); 11422 11423 return function area() { 11424 11425 v0.subVectors( this.c, this.b ); 11426 v1.subVectors( this.a, this.b ); 11427 11428 return v0.cross( v1 ).length() * 0.5; 11429 11430 }; 11431 11432 }(), 11433 11434 midpoint: function ( optionalTarget ) { 11435 11436 var result = optionalTarget || new Vector3(); 11437 return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); 11438 11439 }, 11440 11441 normal: function ( optionalTarget ) { 11442 11443 return Triangle.normal( this.a, this.b, this.c, optionalTarget ); 11444 11445 }, 11446 11447 plane: function ( optionalTarget ) { 11448 11449 var result = optionalTarget || new Plane(); 11450 11451 return result.setFromCoplanarPoints( this.a, this.b, this.c ); 11452 11453 }, 11454 11455 barycoordFromPoint: function ( point, optionalTarget ) { 11456 11457 return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); 11458 11459 }, 11460 11461 containsPoint: function ( point ) { 11462 11463 return Triangle.containsPoint( point, this.a, this.b, this.c ); 11464 11465 }, 11466 11467 closestPointToPoint: function () { 11468 11469 var plane, edgeList, projectedPoint, closestPoint; 11470 11471 return function closestPointToPoint( point, optionalTarget ) { 11472 11473 if ( plane === undefined ) { 11474 11475 plane = new Plane(); 11476 edgeList = [ new Line3(), new Line3(), new Line3() ]; 11477 projectedPoint = new Vector3(); 11478 closestPoint = new Vector3(); 11479 11480 } 11481 11482 var result = optionalTarget || new Vector3(); 11483 var minDistance = Infinity; 11484 11485 // project the point onto the plane of the triangle 11486 11487 plane.setFromCoplanarPoints( this.a, this.b, this.c ); 11488 plane.projectPoint( point, projectedPoint ); 11489 11490 // check if the projection lies within the triangle 11491 11492 if( this.containsPoint( projectedPoint ) === true ) { 11493 11494 // if so, this is the closest point 11495 11496 result.copy( projectedPoint ); 11497 11498 } else { 11499 11500 // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices 11501 11502 edgeList[ 0 ].set( this.a, this.b ); 11503 edgeList[ 1 ].set( this.b, this.c ); 11504 edgeList[ 2 ].set( this.c, this.a ); 11505 11506 for( var i = 0; i < edgeList.length; i ++ ) { 11507 11508 edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint ); 11509 11510 var distance = projectedPoint.distanceToSquared( closestPoint ); 11511 11512 if( distance < minDistance ) { 11513 11514 minDistance = distance; 11515 11516 result.copy( closestPoint ); 11517 11518 } 11519 11520 } 11521 11522 } 11523 11524 return result; 11525 11526 }; 11527 11528 }(), 11529 11530 equals: function ( triangle ) { 11531 11532 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); 11533 11534 } 11535 11536 }; 11537 11538 /** 11539 * @author mrdoob / http://mrdoob.com/ 11540 * @author alteredq / http://alteredqualia.com/ 11541 */ 11542 11543 function Face3( a, b, c, normal, color, materialIndex ) { 11544 11545 this.a = a; 11546 this.b = b; 11547 this.c = c; 11548 11549 this.normal = (normal && normal.isVector3) ? normal : new Vector3(); 11550 this.vertexNormals = Array.isArray( normal ) ? normal : []; 11551 11552 this.color = (color && color.isColor) ? color : new Color(); 11553 this.vertexColors = Array.isArray( color ) ? color : []; 11554 11555 this.materialIndex = materialIndex !== undefined ? materialIndex : 0; 11556 11557 } 11558 11559 Face3.prototype = { 11560 11561 constructor: Face3, 11562 11563 clone: function () { 11564 11565 return new this.constructor().copy( this ); 11566 11567 }, 11568 11569 copy: function ( source ) { 11570 11571 this.a = source.a; 11572 this.b = source.b; 11573 this.c = source.c; 11574 11575 this.normal.copy( source.normal ); 11576 this.color.copy( source.color ); 11577 11578 this.materialIndex = source.materialIndex; 11579 11580 for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { 11581 11582 this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); 11583 11584 } 11585 11586 for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { 11587 11588 this.vertexColors[ i ] = source.vertexColors[ i ].clone(); 11589 11590 } 11591 11592 return this; 11593 11594 } 11595 11596 }; 11597 11598 /** 11599 * @author mrdoob / http://mrdoob.com/ 11600 * @author alteredq / http://alteredqualia.com/ 11601 * 11602 * parameters = { 11603 * color: <hex>, 11604 * opacity: <float>, 11605 * map: new THREE.Texture( <Image> ), 11606 * 11607 * lightMap: new THREE.Texture( <Image> ), 11608 * lightMapIntensity: <float> 11609 * 11610 * aoMap: new THREE.Texture( <Image> ), 11611 * aoMapIntensity: <float> 11612 * 11613 * specularMap: new THREE.Texture( <Image> ), 11614 * 11615 * alphaMap: new THREE.Texture( <Image> ), 11616 * 11617 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), 11618 * combine: THREE.Multiply, 11619 * reflectivity: <float>, 11620 * refractionRatio: <float>, 11621 * 11622 * shading: THREE.SmoothShading, 11623 * depthTest: <bool>, 11624 * depthWrite: <bool>, 11625 * 11626 * wireframe: <boolean>, 11627 * wireframeLinewidth: <float>, 11628 * 11629 * skinning: <bool>, 11630 * morphTargets: <bool> 11631 * } 11632 */ 11633 11634 function MeshBasicMaterial( parameters ) { 11635 11636 Material.call( this ); 11637 11638 this.type = 'MeshBasicMaterial'; 11639 11640 this.color = new Color( 0xffffff ); // emissive 11641 11642 this.map = null; 11643 11644 this.lightMap = null; 11645 this.lightMapIntensity = 1.0; 11646 11647 this.aoMap = null; 11648 this.aoMapIntensity = 1.0; 11649 11650 this.specularMap = null; 11651 11652 this.alphaMap = null; 11653 11654 this.envMap = null; 11655 this.combine = MultiplyOperation; 11656 this.reflectivity = 1; 11657 this.refractionRatio = 0.98; 11658 11659 this.wireframe = false; 11660 this.wireframeLinewidth = 1; 11661 this.wireframeLinecap = 'round'; 11662 this.wireframeLinejoin = 'round'; 11663 11664 this.skinning = false; 11665 this.morphTargets = false; 11666 11667 this.lights = false; 11668 11669 this.setValues( parameters ); 11670 11671 } 11672 11673 MeshBasicMaterial.prototype = Object.create( Material.prototype ); 11674 MeshBasicMaterial.prototype.constructor = MeshBasicMaterial; 11675 11676 MeshBasicMaterial.prototype.isMeshBasicMaterial = true; 11677 11678 MeshBasicMaterial.prototype.copy = function ( source ) { 11679 11680 Material.prototype.copy.call( this, source ); 11681 11682 this.color.copy( source.color ); 11683 11684 this.map = source.map; 11685 11686 this.lightMap = source.lightMap; 11687 this.lightMapIntensity = source.lightMapIntensity; 11688 11689 this.aoMap = source.aoMap; 11690 this.aoMapIntensity = source.aoMapIntensity; 11691 11692 this.specularMap = source.specularMap; 11693 11694 this.alphaMap = source.alphaMap; 11695 11696 this.envMap = source.envMap; 11697 this.combine = source.combine; 11698 this.reflectivity = source.reflectivity; 11699 this.refractionRatio = source.refractionRatio; 11700 11701 this.wireframe = source.wireframe; 11702 this.wireframeLinewidth = source.wireframeLinewidth; 11703 this.wireframeLinecap = source.wireframeLinecap; 11704 this.wireframeLinejoin = source.wireframeLinejoin; 11705 11706 this.skinning = source.skinning; 11707 this.morphTargets = source.morphTargets; 11708 11709 return this; 11710 11711 }; 11712 11713 /** 11714 * @author mrdoob / http://mrdoob.com/ 11715 */ 11716 11717 function BufferAttribute( array, itemSize, normalized ) { 11718 11719 if ( Array.isArray( array ) ) { 11720 11721 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 11722 11723 } 11724 11725 this.uuid = _Math.generateUUID(); 11726 11727 this.array = array; 11728 this.itemSize = itemSize; 11729 this.count = array !== undefined ? array.length / itemSize : 0; 11730 this.normalized = normalized === true; 11731 11732 this.dynamic = false; 11733 this.updateRange = { offset: 0, count: - 1 }; 11734 11735 this.onUploadCallback = function () {}; 11736 11737 this.version = 0; 11738 11739 } 11740 11741 BufferAttribute.prototype = { 11742 11743 constructor: BufferAttribute, 11744 11745 isBufferAttribute: true, 11746 11747 set needsUpdate( value ) { 11748 11749 if ( value === true ) this.version ++; 11750 11751 }, 11752 11753 setArray: function ( array ) { 11754 11755 if ( Array.isArray( array ) ) { 11756 11757 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 11758 11759 } 11760 11761 this.count = array !== undefined ? array.length / this.itemSize : 0; 11762 this.array = array; 11763 11764 }, 11765 11766 setDynamic: function ( value ) { 11767 11768 this.dynamic = value; 11769 11770 return this; 11771 11772 }, 11773 11774 copy: function ( source ) { 11775 11776 this.array = new source.array.constructor( source.array ); 11777 this.itemSize = source.itemSize; 11778 this.count = source.count; 11779 this.normalized = source.normalized; 11780 11781 this.dynamic = source.dynamic; 11782 11783 return this; 11784 11785 }, 11786 11787 copyAt: function ( index1, attribute, index2 ) { 11788 11789 index1 *= this.itemSize; 11790 index2 *= attribute.itemSize; 11791 11792 for ( var i = 0, l = this.itemSize; i < l; i ++ ) { 11793 11794 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 11795 11796 } 11797 11798 return this; 11799 11800 }, 11801 11802 copyArray: function ( array ) { 11803 11804 this.array.set( array ); 11805 11806 return this; 11807 11808 }, 11809 11810 copyColorsArray: function ( colors ) { 11811 11812 var array = this.array, offset = 0; 11813 11814 for ( var i = 0, l = colors.length; i < l; i ++ ) { 11815 11816 var color = colors[ i ]; 11817 11818 if ( color === undefined ) { 11819 11820 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); 11821 color = new Color(); 11822 11823 } 11824 11825 array[ offset ++ ] = color.r; 11826 array[ offset ++ ] = color.g; 11827 array[ offset ++ ] = color.b; 11828 11829 } 11830 11831 return this; 11832 11833 }, 11834 11835 copyIndicesArray: function ( indices ) { 11836 11837 var array = this.array, offset = 0; 11838 11839 for ( var i = 0, l = indices.length; i < l; i ++ ) { 11840 11841 var index = indices[ i ]; 11842 11843 array[ offset ++ ] = index.a; 11844 array[ offset ++ ] = index.b; 11845 array[ offset ++ ] = index.c; 11846 11847 } 11848 11849 return this; 11850 11851 }, 11852 11853 copyVector2sArray: function ( vectors ) { 11854 11855 var array = this.array, offset = 0; 11856 11857 for ( var i = 0, l = vectors.length; i < l; i ++ ) { 11858 11859 var vector = vectors[ i ]; 11860 11861 if ( vector === undefined ) { 11862 11863 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); 11864 vector = new Vector2(); 11865 11866 } 11867 11868 array[ offset ++ ] = vector.x; 11869 array[ offset ++ ] = vector.y; 11870 11871 } 11872 11873 return this; 11874 11875 }, 11876 11877 copyVector3sArray: function ( vectors ) { 11878 11879 var array = this.array, offset = 0; 11880 11881 for ( var i = 0, l = vectors.length; i < l; i ++ ) { 11882 11883 var vector = vectors[ i ]; 11884 11885 if ( vector === undefined ) { 11886 11887 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); 11888 vector = new Vector3(); 11889 11890 } 11891 11892 array[ offset ++ ] = vector.x; 11893 array[ offset ++ ] = vector.y; 11894 array[ offset ++ ] = vector.z; 11895 11896 } 11897 11898 return this; 11899 11900 }, 11901 11902 copyVector4sArray: function ( vectors ) { 11903 11904 var array = this.array, offset = 0; 11905 11906 for ( var i = 0, l = vectors.length; i < l; i ++ ) { 11907 11908 var vector = vectors[ i ]; 11909 11910 if ( vector === undefined ) { 11911 11912 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); 11913 vector = new Vector4(); 11914 11915 } 11916 11917 array[ offset ++ ] = vector.x; 11918 array[ offset ++ ] = vector.y; 11919 array[ offset ++ ] = vector.z; 11920 array[ offset ++ ] = vector.w; 11921 11922 } 11923 11924 return this; 11925 11926 }, 11927 11928 set: function ( value, offset ) { 11929 11930 if ( offset === undefined ) offset = 0; 11931 11932 this.array.set( value, offset ); 11933 11934 return this; 11935 11936 }, 11937 11938 getX: function ( index ) { 11939 11940 return this.array[ index * this.itemSize ]; 11941 11942 }, 11943 11944 setX: function ( index, x ) { 11945 11946 this.array[ index * this.itemSize ] = x; 11947 11948 return this; 11949 11950 }, 11951 11952 getY: function ( index ) { 11953 11954 return this.array[ index * this.itemSize + 1 ]; 11955 11956 }, 11957 11958 setY: function ( index, y ) { 11959 11960 this.array[ index * this.itemSize + 1 ] = y; 11961 11962 return this; 11963 11964 }, 11965 11966 getZ: function ( index ) { 11967 11968 return this.array[ index * this.itemSize + 2 ]; 11969 11970 }, 11971 11972 setZ: function ( index, z ) { 11973 11974 this.array[ index * this.itemSize + 2 ] = z; 11975 11976 return this; 11977 11978 }, 11979 11980 getW: function ( index ) { 11981 11982 return this.array[ index * this.itemSize + 3 ]; 11983 11984 }, 11985 11986 setW: function ( index, w ) { 11987 11988 this.array[ index * this.itemSize + 3 ] = w; 11989 11990 return this; 11991 11992 }, 11993 11994 setXY: function ( index, x, y ) { 11995 11996 index *= this.itemSize; 11997 11998 this.array[ index + 0 ] = x; 11999 this.array[ index + 1 ] = y; 12000 12001 return this; 12002 12003 }, 12004 12005 setXYZ: function ( index, x, y, z ) { 12006 12007 index *= this.itemSize; 12008 12009 this.array[ index + 0 ] = x; 12010 this.array[ index + 1 ] = y; 12011 this.array[ index + 2 ] = z; 12012 12013 return this; 12014 12015 }, 12016 12017 setXYZW: function ( index, x, y, z, w ) { 12018 12019 index *= this.itemSize; 12020 12021 this.array[ index + 0 ] = x; 12022 this.array[ index + 1 ] = y; 12023 this.array[ index + 2 ] = z; 12024 this.array[ index + 3 ] = w; 12025 12026 return this; 12027 12028 }, 12029 12030 onUpload: function ( callback ) { 12031 12032 this.onUploadCallback = callback; 12033 12034 return this; 12035 12036 }, 12037 12038 clone: function () { 12039 12040 return new this.constructor( this.array, this.itemSize ).copy( this ); 12041 12042 } 12043 12044 }; 12045 12046 // 12047 12048 function Int8BufferAttribute( array, itemSize ) { 12049 12050 BufferAttribute.call( this, new Int8Array( array ), itemSize ); 12051 12052 } 12053 12054 Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12055 Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; 12056 12057 12058 function Uint8BufferAttribute( array, itemSize ) { 12059 12060 BufferAttribute.call( this, new Uint8Array( array ), itemSize ); 12061 12062 } 12063 12064 Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12065 Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; 12066 12067 12068 function Uint8ClampedBufferAttribute( array, itemSize ) { 12069 12070 BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize ); 12071 12072 } 12073 12074 Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12075 Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; 12076 12077 12078 function Int16BufferAttribute( array, itemSize ) { 12079 12080 BufferAttribute.call( this, new Int16Array( array ), itemSize ); 12081 12082 } 12083 12084 Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12085 Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; 12086 12087 12088 function Uint16BufferAttribute( array, itemSize ) { 12089 12090 BufferAttribute.call( this, new Uint16Array( array ), itemSize ); 12091 12092 } 12093 12094 Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12095 Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; 12096 12097 12098 function Int32BufferAttribute( array, itemSize ) { 12099 12100 BufferAttribute.call( this, new Int32Array( array ), itemSize ); 12101 12102 } 12103 12104 Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12105 Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; 12106 12107 12108 function Uint32BufferAttribute( array, itemSize ) { 12109 12110 BufferAttribute.call( this, new Uint32Array( array ), itemSize ); 12111 12112 } 12113 12114 Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12115 Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; 12116 12117 12118 function Float32BufferAttribute( array, itemSize ) { 12119 12120 BufferAttribute.call( this, new Float32Array( array ), itemSize ); 12121 12122 } 12123 12124 Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12125 Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; 12126 12127 12128 function Float64BufferAttribute( array, itemSize ) { 12129 12130 BufferAttribute.call( this, new Float64Array( array ), itemSize ); 12131 12132 } 12133 12134 Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 12135 Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; 12136 12137 /** 12138 * @author mrdoob / http://mrdoob.com/ 12139 */ 12140 12141 function DirectGeometry() { 12142 12143 this.indices = []; 12144 this.vertices = []; 12145 this.normals = []; 12146 this.colors = []; 12147 this.uvs = []; 12148 this.uvs2 = []; 12149 12150 this.groups = []; 12151 12152 this.morphTargets = {}; 12153 12154 this.skinWeights = []; 12155 this.skinIndices = []; 12156 12157 // this.lineDistances = []; 12158 12159 this.boundingBox = null; 12160 this.boundingSphere = null; 12161 12162 // update flags 12163 12164 this.verticesNeedUpdate = false; 12165 this.normalsNeedUpdate = false; 12166 this.colorsNeedUpdate = false; 12167 this.uvsNeedUpdate = false; 12168 this.groupsNeedUpdate = false; 12169 12170 } 12171 12172 Object.assign( DirectGeometry.prototype, { 12173 12174 computeGroups: function ( geometry ) { 12175 12176 var group; 12177 var groups = []; 12178 var materialIndex = undefined; 12179 12180 var faces = geometry.faces; 12181 12182 for ( var i = 0; i < faces.length; i ++ ) { 12183 12184 var face = faces[ i ]; 12185 12186 // materials 12187 12188 if ( face.materialIndex !== materialIndex ) { 12189 12190 materialIndex = face.materialIndex; 12191 12192 if ( group !== undefined ) { 12193 12194 group.count = ( i * 3 ) - group.start; 12195 groups.push( group ); 12196 12197 } 12198 12199 group = { 12200 start: i * 3, 12201 materialIndex: materialIndex 12202 }; 12203 12204 } 12205 12206 } 12207 12208 if ( group !== undefined ) { 12209 12210 group.count = ( i * 3 ) - group.start; 12211 groups.push( group ); 12212 12213 } 12214 12215 this.groups = groups; 12216 12217 }, 12218 12219 fromGeometry: function ( geometry ) { 12220 12221 var faces = geometry.faces; 12222 var vertices = geometry.vertices; 12223 var faceVertexUvs = geometry.faceVertexUvs; 12224 12225 var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; 12226 var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; 12227 12228 // morphs 12229 12230 var morphTargets = geometry.morphTargets; 12231 var morphTargetsLength = morphTargets.length; 12232 12233 var morphTargetsPosition; 12234 12235 if ( morphTargetsLength > 0 ) { 12236 12237 morphTargetsPosition = []; 12238 12239 for ( var i = 0; i < morphTargetsLength; i ++ ) { 12240 12241 morphTargetsPosition[ i ] = []; 12242 12243 } 12244 12245 this.morphTargets.position = morphTargetsPosition; 12246 12247 } 12248 12249 var morphNormals = geometry.morphNormals; 12250 var morphNormalsLength = morphNormals.length; 12251 12252 var morphTargetsNormal; 12253 12254 if ( morphNormalsLength > 0 ) { 12255 12256 morphTargetsNormal = []; 12257 12258 for ( var i = 0; i < morphNormalsLength; i ++ ) { 12259 12260 morphTargetsNormal[ i ] = []; 12261 12262 } 12263 12264 this.morphTargets.normal = morphTargetsNormal; 12265 12266 } 12267 12268 // skins 12269 12270 var skinIndices = geometry.skinIndices; 12271 var skinWeights = geometry.skinWeights; 12272 12273 var hasSkinIndices = skinIndices.length === vertices.length; 12274 var hasSkinWeights = skinWeights.length === vertices.length; 12275 12276 // 12277 12278 for ( var i = 0; i < faces.length; i ++ ) { 12279 12280 var face = faces[ i ]; 12281 12282 this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); 12283 12284 var vertexNormals = face.vertexNormals; 12285 12286 if ( vertexNormals.length === 3 ) { 12287 12288 this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); 12289 12290 } else { 12291 12292 var normal = face.normal; 12293 12294 this.normals.push( normal, normal, normal ); 12295 12296 } 12297 12298 var vertexColors = face.vertexColors; 12299 12300 if ( vertexColors.length === 3 ) { 12301 12302 this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); 12303 12304 } else { 12305 12306 var color = face.color; 12307 12308 this.colors.push( color, color, color ); 12309 12310 } 12311 12312 if ( hasFaceVertexUv === true ) { 12313 12314 var vertexUvs = faceVertexUvs[ 0 ][ i ]; 12315 12316 if ( vertexUvs !== undefined ) { 12317 12318 this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); 12319 12320 } else { 12321 12322 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); 12323 12324 this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); 12325 12326 } 12327 12328 } 12329 12330 if ( hasFaceVertexUv2 === true ) { 12331 12332 var vertexUvs = faceVertexUvs[ 1 ][ i ]; 12333 12334 if ( vertexUvs !== undefined ) { 12335 12336 this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); 12337 12338 } else { 12339 12340 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); 12341 12342 this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); 12343 12344 } 12345 12346 } 12347 12348 // morphs 12349 12350 for ( var j = 0; j < morphTargetsLength; j ++ ) { 12351 12352 var morphTarget = morphTargets[ j ].vertices; 12353 12354 morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); 12355 12356 } 12357 12358 for ( var j = 0; j < morphNormalsLength; j ++ ) { 12359 12360 var morphNormal = morphNormals[ j ].vertexNormals[ i ]; 12361 12362 morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); 12363 12364 } 12365 12366 // skins 12367 12368 if ( hasSkinIndices ) { 12369 12370 this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); 12371 12372 } 12373 12374 if ( hasSkinWeights ) { 12375 12376 this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); 12377 12378 } 12379 12380 } 12381 12382 this.computeGroups( geometry ); 12383 12384 this.verticesNeedUpdate = geometry.verticesNeedUpdate; 12385 this.normalsNeedUpdate = geometry.normalsNeedUpdate; 12386 this.colorsNeedUpdate = geometry.colorsNeedUpdate; 12387 this.uvsNeedUpdate = geometry.uvsNeedUpdate; 12388 this.groupsNeedUpdate = geometry.groupsNeedUpdate; 12389 12390 return this; 12391 12392 } 12393 12394 } ); 12395 12396 // http://stackoverflow.com/questions/1669190/javascript-min-max-array-values/13440842#13440842 12397 12398 function arrayMax( array ) { 12399 12400 var length = array.length, max = - Infinity; 12401 12402 while ( length -- ) { 12403 12404 if ( array[ length ] > max ) { 12405 12406 max = array[ length ]; 12407 12408 } 12409 12410 } 12411 12412 return max; 12413 12414 } 12415 12416 /** 12417 * @author mrdoob / http://mrdoob.com/ 12418 * @author kile / http://kile.stravaganza.org/ 12419 * @author alteredq / http://alteredqualia.com/ 12420 * @author mikael emtinger / http://gomo.se/ 12421 * @author zz85 / http://www.lab4games.net/zz85/blog 12422 * @author bhouston / http://clara.io 12423 */ 12424 12425 var count = 0; 12426 function GeometryIdCount() { return count++; } 12427 12428 function Geometry() { 12429 12430 Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); 12431 12432 this.uuid = _Math.generateUUID(); 12433 12434 this.name = ''; 12435 this.type = 'Geometry'; 12436 12437 this.vertices = []; 12438 this.colors = []; 12439 this.faces = []; 12440 this.faceVertexUvs = [[]]; 12441 12442 this.morphTargets = []; 12443 this.morphNormals = []; 12444 12445 this.skinWeights = []; 12446 this.skinIndices = []; 12447 12448 this.lineDistances = []; 12449 12450 this.boundingBox = null; 12451 this.boundingSphere = null; 12452 12453 // update flags 12454 12455 this.elementsNeedUpdate = false; 12456 this.verticesNeedUpdate = false; 12457 this.uvsNeedUpdate = false; 12458 this.normalsNeedUpdate = false; 12459 this.colorsNeedUpdate = false; 12460 this.lineDistancesNeedUpdate = false; 12461 this.groupsNeedUpdate = false; 12462 12463 } 12464 12465 Geometry.prototype = { 12466 12467 constructor: Geometry, 12468 12469 isGeometry: true, 12470 12471 applyMatrix: function ( matrix ) { 12472 12473 var normalMatrix = new Matrix3().getNormalMatrix( matrix ); 12474 12475 for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { 12476 12477 var vertex = this.vertices[ i ]; 12478 vertex.applyMatrix4( matrix ); 12479 12480 } 12481 12482 for ( var i = 0, il = this.faces.length; i < il; i ++ ) { 12483 12484 var face = this.faces[ i ]; 12485 face.normal.applyMatrix3( normalMatrix ).normalize(); 12486 12487 for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { 12488 12489 face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); 12490 12491 } 12492 12493 } 12494 12495 if ( this.boundingBox !== null ) { 12496 12497 this.computeBoundingBox(); 12498 12499 } 12500 12501 if ( this.boundingSphere !== null ) { 12502 12503 this.computeBoundingSphere(); 12504 12505 } 12506 12507 this.verticesNeedUpdate = true; 12508 this.normalsNeedUpdate = true; 12509 12510 return this; 12511 12512 }, 12513 12514 rotateX: function () { 12515 12516 // rotate geometry around world x-axis 12517 12518 var m1; 12519 12520 return function rotateX( angle ) { 12521 12522 if ( m1 === undefined ) m1 = new Matrix4(); 12523 12524 m1.makeRotationX( angle ); 12525 12526 this.applyMatrix( m1 ); 12527 12528 return this; 12529 12530 }; 12531 12532 }(), 12533 12534 rotateY: function () { 12535 12536 // rotate geometry around world y-axis 12537 12538 var m1; 12539 12540 return function rotateY( angle ) { 12541 12542 if ( m1 === undefined ) m1 = new Matrix4(); 12543 12544 m1.makeRotationY( angle ); 12545 12546 this.applyMatrix( m1 ); 12547 12548 return this; 12549 12550 }; 12551 12552 }(), 12553 12554 rotateZ: function () { 12555 12556 // rotate geometry around world z-axis 12557 12558 var m1; 12559 12560 return function rotateZ( angle ) { 12561 12562 if ( m1 === undefined ) m1 = new Matrix4(); 12563 12564 m1.makeRotationZ( angle ); 12565 12566 this.applyMatrix( m1 ); 12567 12568 return this; 12569 12570 }; 12571 12572 }(), 12573 12574 translate: function () { 12575 12576 // translate geometry 12577 12578 var m1; 12579 12580 return function translate( x, y, z ) { 12581 12582 if ( m1 === undefined ) m1 = new Matrix4(); 12583 12584 m1.makeTranslation( x, y, z ); 12585 12586 this.applyMatrix( m1 ); 12587 12588 return this; 12589 12590 }; 12591 12592 }(), 12593 12594 scale: function () { 12595 12596 // scale geometry 12597 12598 var m1; 12599 12600 return function scale( x, y, z ) { 12601 12602 if ( m1 === undefined ) m1 = new Matrix4(); 12603 12604 m1.makeScale( x, y, z ); 12605 12606 this.applyMatrix( m1 ); 12607 12608 return this; 12609 12610 }; 12611 12612 }(), 12613 12614 lookAt: function () { 12615 12616 var obj; 12617 12618 return function lookAt( vector ) { 12619 12620 if ( obj === undefined ) obj = new Object3D(); 12621 12622 obj.lookAt( vector ); 12623 12624 obj.updateMatrix(); 12625 12626 this.applyMatrix( obj.matrix ); 12627 12628 }; 12629 12630 }(), 12631 12632 fromBufferGeometry: function ( geometry ) { 12633 12634 var scope = this; 12635 12636 var indices = geometry.index !== null ? geometry.index.array : undefined; 12637 var attributes = geometry.attributes; 12638 12639 var positions = attributes.position.array; 12640 var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; 12641 var colors = attributes.color !== undefined ? attributes.color.array : undefined; 12642 var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; 12643 var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; 12644 12645 if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; 12646 12647 var tempNormals = []; 12648 var tempUVs = []; 12649 var tempUVs2 = []; 12650 12651 for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { 12652 12653 scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) ); 12654 12655 if ( normals !== undefined ) { 12656 12657 tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); 12658 12659 } 12660 12661 if ( colors !== undefined ) { 12662 12663 scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); 12664 12665 } 12666 12667 if ( uvs !== undefined ) { 12668 12669 tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) ); 12670 12671 } 12672 12673 if ( uvs2 !== undefined ) { 12674 12675 tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); 12676 12677 } 12678 12679 } 12680 12681 function addFace( a, b, c, materialIndex ) { 12682 12683 var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; 12684 var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; 12685 12686 var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); 12687 12688 scope.faces.push( face ); 12689 12690 if ( uvs !== undefined ) { 12691 12692 scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); 12693 12694 } 12695 12696 if ( uvs2 !== undefined ) { 12697 12698 scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); 12699 12700 } 12701 12702 } 12703 12704 if ( indices !== undefined ) { 12705 12706 var groups = geometry.groups; 12707 12708 if ( groups.length > 0 ) { 12709 12710 for ( var i = 0; i < groups.length; i ++ ) { 12711 12712 var group = groups[ i ]; 12713 12714 var start = group.start; 12715 var count = group.count; 12716 12717 for ( var j = start, jl = start + count; j < jl; j += 3 ) { 12718 12719 addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); 12720 12721 } 12722 12723 } 12724 12725 } else { 12726 12727 for ( var i = 0; i < indices.length; i += 3 ) { 12728 12729 addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); 12730 12731 } 12732 12733 } 12734 12735 } else { 12736 12737 for ( var i = 0; i < positions.length / 3; i += 3 ) { 12738 12739 addFace( i, i + 1, i + 2 ); 12740 12741 } 12742 12743 } 12744 12745 this.computeFaceNormals(); 12746 12747 if ( geometry.boundingBox !== null ) { 12748 12749 this.boundingBox = geometry.boundingBox.clone(); 12750 12751 } 12752 12753 if ( geometry.boundingSphere !== null ) { 12754 12755 this.boundingSphere = geometry.boundingSphere.clone(); 12756 12757 } 12758 12759 return this; 12760 12761 }, 12762 12763 center: function () { 12764 12765 this.computeBoundingBox(); 12766 12767 var offset = this.boundingBox.getCenter().negate(); 12768 12769 this.translate( offset.x, offset.y, offset.z ); 12770 12771 return offset; 12772 12773 }, 12774 12775 normalize: function () { 12776 12777 this.computeBoundingSphere(); 12778 12779 var center = this.boundingSphere.center; 12780 var radius = this.boundingSphere.radius; 12781 12782 var s = radius === 0 ? 1 : 1.0 / radius; 12783 12784 var matrix = new Matrix4(); 12785 matrix.set( 12786 s, 0, 0, - s * center.x, 12787 0, s, 0, - s * center.y, 12788 0, 0, s, - s * center.z, 12789 0, 0, 0, 1 12790 ); 12791 12792 this.applyMatrix( matrix ); 12793 12794 return this; 12795 12796 }, 12797 12798 computeFaceNormals: function () { 12799 12800 var cb = new Vector3(), ab = new Vector3(); 12801 12802 for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { 12803 12804 var face = this.faces[ f ]; 12805 12806 var vA = this.vertices[ face.a ]; 12807 var vB = this.vertices[ face.b ]; 12808 var vC = this.vertices[ face.c ]; 12809 12810 cb.subVectors( vC, vB ); 12811 ab.subVectors( vA, vB ); 12812 cb.cross( ab ); 12813 12814 cb.normalize(); 12815 12816 face.normal.copy( cb ); 12817 12818 } 12819 12820 }, 12821 12822 computeVertexNormals: function ( areaWeighted ) { 12823 12824 if ( areaWeighted === undefined ) areaWeighted = true; 12825 12826 var v, vl, f, fl, face, vertices; 12827 12828 vertices = new Array( this.vertices.length ); 12829 12830 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { 12831 12832 vertices[ v ] = new Vector3(); 12833 12834 } 12835 12836 if ( areaWeighted ) { 12837 12838 // vertex normals weighted by triangle areas 12839 // http://www.iquilezles.org/www/articles/normals/normals.htm 12840 12841 var vA, vB, vC; 12842 var cb = new Vector3(), ab = new Vector3(); 12843 12844 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 12845 12846 face = this.faces[ f ]; 12847 12848 vA = this.vertices[ face.a ]; 12849 vB = this.vertices[ face.b ]; 12850 vC = this.vertices[ face.c ]; 12851 12852 cb.subVectors( vC, vB ); 12853 ab.subVectors( vA, vB ); 12854 cb.cross( ab ); 12855 12856 vertices[ face.a ].add( cb ); 12857 vertices[ face.b ].add( cb ); 12858 vertices[ face.c ].add( cb ); 12859 12860 } 12861 12862 } else { 12863 12864 this.computeFaceNormals(); 12865 12866 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 12867 12868 face = this.faces[ f ]; 12869 12870 vertices[ face.a ].add( face.normal ); 12871 vertices[ face.b ].add( face.normal ); 12872 vertices[ face.c ].add( face.normal ); 12873 12874 } 12875 12876 } 12877 12878 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { 12879 12880 vertices[ v ].normalize(); 12881 12882 } 12883 12884 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 12885 12886 face = this.faces[ f ]; 12887 12888 var vertexNormals = face.vertexNormals; 12889 12890 if ( vertexNormals.length === 3 ) { 12891 12892 vertexNormals[ 0 ].copy( vertices[ face.a ] ); 12893 vertexNormals[ 1 ].copy( vertices[ face.b ] ); 12894 vertexNormals[ 2 ].copy( vertices[ face.c ] ); 12895 12896 } else { 12897 12898 vertexNormals[ 0 ] = vertices[ face.a ].clone(); 12899 vertexNormals[ 1 ] = vertices[ face.b ].clone(); 12900 vertexNormals[ 2 ] = vertices[ face.c ].clone(); 12901 12902 } 12903 12904 } 12905 12906 if ( this.faces.length > 0 ) { 12907 12908 this.normalsNeedUpdate = true; 12909 12910 } 12911 12912 }, 12913 12914 computeFlatVertexNormals: function () { 12915 12916 var f, fl, face; 12917 12918 this.computeFaceNormals(); 12919 12920 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 12921 12922 face = this.faces[ f ]; 12923 12924 var vertexNormals = face.vertexNormals; 12925 12926 if ( vertexNormals.length === 3 ) { 12927 12928 vertexNormals[ 0 ].copy( face.normal ); 12929 vertexNormals[ 1 ].copy( face.normal ); 12930 vertexNormals[ 2 ].copy( face.normal ); 12931 12932 } else { 12933 12934 vertexNormals[ 0 ] = face.normal.clone(); 12935 vertexNormals[ 1 ] = face.normal.clone(); 12936 vertexNormals[ 2 ] = face.normal.clone(); 12937 12938 } 12939 12940 } 12941 12942 if ( this.faces.length > 0 ) { 12943 12944 this.normalsNeedUpdate = true; 12945 12946 } 12947 12948 }, 12949 12950 computeMorphNormals: function () { 12951 12952 var i, il, f, fl, face; 12953 12954 // save original normals 12955 // - create temp variables on first access 12956 // otherwise just copy (for faster repeated calls) 12957 12958 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 12959 12960 face = this.faces[ f ]; 12961 12962 if ( ! face.__originalFaceNormal ) { 12963 12964 face.__originalFaceNormal = face.normal.clone(); 12965 12966 } else { 12967 12968 face.__originalFaceNormal.copy( face.normal ); 12969 12970 } 12971 12972 if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; 12973 12974 for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { 12975 12976 if ( ! face.__originalVertexNormals[ i ] ) { 12977 12978 face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); 12979 12980 } else { 12981 12982 face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); 12983 12984 } 12985 12986 } 12987 12988 } 12989 12990 // use temp geometry to compute face and vertex normals for each morph 12991 12992 var tmpGeo = new Geometry(); 12993 tmpGeo.faces = this.faces; 12994 12995 for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { 12996 12997 // create on first access 12998 12999 if ( ! this.morphNormals[ i ] ) { 13000 13001 this.morphNormals[ i ] = {}; 13002 this.morphNormals[ i ].faceNormals = []; 13003 this.morphNormals[ i ].vertexNormals = []; 13004 13005 var dstNormalsFace = this.morphNormals[ i ].faceNormals; 13006 var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; 13007 13008 var faceNormal, vertexNormals; 13009 13010 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 13011 13012 faceNormal = new Vector3(); 13013 vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; 13014 13015 dstNormalsFace.push( faceNormal ); 13016 dstNormalsVertex.push( vertexNormals ); 13017 13018 } 13019 13020 } 13021 13022 var morphNormals = this.morphNormals[ i ]; 13023 13024 // set vertices to morph target 13025 13026 tmpGeo.vertices = this.morphTargets[ i ].vertices; 13027 13028 // compute morph normals 13029 13030 tmpGeo.computeFaceNormals(); 13031 tmpGeo.computeVertexNormals(); 13032 13033 // store morph normals 13034 13035 var faceNormal, vertexNormals; 13036 13037 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 13038 13039 face = this.faces[ f ]; 13040 13041 faceNormal = morphNormals.faceNormals[ f ]; 13042 vertexNormals = morphNormals.vertexNormals[ f ]; 13043 13044 faceNormal.copy( face.normal ); 13045 13046 vertexNormals.a.copy( face.vertexNormals[ 0 ] ); 13047 vertexNormals.b.copy( face.vertexNormals[ 1 ] ); 13048 vertexNormals.c.copy( face.vertexNormals[ 2 ] ); 13049 13050 } 13051 13052 } 13053 13054 // restore original normals 13055 13056 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { 13057 13058 face = this.faces[ f ]; 13059 13060 face.normal = face.__originalFaceNormal; 13061 face.vertexNormals = face.__originalVertexNormals; 13062 13063 } 13064 13065 }, 13066 13067 computeLineDistances: function () { 13068 13069 var d = 0; 13070 var vertices = this.vertices; 13071 13072 for ( var i = 0, il = vertices.length; i < il; i ++ ) { 13073 13074 if ( i > 0 ) { 13075 13076 d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); 13077 13078 } 13079 13080 this.lineDistances[ i ] = d; 13081 13082 } 13083 13084 }, 13085 13086 computeBoundingBox: function () { 13087 13088 if ( this.boundingBox === null ) { 13089 13090 this.boundingBox = new Box3(); 13091 13092 } 13093 13094 this.boundingBox.setFromPoints( this.vertices ); 13095 13096 }, 13097 13098 computeBoundingSphere: function () { 13099 13100 if ( this.boundingSphere === null ) { 13101 13102 this.boundingSphere = new Sphere(); 13103 13104 } 13105 13106 this.boundingSphere.setFromPoints( this.vertices ); 13107 13108 }, 13109 13110 merge: function ( geometry, matrix, materialIndexOffset ) { 13111 13112 if ( ( geometry && geometry.isGeometry ) === false ) { 13113 13114 console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); 13115 return; 13116 13117 } 13118 13119 var normalMatrix, 13120 vertexOffset = this.vertices.length, 13121 vertices1 = this.vertices, 13122 vertices2 = geometry.vertices, 13123 faces1 = this.faces, 13124 faces2 = geometry.faces, 13125 uvs1 = this.faceVertexUvs[ 0 ], 13126 uvs2 = geometry.faceVertexUvs[ 0 ], 13127 colors1 = this.colors, 13128 colors2 = geometry.colors; 13129 13130 if ( materialIndexOffset === undefined ) materialIndexOffset = 0; 13131 13132 if ( matrix !== undefined ) { 13133 13134 normalMatrix = new Matrix3().getNormalMatrix( matrix ); 13135 13136 } 13137 13138 // vertices 13139 13140 for ( var i = 0, il = vertices2.length; i < il; i ++ ) { 13141 13142 var vertex = vertices2[ i ]; 13143 13144 var vertexCopy = vertex.clone(); 13145 13146 if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); 13147 13148 vertices1.push( vertexCopy ); 13149 13150 } 13151 13152 // colors 13153 13154 for ( var i = 0, il = colors2.length; i < il; i ++ ) { 13155 13156 colors1.push( colors2[ i ].clone() ); 13157 13158 } 13159 13160 // faces 13161 13162 for ( i = 0, il = faces2.length; i < il; i ++ ) { 13163 13164 var face = faces2[ i ], faceCopy, normal, color, 13165 faceVertexNormals = face.vertexNormals, 13166 faceVertexColors = face.vertexColors; 13167 13168 faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); 13169 faceCopy.normal.copy( face.normal ); 13170 13171 if ( normalMatrix !== undefined ) { 13172 13173 faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); 13174 13175 } 13176 13177 for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { 13178 13179 normal = faceVertexNormals[ j ].clone(); 13180 13181 if ( normalMatrix !== undefined ) { 13182 13183 normal.applyMatrix3( normalMatrix ).normalize(); 13184 13185 } 13186 13187 faceCopy.vertexNormals.push( normal ); 13188 13189 } 13190 13191 faceCopy.color.copy( face.color ); 13192 13193 for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { 13194 13195 color = faceVertexColors[ j ]; 13196 faceCopy.vertexColors.push( color.clone() ); 13197 13198 } 13199 13200 faceCopy.materialIndex = face.materialIndex + materialIndexOffset; 13201 13202 faces1.push( faceCopy ); 13203 13204 } 13205 13206 // uvs 13207 13208 for ( i = 0, il = uvs2.length; i < il; i ++ ) { 13209 13210 var uv = uvs2[ i ], uvCopy = []; 13211 13212 if ( uv === undefined ) { 13213 13214 continue; 13215 13216 } 13217 13218 for ( var j = 0, jl = uv.length; j < jl; j ++ ) { 13219 13220 uvCopy.push( uv[ j ].clone() ); 13221 13222 } 13223 13224 uvs1.push( uvCopy ); 13225 13226 } 13227 13228 }, 13229 13230 mergeMesh: function ( mesh ) { 13231 13232 if ( ( mesh && mesh.isMesh ) === false ) { 13233 13234 console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); 13235 return; 13236 13237 } 13238 13239 mesh.matrixAutoUpdate && mesh.updateMatrix(); 13240 13241 this.merge( mesh.geometry, mesh.matrix ); 13242 13243 }, 13244 13245 /* 13246 * Checks for duplicate vertices with hashmap. 13247 * Duplicated vertices are removed 13248 * and faces' vertices are updated. 13249 */ 13250 13251 mergeVertices: function () { 13252 13253 var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) 13254 var unique = [], changes = []; 13255 13256 var v, key; 13257 var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 13258 var precision = Math.pow( 10, precisionPoints ); 13259 var i, il, face; 13260 var indices, j, jl; 13261 13262 for ( i = 0, il = this.vertices.length; i < il; i ++ ) { 13263 13264 v = this.vertices[ i ]; 13265 key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); 13266 13267 if ( verticesMap[ key ] === undefined ) { 13268 13269 verticesMap[ key ] = i; 13270 unique.push( this.vertices[ i ] ); 13271 changes[ i ] = unique.length - 1; 13272 13273 } else { 13274 13275 //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); 13276 changes[ i ] = changes[ verticesMap[ key ] ]; 13277 13278 } 13279 13280 } 13281 13282 13283 // if faces are completely degenerate after merging vertices, we 13284 // have to remove them from the geometry. 13285 var faceIndicesToRemove = []; 13286 13287 for ( i = 0, il = this.faces.length; i < il; i ++ ) { 13288 13289 face = this.faces[ i ]; 13290 13291 face.a = changes[ face.a ]; 13292 face.b = changes[ face.b ]; 13293 face.c = changes[ face.c ]; 13294 13295 indices = [ face.a, face.b, face.c ]; 13296 13297 // if any duplicate vertices are found in a Face3 13298 // we have to remove the face as nothing can be saved 13299 for ( var n = 0; n < 3; n ++ ) { 13300 13301 if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { 13302 13303 faceIndicesToRemove.push( i ); 13304 break; 13305 13306 } 13307 13308 } 13309 13310 } 13311 13312 for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { 13313 13314 var idx = faceIndicesToRemove[ i ]; 13315 13316 this.faces.splice( idx, 1 ); 13317 13318 for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { 13319 13320 this.faceVertexUvs[ j ].splice( idx, 1 ); 13321 13322 } 13323 13324 } 13325 13326 // Use unique set of vertices 13327 13328 var diff = this.vertices.length - unique.length; 13329 this.vertices = unique; 13330 return diff; 13331 13332 }, 13333 13334 sortFacesByMaterialIndex: function () { 13335 13336 var faces = this.faces; 13337 var length = faces.length; 13338 13339 // tag faces 13340 13341 for ( var i = 0; i < length; i ++ ) { 13342 13343 faces[ i ]._id = i; 13344 13345 } 13346 13347 // sort faces 13348 13349 function materialIndexSort( a, b ) { 13350 13351 return a.materialIndex - b.materialIndex; 13352 13353 } 13354 13355 faces.sort( materialIndexSort ); 13356 13357 // sort uvs 13358 13359 var uvs1 = this.faceVertexUvs[ 0 ]; 13360 var uvs2 = this.faceVertexUvs[ 1 ]; 13361 13362 var newUvs1, newUvs2; 13363 13364 if ( uvs1 && uvs1.length === length ) newUvs1 = []; 13365 if ( uvs2 && uvs2.length === length ) newUvs2 = []; 13366 13367 for ( var i = 0; i < length; i ++ ) { 13368 13369 var id = faces[ i ]._id; 13370 13371 if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); 13372 if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); 13373 13374 } 13375 13376 if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; 13377 if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; 13378 13379 }, 13380 13381 toJSON: function () { 13382 13383 var data = { 13384 metadata: { 13385 version: 4.4, 13386 type: 'Geometry', 13387 generator: 'Geometry.toJSON' 13388 } 13389 }; 13390 13391 // standard Geometry serialization 13392 13393 data.uuid = this.uuid; 13394 data.type = this.type; 13395 if ( this.name !== '' ) data.name = this.name; 13396 13397 if ( this.parameters !== undefined ) { 13398 13399 var parameters = this.parameters; 13400 13401 for ( var key in parameters ) { 13402 13403 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; 13404 13405 } 13406 13407 return data; 13408 13409 } 13410 13411 var vertices = []; 13412 13413 for ( var i = 0; i < this.vertices.length; i ++ ) { 13414 13415 var vertex = this.vertices[ i ]; 13416 vertices.push( vertex.x, vertex.y, vertex.z ); 13417 13418 } 13419 13420 var faces = []; 13421 var normals = []; 13422 var normalsHash = {}; 13423 var colors = []; 13424 var colorsHash = {}; 13425 var uvs = []; 13426 var uvsHash = {}; 13427 13428 for ( var i = 0; i < this.faces.length; i ++ ) { 13429 13430 var face = this.faces[ i ]; 13431 13432 var hasMaterial = true; 13433 var hasFaceUv = false; // deprecated 13434 var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; 13435 var hasFaceNormal = face.normal.length() > 0; 13436 var hasFaceVertexNormal = face.vertexNormals.length > 0; 13437 var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; 13438 var hasFaceVertexColor = face.vertexColors.length > 0; 13439 13440 var faceType = 0; 13441 13442 faceType = setBit( faceType, 0, 0 ); // isQuad 13443 faceType = setBit( faceType, 1, hasMaterial ); 13444 faceType = setBit( faceType, 2, hasFaceUv ); 13445 faceType = setBit( faceType, 3, hasFaceVertexUv ); 13446 faceType = setBit( faceType, 4, hasFaceNormal ); 13447 faceType = setBit( faceType, 5, hasFaceVertexNormal ); 13448 faceType = setBit( faceType, 6, hasFaceColor ); 13449 faceType = setBit( faceType, 7, hasFaceVertexColor ); 13450 13451 faces.push( faceType ); 13452 faces.push( face.a, face.b, face.c ); 13453 faces.push( face.materialIndex ); 13454 13455 if ( hasFaceVertexUv ) { 13456 13457 var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; 13458 13459 faces.push( 13460 getUvIndex( faceVertexUvs[ 0 ] ), 13461 getUvIndex( faceVertexUvs[ 1 ] ), 13462 getUvIndex( faceVertexUvs[ 2 ] ) 13463 ); 13464 13465 } 13466 13467 if ( hasFaceNormal ) { 13468 13469 faces.push( getNormalIndex( face.normal ) ); 13470 13471 } 13472 13473 if ( hasFaceVertexNormal ) { 13474 13475 var vertexNormals = face.vertexNormals; 13476 13477 faces.push( 13478 getNormalIndex( vertexNormals[ 0 ] ), 13479 getNormalIndex( vertexNormals[ 1 ] ), 13480 getNormalIndex( vertexNormals[ 2 ] ) 13481 ); 13482 13483 } 13484 13485 if ( hasFaceColor ) { 13486 13487 faces.push( getColorIndex( face.color ) ); 13488 13489 } 13490 13491 if ( hasFaceVertexColor ) { 13492 13493 var vertexColors = face.vertexColors; 13494 13495 faces.push( 13496 getColorIndex( vertexColors[ 0 ] ), 13497 getColorIndex( vertexColors[ 1 ] ), 13498 getColorIndex( vertexColors[ 2 ] ) 13499 ); 13500 13501 } 13502 13503 } 13504 13505 function setBit( value, position, enabled ) { 13506 13507 return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); 13508 13509 } 13510 13511 function getNormalIndex( normal ) { 13512 13513 var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); 13514 13515 if ( normalsHash[ hash ] !== undefined ) { 13516 13517 return normalsHash[ hash ]; 13518 13519 } 13520 13521 normalsHash[ hash ] = normals.length / 3; 13522 normals.push( normal.x, normal.y, normal.z ); 13523 13524 return normalsHash[ hash ]; 13525 13526 } 13527 13528 function getColorIndex( color ) { 13529 13530 var hash = color.r.toString() + color.g.toString() + color.b.toString(); 13531 13532 if ( colorsHash[ hash ] !== undefined ) { 13533 13534 return colorsHash[ hash ]; 13535 13536 } 13537 13538 colorsHash[ hash ] = colors.length; 13539 colors.push( color.getHex() ); 13540 13541 return colorsHash[ hash ]; 13542 13543 } 13544 13545 function getUvIndex( uv ) { 13546 13547 var hash = uv.x.toString() + uv.y.toString(); 13548 13549 if ( uvsHash[ hash ] !== undefined ) { 13550 13551 return uvsHash[ hash ]; 13552 13553 } 13554 13555 uvsHash[ hash ] = uvs.length / 2; 13556 uvs.push( uv.x, uv.y ); 13557 13558 return uvsHash[ hash ]; 13559 13560 } 13561 13562 data.data = {}; 13563 13564 data.data.vertices = vertices; 13565 data.data.normals = normals; 13566 if ( colors.length > 0 ) data.data.colors = colors; 13567 if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility 13568 data.data.faces = faces; 13569 13570 return data; 13571 13572 }, 13573 13574 clone: function () { 13575 13576 /* 13577 // Handle primitives 13578 13579 var parameters = this.parameters; 13580 13581 if ( parameters !== undefined ) { 13582 13583 var values = []; 13584 13585 for ( var key in parameters ) { 13586 13587 values.push( parameters[ key ] ); 13588 13589 } 13590 13591 var geometry = Object.create( this.constructor.prototype ); 13592 this.constructor.apply( geometry, values ); 13593 return geometry; 13594 13595 } 13596 13597 return new this.constructor().copy( this ); 13598 */ 13599 13600 return new Geometry().copy( this ); 13601 13602 }, 13603 13604 copy: function ( source ) { 13605 13606 var i, il, j, jl, k, kl; 13607 13608 // reset 13609 13610 this.vertices = []; 13611 this.colors = []; 13612 this.faces = []; 13613 this.faceVertexUvs = [[]]; 13614 this.morphTargets = []; 13615 this.morphNormals = []; 13616 this.skinWeights = []; 13617 this.skinIndices = []; 13618 this.lineDistances = []; 13619 this.boundingBox = null; 13620 this.boundingSphere = null; 13621 13622 // name 13623 13624 this.name = source.name; 13625 13626 // vertices 13627 13628 var vertices = source.vertices; 13629 13630 for ( i = 0, il = vertices.length; i < il; i ++ ) { 13631 13632 this.vertices.push( vertices[ i ].clone() ); 13633 13634 } 13635 13636 // colors 13637 13638 var colors = source.colors; 13639 13640 for ( i = 0, il = colors.length; i < il; i ++ ) { 13641 13642 this.colors.push( colors[ i ].clone() ); 13643 13644 } 13645 13646 // faces 13647 13648 var faces = source.faces; 13649 13650 for ( i = 0, il = faces.length; i < il; i ++ ) { 13651 13652 this.faces.push( faces[ i ].clone() ); 13653 13654 } 13655 13656 // face vertex uvs 13657 13658 for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { 13659 13660 var faceVertexUvs = source.faceVertexUvs[ i ]; 13661 13662 if ( this.faceVertexUvs[ i ] === undefined ) { 13663 13664 this.faceVertexUvs[ i ] = []; 13665 13666 } 13667 13668 for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { 13669 13670 var uvs = faceVertexUvs[ j ], uvsCopy = []; 13671 13672 for ( k = 0, kl = uvs.length; k < kl; k ++ ) { 13673 13674 var uv = uvs[ k ]; 13675 13676 uvsCopy.push( uv.clone() ); 13677 13678 } 13679 13680 this.faceVertexUvs[ i ].push( uvsCopy ); 13681 13682 } 13683 13684 } 13685 13686 // morph targets 13687 13688 var morphTargets = source.morphTargets; 13689 13690 for ( i = 0, il = morphTargets.length; i < il; i ++ ) { 13691 13692 var morphTarget = {}; 13693 morphTarget.name = morphTargets[ i ].name; 13694 13695 // vertices 13696 13697 if ( morphTargets[ i ].vertices !== undefined ) { 13698 13699 morphTarget.vertices = []; 13700 13701 for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { 13702 13703 morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); 13704 13705 } 13706 13707 } 13708 13709 // normals 13710 13711 if ( morphTargets[ i ].normals !== undefined ) { 13712 13713 morphTarget.normals = []; 13714 13715 for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { 13716 13717 morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); 13718 13719 } 13720 13721 } 13722 13723 this.morphTargets.push( morphTarget ); 13724 13725 } 13726 13727 // morph normals 13728 13729 var morphNormals = source.morphNormals; 13730 13731 for ( i = 0, il = morphNormals.length; i < il; i ++ ) { 13732 13733 var morphNormal = {}; 13734 13735 // vertex normals 13736 13737 if ( morphNormals[ i ].vertexNormals !== undefined ) { 13738 13739 morphNormal.vertexNormals = []; 13740 13741 for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { 13742 13743 var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; 13744 var destVertexNormal = {}; 13745 13746 destVertexNormal.a = srcVertexNormal.a.clone(); 13747 destVertexNormal.b = srcVertexNormal.b.clone(); 13748 destVertexNormal.c = srcVertexNormal.c.clone(); 13749 13750 morphNormal.vertexNormals.push( destVertexNormal ); 13751 13752 } 13753 13754 } 13755 13756 // face normals 13757 13758 if ( morphNormals[ i ].faceNormals !== undefined ) { 13759 13760 morphNormal.faceNormals = []; 13761 13762 for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { 13763 13764 morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); 13765 13766 } 13767 13768 } 13769 13770 this.morphNormals.push( morphNormal ); 13771 13772 } 13773 13774 // skin weights 13775 13776 var skinWeights = source.skinWeights; 13777 13778 for ( i = 0, il = skinWeights.length; i < il; i ++ ) { 13779 13780 this.skinWeights.push( skinWeights[ i ].clone() ); 13781 13782 } 13783 13784 // skin indices 13785 13786 var skinIndices = source.skinIndices; 13787 13788 for ( i = 0, il = skinIndices.length; i < il; i ++ ) { 13789 13790 this.skinIndices.push( skinIndices[ i ].clone() ); 13791 13792 } 13793 13794 // line distances 13795 13796 var lineDistances = source.lineDistances; 13797 13798 for ( i = 0, il = lineDistances.length; i < il; i ++ ) { 13799 13800 this.lineDistances.push( lineDistances[ i ] ); 13801 13802 } 13803 13804 // bounding box 13805 13806 var boundingBox = source.boundingBox; 13807 13808 if ( boundingBox !== null ) { 13809 13810 this.boundingBox = boundingBox.clone(); 13811 13812 } 13813 13814 // bounding sphere 13815 13816 var boundingSphere = source.boundingSphere; 13817 13818 if ( boundingSphere !== null ) { 13819 13820 this.boundingSphere = boundingSphere.clone(); 13821 13822 } 13823 13824 // update flags 13825 13826 this.elementsNeedUpdate = source.elementsNeedUpdate; 13827 this.verticesNeedUpdate = source.verticesNeedUpdate; 13828 this.uvsNeedUpdate = source.uvsNeedUpdate; 13829 this.normalsNeedUpdate = source.normalsNeedUpdate; 13830 this.colorsNeedUpdate = source.colorsNeedUpdate; 13831 this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate; 13832 this.groupsNeedUpdate = source.groupsNeedUpdate; 13833 13834 return this; 13835 13836 }, 13837 13838 dispose: function () { 13839 13840 this.dispatchEvent( { type: 'dispose' } ); 13841 13842 } 13843 13844 }; 13845 13846 Object.assign( Geometry.prototype, EventDispatcher.prototype ); 13847 13848 /** 13849 * @author alteredq / http://alteredqualia.com/ 13850 * @author mrdoob / http://mrdoob.com/ 13851 */ 13852 13853 function BufferGeometry() { 13854 13855 Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); 13856 13857 this.uuid = _Math.generateUUID(); 13858 13859 this.name = ''; 13860 this.type = 'BufferGeometry'; 13861 13862 this.index = null; 13863 this.attributes = {}; 13864 13865 this.morphAttributes = {}; 13866 13867 this.groups = []; 13868 13869 this.boundingBox = null; 13870 this.boundingSphere = null; 13871 13872 this.drawRange = { start: 0, count: Infinity }; 13873 13874 } 13875 13876 BufferGeometry.prototype = { 13877 13878 constructor: BufferGeometry, 13879 13880 isBufferGeometry: true, 13881 13882 getIndex: function () { 13883 13884 return this.index; 13885 13886 }, 13887 13888 setIndex: function ( index ) { 13889 13890 if ( Array.isArray( index ) ) { 13891 13892 this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); 13893 13894 } else { 13895 13896 this.index = index; 13897 13898 } 13899 13900 }, 13901 13902 addAttribute: function ( name, attribute ) { 13903 13904 if ( ( attribute && attribute.isBufferAttribute ) === false && ( attribute && attribute.isInterleavedBufferAttribute ) === false ) { 13905 13906 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); 13907 13908 this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); 13909 13910 return; 13911 13912 } 13913 13914 if ( name === 'index' ) { 13915 13916 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); 13917 this.setIndex( attribute ); 13918 13919 return; 13920 13921 } 13922 13923 this.attributes[ name ] = attribute; 13924 13925 return this; 13926 13927 }, 13928 13929 getAttribute: function ( name ) { 13930 13931 return this.attributes[ name ]; 13932 13933 }, 13934 13935 removeAttribute: function ( name ) { 13936 13937 delete this.attributes[ name ]; 13938 13939 return this; 13940 13941 }, 13942 13943 addGroup: function ( start, count, materialIndex ) { 13944 13945 this.groups.push( { 13946 13947 start: start, 13948 count: count, 13949 materialIndex: materialIndex !== undefined ? materialIndex : 0 13950 13951 } ); 13952 13953 }, 13954 13955 clearGroups: function () { 13956 13957 this.groups = []; 13958 13959 }, 13960 13961 setDrawRange: function ( start, count ) { 13962 13963 this.drawRange.start = start; 13964 this.drawRange.count = count; 13965 13966 }, 13967 13968 applyMatrix: function ( matrix ) { 13969 13970 var position = this.attributes.position; 13971 13972 if ( position !== undefined ) { 13973 13974 matrix.applyToBufferAttribute( position ); 13975 position.needsUpdate = true; 13976 13977 } 13978 13979 var normal = this.attributes.normal; 13980 13981 if ( normal !== undefined ) { 13982 13983 var normalMatrix = new Matrix3().getNormalMatrix( matrix ); 13984 13985 normalMatrix.applyToBufferAttribute( normal ); 13986 normal.needsUpdate = true; 13987 13988 } 13989 13990 if ( this.boundingBox !== null ) { 13991 13992 this.computeBoundingBox(); 13993 13994 } 13995 13996 if ( this.boundingSphere !== null ) { 13997 13998 this.computeBoundingSphere(); 13999 14000 } 14001 14002 return this; 14003 14004 }, 14005 14006 rotateX: function () { 14007 14008 // rotate geometry around world x-axis 14009 14010 var m1; 14011 14012 return function rotateX( angle ) { 14013 14014 if ( m1 === undefined ) m1 = new Matrix4(); 14015 14016 m1.makeRotationX( angle ); 14017 14018 this.applyMatrix( m1 ); 14019 14020 return this; 14021 14022 }; 14023 14024 }(), 14025 14026 rotateY: function () { 14027 14028 // rotate geometry around world y-axis 14029 14030 var m1; 14031 14032 return function rotateY( angle ) { 14033 14034 if ( m1 === undefined ) m1 = new Matrix4(); 14035 14036 m1.makeRotationY( angle ); 14037 14038 this.applyMatrix( m1 ); 14039 14040 return this; 14041 14042 }; 14043 14044 }(), 14045 14046 rotateZ: function () { 14047 14048 // rotate geometry around world z-axis 14049 14050 var m1; 14051 14052 return function rotateZ( angle ) { 14053 14054 if ( m1 === undefined ) m1 = new Matrix4(); 14055 14056 m1.makeRotationZ( angle ); 14057 14058 this.applyMatrix( m1 ); 14059 14060 return this; 14061 14062 }; 14063 14064 }(), 14065 14066 translate: function () { 14067 14068 // translate geometry 14069 14070 var m1; 14071 14072 return function translate( x, y, z ) { 14073 14074 if ( m1 === undefined ) m1 = new Matrix4(); 14075 14076 m1.makeTranslation( x, y, z ); 14077 14078 this.applyMatrix( m1 ); 14079 14080 return this; 14081 14082 }; 14083 14084 }(), 14085 14086 scale: function () { 14087 14088 // scale geometry 14089 14090 var m1; 14091 14092 return function scale( x, y, z ) { 14093 14094 if ( m1 === undefined ) m1 = new Matrix4(); 14095 14096 m1.makeScale( x, y, z ); 14097 14098 this.applyMatrix( m1 ); 14099 14100 return this; 14101 14102 }; 14103 14104 }(), 14105 14106 lookAt: function () { 14107 14108 var obj; 14109 14110 return function lookAt( vector ) { 14111 14112 if ( obj === undefined ) obj = new Object3D(); 14113 14114 obj.lookAt( vector ); 14115 14116 obj.updateMatrix(); 14117 14118 this.applyMatrix( obj.matrix ); 14119 14120 }; 14121 14122 }(), 14123 14124 center: function () { 14125 14126 this.computeBoundingBox(); 14127 14128 var offset = this.boundingBox.getCenter().negate(); 14129 14130 this.translate( offset.x, offset.y, offset.z ); 14131 14132 return offset; 14133 14134 }, 14135 14136 setFromObject: function ( object ) { 14137 14138 // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); 14139 14140 var geometry = object.geometry; 14141 14142 if ( object.isPoints || object.isLine ) { 14143 14144 var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); 14145 var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); 14146 14147 this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); 14148 this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); 14149 14150 if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { 14151 14152 var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); 14153 14154 this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); 14155 14156 } 14157 14158 if ( geometry.boundingSphere !== null ) { 14159 14160 this.boundingSphere = geometry.boundingSphere.clone(); 14161 14162 } 14163 14164 if ( geometry.boundingBox !== null ) { 14165 14166 this.boundingBox = geometry.boundingBox.clone(); 14167 14168 } 14169 14170 } else if ( object.isMesh ) { 14171 14172 if ( geometry && geometry.isGeometry ) { 14173 14174 this.fromGeometry( geometry ); 14175 14176 } 14177 14178 } 14179 14180 return this; 14181 14182 }, 14183 14184 updateFromObject: function ( object ) { 14185 14186 var geometry = object.geometry; 14187 14188 if ( object.isMesh ) { 14189 14190 var direct = geometry.__directGeometry; 14191 14192 if ( geometry.elementsNeedUpdate === true ) { 14193 14194 direct = undefined; 14195 geometry.elementsNeedUpdate = false; 14196 14197 } 14198 14199 if ( direct === undefined ) { 14200 14201 return this.fromGeometry( geometry ); 14202 14203 } 14204 14205 direct.verticesNeedUpdate = geometry.verticesNeedUpdate; 14206 direct.normalsNeedUpdate = geometry.normalsNeedUpdate; 14207 direct.colorsNeedUpdate = geometry.colorsNeedUpdate; 14208 direct.uvsNeedUpdate = geometry.uvsNeedUpdate; 14209 direct.groupsNeedUpdate = geometry.groupsNeedUpdate; 14210 14211 geometry.verticesNeedUpdate = false; 14212 geometry.normalsNeedUpdate = false; 14213 geometry.colorsNeedUpdate = false; 14214 geometry.uvsNeedUpdate = false; 14215 geometry.groupsNeedUpdate = false; 14216 14217 geometry = direct; 14218 14219 } 14220 14221 var attribute; 14222 14223 if ( geometry.verticesNeedUpdate === true ) { 14224 14225 attribute = this.attributes.position; 14226 14227 if ( attribute !== undefined ) { 14228 14229 attribute.copyVector3sArray( geometry.vertices ); 14230 attribute.needsUpdate = true; 14231 14232 } 14233 14234 geometry.verticesNeedUpdate = false; 14235 14236 } 14237 14238 if ( geometry.normalsNeedUpdate === true ) { 14239 14240 attribute = this.attributes.normal; 14241 14242 if ( attribute !== undefined ) { 14243 14244 attribute.copyVector3sArray( geometry.normals ); 14245 attribute.needsUpdate = true; 14246 14247 } 14248 14249 geometry.normalsNeedUpdate = false; 14250 14251 } 14252 14253 if ( geometry.colorsNeedUpdate === true ) { 14254 14255 attribute = this.attributes.color; 14256 14257 if ( attribute !== undefined ) { 14258 14259 attribute.copyColorsArray( geometry.colors ); 14260 attribute.needsUpdate = true; 14261 14262 } 14263 14264 geometry.colorsNeedUpdate = false; 14265 14266 } 14267 14268 if ( geometry.uvsNeedUpdate ) { 14269 14270 attribute = this.attributes.uv; 14271 14272 if ( attribute !== undefined ) { 14273 14274 attribute.copyVector2sArray( geometry.uvs ); 14275 attribute.needsUpdate = true; 14276 14277 } 14278 14279 geometry.uvsNeedUpdate = false; 14280 14281 } 14282 14283 if ( geometry.lineDistancesNeedUpdate ) { 14284 14285 attribute = this.attributes.lineDistance; 14286 14287 if ( attribute !== undefined ) { 14288 14289 attribute.copyArray( geometry.lineDistances ); 14290 attribute.needsUpdate = true; 14291 14292 } 14293 14294 geometry.lineDistancesNeedUpdate = false; 14295 14296 } 14297 14298 if ( geometry.groupsNeedUpdate ) { 14299 14300 geometry.computeGroups( object.geometry ); 14301 this.groups = geometry.groups; 14302 14303 geometry.groupsNeedUpdate = false; 14304 14305 } 14306 14307 return this; 14308 14309 }, 14310 14311 fromGeometry: function ( geometry ) { 14312 14313 geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); 14314 14315 return this.fromDirectGeometry( geometry.__directGeometry ); 14316 14317 }, 14318 14319 fromDirectGeometry: function ( geometry ) { 14320 14321 var positions = new Float32Array( geometry.vertices.length * 3 ); 14322 this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); 14323 14324 if ( geometry.normals.length > 0 ) { 14325 14326 var normals = new Float32Array( geometry.normals.length * 3 ); 14327 this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); 14328 14329 } 14330 14331 if ( geometry.colors.length > 0 ) { 14332 14333 var colors = new Float32Array( geometry.colors.length * 3 ); 14334 this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); 14335 14336 } 14337 14338 if ( geometry.uvs.length > 0 ) { 14339 14340 var uvs = new Float32Array( geometry.uvs.length * 2 ); 14341 this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); 14342 14343 } 14344 14345 if ( geometry.uvs2.length > 0 ) { 14346 14347 var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); 14348 this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); 14349 14350 } 14351 14352 if ( geometry.indices.length > 0 ) { 14353 14354 var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array; 14355 var indices = new TypeArray( geometry.indices.length * 3 ); 14356 this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); 14357 14358 } 14359 14360 // groups 14361 14362 this.groups = geometry.groups; 14363 14364 // morphs 14365 14366 for ( var name in geometry.morphTargets ) { 14367 14368 var array = []; 14369 var morphTargets = geometry.morphTargets[ name ]; 14370 14371 for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { 14372 14373 var morphTarget = morphTargets[ i ]; 14374 14375 var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 ); 14376 14377 array.push( attribute.copyVector3sArray( morphTarget ) ); 14378 14379 } 14380 14381 this.morphAttributes[ name ] = array; 14382 14383 } 14384 14385 // skinning 14386 14387 if ( geometry.skinIndices.length > 0 ) { 14388 14389 var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); 14390 this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); 14391 14392 } 14393 14394 if ( geometry.skinWeights.length > 0 ) { 14395 14396 var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); 14397 this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); 14398 14399 } 14400 14401 // 14402 14403 if ( geometry.boundingSphere !== null ) { 14404 14405 this.boundingSphere = geometry.boundingSphere.clone(); 14406 14407 } 14408 14409 if ( geometry.boundingBox !== null ) { 14410 14411 this.boundingBox = geometry.boundingBox.clone(); 14412 14413 } 14414 14415 return this; 14416 14417 }, 14418 14419 computeBoundingBox: function () { 14420 14421 if ( this.boundingBox === null ) { 14422 14423 this.boundingBox = new Box3(); 14424 14425 } 14426 14427 var position = this.attributes.position; 14428 14429 if ( position !== undefined ) { 14430 14431 this.boundingBox.setFromBufferAttribute( position ); 14432 14433 } else { 14434 14435 this.boundingBox.makeEmpty(); 14436 14437 } 14438 14439 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { 14440 14441 console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); 14442 14443 } 14444 14445 }, 14446 14447 computeBoundingSphere: function () { 14448 14449 var box = new Box3(); 14450 var vector = new Vector3(); 14451 14452 return function computeBoundingSphere() { 14453 14454 if ( this.boundingSphere === null ) { 14455 14456 this.boundingSphere = new Sphere(); 14457 14458 } 14459 14460 var position = this.attributes.position; 14461 14462 if ( position ) { 14463 14464 var center = this.boundingSphere.center; 14465 14466 box.setFromBufferAttribute( position ); 14467 box.getCenter( center ); 14468 14469 // hoping to find a boundingSphere with a radius smaller than the 14470 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 14471 14472 var maxRadiusSq = 0; 14473 14474 for ( var i = 0, il = position.count; i < il; i ++ ) { 14475 14476 vector.x = position.getX( i ); 14477 vector.y = position.getY( i ); 14478 vector.z = position.getZ( i ); 14479 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); 14480 14481 } 14482 14483 this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); 14484 14485 if ( isNaN( this.boundingSphere.radius ) ) { 14486 14487 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); 14488 14489 } 14490 14491 } 14492 14493 }; 14494 14495 }(), 14496 14497 computeFaceNormals: function () { 14498 14499 // backwards compatibility 14500 14501 }, 14502 14503 computeVertexNormals: function () { 14504 14505 var index = this.index; 14506 var attributes = this.attributes; 14507 var groups = this.groups; 14508 14509 if ( attributes.position ) { 14510 14511 var positions = attributes.position.array; 14512 14513 if ( attributes.normal === undefined ) { 14514 14515 this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); 14516 14517 } else { 14518 14519 // reset existing normals to zero 14520 14521 var array = attributes.normal.array; 14522 14523 for ( var i = 0, il = array.length; i < il; i ++ ) { 14524 14525 array[ i ] = 0; 14526 14527 } 14528 14529 } 14530 14531 var normals = attributes.normal.array; 14532 14533 var vA, vB, vC; 14534 var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 14535 var cb = new Vector3(), ab = new Vector3(); 14536 14537 // indexed elements 14538 14539 if ( index ) { 14540 14541 var indices = index.array; 14542 14543 if ( groups.length === 0 ) { 14544 14545 this.addGroup( 0, indices.length ); 14546 14547 } 14548 14549 for ( var j = 0, jl = groups.length; j < jl; ++ j ) { 14550 14551 var group = groups[ j ]; 14552 14553 var start = group.start; 14554 var count = group.count; 14555 14556 for ( var i = start, il = start + count; i < il; i += 3 ) { 14557 14558 vA = indices[ i + 0 ] * 3; 14559 vB = indices[ i + 1 ] * 3; 14560 vC = indices[ i + 2 ] * 3; 14561 14562 pA.fromArray( positions, vA ); 14563 pB.fromArray( positions, vB ); 14564 pC.fromArray( positions, vC ); 14565 14566 cb.subVectors( pC, pB ); 14567 ab.subVectors( pA, pB ); 14568 cb.cross( ab ); 14569 14570 normals[ vA ] += cb.x; 14571 normals[ vA + 1 ] += cb.y; 14572 normals[ vA + 2 ] += cb.z; 14573 14574 normals[ vB ] += cb.x; 14575 normals[ vB + 1 ] += cb.y; 14576 normals[ vB + 2 ] += cb.z; 14577 14578 normals[ vC ] += cb.x; 14579 normals[ vC + 1 ] += cb.y; 14580 normals[ vC + 2 ] += cb.z; 14581 14582 } 14583 14584 } 14585 14586 } else { 14587 14588 // non-indexed elements (unconnected triangle soup) 14589 14590 for ( var i = 0, il = positions.length; i < il; i += 9 ) { 14591 14592 pA.fromArray( positions, i ); 14593 pB.fromArray( positions, i + 3 ); 14594 pC.fromArray( positions, i + 6 ); 14595 14596 cb.subVectors( pC, pB ); 14597 ab.subVectors( pA, pB ); 14598 cb.cross( ab ); 14599 14600 normals[ i ] = cb.x; 14601 normals[ i + 1 ] = cb.y; 14602 normals[ i + 2 ] = cb.z; 14603 14604 normals[ i + 3 ] = cb.x; 14605 normals[ i + 4 ] = cb.y; 14606 normals[ i + 5 ] = cb.z; 14607 14608 normals[ i + 6 ] = cb.x; 14609 normals[ i + 7 ] = cb.y; 14610 normals[ i + 8 ] = cb.z; 14611 14612 } 14613 14614 } 14615 14616 this.normalizeNormals(); 14617 14618 attributes.normal.needsUpdate = true; 14619 14620 } 14621 14622 }, 14623 14624 merge: function ( geometry, offset ) { 14625 14626 if ( ( geometry && geometry.isBufferGeometry ) === false ) { 14627 14628 console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); 14629 return; 14630 14631 } 14632 14633 if ( offset === undefined ) offset = 0; 14634 14635 var attributes = this.attributes; 14636 14637 for ( var key in attributes ) { 14638 14639 if ( geometry.attributes[ key ] === undefined ) continue; 14640 14641 var attribute1 = attributes[ key ]; 14642 var attributeArray1 = attribute1.array; 14643 14644 var attribute2 = geometry.attributes[ key ]; 14645 var attributeArray2 = attribute2.array; 14646 14647 var attributeSize = attribute2.itemSize; 14648 14649 for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { 14650 14651 attributeArray1[ j ] = attributeArray2[ i ]; 14652 14653 } 14654 14655 } 14656 14657 return this; 14658 14659 }, 14660 14661 normalizeNormals: function () { 14662 14663 var normals = this.attributes.normal.array; 14664 14665 var x, y, z, n; 14666 14667 for ( var i = 0, il = normals.length; i < il; i += 3 ) { 14668 14669 x = normals[ i ]; 14670 y = normals[ i + 1 ]; 14671 z = normals[ i + 2 ]; 14672 14673 n = 1.0 / Math.sqrt( x * x + y * y + z * z ); 14674 14675 normals[ i ] *= n; 14676 normals[ i + 1 ] *= n; 14677 normals[ i + 2 ] *= n; 14678 14679 } 14680 14681 }, 14682 14683 toNonIndexed: function () { 14684 14685 if ( this.index === null ) { 14686 14687 console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); 14688 return this; 14689 14690 } 14691 14692 var geometry2 = new BufferGeometry(); 14693 14694 var indices = this.index.array; 14695 var attributes = this.attributes; 14696 14697 for ( var name in attributes ) { 14698 14699 var attribute = attributes[ name ]; 14700 14701 var array = attribute.array; 14702 var itemSize = attribute.itemSize; 14703 14704 var array2 = new array.constructor( indices.length * itemSize ); 14705 14706 var index = 0, index2 = 0; 14707 14708 for ( var i = 0, l = indices.length; i < l; i ++ ) { 14709 14710 index = indices[ i ] * itemSize; 14711 14712 for ( var j = 0; j < itemSize; j ++ ) { 14713 14714 array2[ index2 ++ ] = array[ index ++ ]; 14715 14716 } 14717 14718 } 14719 14720 geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); 14721 14722 } 14723 14724 return geometry2; 14725 14726 }, 14727 14728 toJSON: function () { 14729 14730 var data = { 14731 metadata: { 14732 version: 4.4, 14733 type: 'BufferGeometry', 14734 generator: 'BufferGeometry.toJSON' 14735 } 14736 }; 14737 14738 // standard BufferGeometry serialization 14739 14740 data.uuid = this.uuid; 14741 data.type = this.type; 14742 if ( this.name !== '' ) data.name = this.name; 14743 14744 if ( this.parameters !== undefined ) { 14745 14746 var parameters = this.parameters; 14747 14748 for ( var key in parameters ) { 14749 14750 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; 14751 14752 } 14753 14754 return data; 14755 14756 } 14757 14758 data.data = { attributes: {} }; 14759 14760 var index = this.index; 14761 14762 if ( index !== null ) { 14763 14764 var array = Array.prototype.slice.call( index.array ); 14765 14766 data.data.index = { 14767 type: index.array.constructor.name, 14768 array: array 14769 }; 14770 14771 } 14772 14773 var attributes = this.attributes; 14774 14775 for ( var key in attributes ) { 14776 14777 var attribute = attributes[ key ]; 14778 14779 var array = Array.prototype.slice.call( attribute.array ); 14780 14781 data.data.attributes[ key ] = { 14782 itemSize: attribute.itemSize, 14783 type: attribute.array.constructor.name, 14784 array: array, 14785 normalized: attribute.normalized 14786 }; 14787 14788 } 14789 14790 var groups = this.groups; 14791 14792 if ( groups.length > 0 ) { 14793 14794 data.data.groups = JSON.parse( JSON.stringify( groups ) ); 14795 14796 } 14797 14798 var boundingSphere = this.boundingSphere; 14799 14800 if ( boundingSphere !== null ) { 14801 14802 data.data.boundingSphere = { 14803 center: boundingSphere.center.toArray(), 14804 radius: boundingSphere.radius 14805 }; 14806 14807 } 14808 14809 return data; 14810 14811 }, 14812 14813 clone: function () { 14814 14815 /* 14816 // Handle primitives 14817 14818 var parameters = this.parameters; 14819 14820 if ( parameters !== undefined ) { 14821 14822 var values = []; 14823 14824 for ( var key in parameters ) { 14825 14826 values.push( parameters[ key ] ); 14827 14828 } 14829 14830 var geometry = Object.create( this.constructor.prototype ); 14831 this.constructor.apply( geometry, values ); 14832 return geometry; 14833 14834 } 14835 14836 return new this.constructor().copy( this ); 14837 */ 14838 14839 return new BufferGeometry().copy( this ); 14840 14841 }, 14842 14843 copy: function ( source ) { 14844 14845 var name, i, l; 14846 14847 // reset 14848 14849 this.index = null; 14850 this.attributes = {}; 14851 this.morphAttributes = {}; 14852 this.groups = []; 14853 this.boundingBox = null; 14854 this.boundingSphere = null; 14855 14856 // name 14857 14858 this.name = source.name; 14859 14860 // index 14861 14862 var index = source.index; 14863 14864 if ( index !== null ) { 14865 14866 this.setIndex( index.clone() ); 14867 14868 } 14869 14870 // attributes 14871 14872 var attributes = source.attributes; 14873 14874 for ( name in attributes ) { 14875 14876 var attribute = attributes[ name ]; 14877 this.addAttribute( name, attribute.clone() ); 14878 14879 } 14880 14881 // morph attributes 14882 14883 var morphAttributes = source.morphAttributes; 14884 14885 for ( name in morphAttributes ) { 14886 14887 var array = []; 14888 var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 14889 14890 for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { 14891 14892 array.push( morphAttribute[ i ].clone() ); 14893 14894 } 14895 14896 this.morphAttributes[ name ] = array; 14897 14898 } 14899 14900 // groups 14901 14902 var groups = source.groups; 14903 14904 for ( i = 0, l = groups.length; i < l; i ++ ) { 14905 14906 var group = groups[ i ]; 14907 this.addGroup( group.start, group.count, group.materialIndex ); 14908 14909 } 14910 14911 // bounding box 14912 14913 var boundingBox = source.boundingBox; 14914 14915 if ( boundingBox !== null ) { 14916 14917 this.boundingBox = boundingBox.clone(); 14918 14919 } 14920 14921 // bounding sphere 14922 14923 var boundingSphere = source.boundingSphere; 14924 14925 if ( boundingSphere !== null ) { 14926 14927 this.boundingSphere = boundingSphere.clone(); 14928 14929 } 14930 14931 // draw range 14932 14933 this.drawRange.start = source.drawRange.start; 14934 this.drawRange.count = source.drawRange.count; 14935 14936 return this; 14937 14938 }, 14939 14940 dispose: function () { 14941 14942 this.dispatchEvent( { type: 'dispose' } ); 14943 14944 } 14945 14946 }; 14947 14948 BufferGeometry.MaxIndex = 65535; 14949 14950 Object.assign( BufferGeometry.prototype, EventDispatcher.prototype ); 14951 14952 /** 14953 * @author mrdoob / http://mrdoob.com/ 14954 * @author alteredq / http://alteredqualia.com/ 14955 * @author mikael emtinger / http://gomo.se/ 14956 * @author jonobr1 / http://jonobr1.com/ 14957 */ 14958 14959 function Mesh( geometry, material ) { 14960 14961 Object3D.call( this ); 14962 14963 this.type = 'Mesh'; 14964 14965 this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); 14966 this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); 14967 14968 this.drawMode = TrianglesDrawMode; 14969 14970 this.updateMorphTargets(); 14971 14972 } 14973 14974 Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { 14975 14976 constructor: Mesh, 14977 14978 isMesh: true, 14979 14980 setDrawMode: function ( value ) { 14981 14982 this.drawMode = value; 14983 14984 }, 14985 14986 copy: function ( source ) { 14987 14988 Object3D.prototype.copy.call( this, source ); 14989 14990 this.drawMode = source.drawMode; 14991 14992 return this; 14993 14994 }, 14995 14996 updateMorphTargets: function () { 14997 14998 var morphTargets = this.geometry.morphTargets; 14999 15000 if ( morphTargets !== undefined && morphTargets.length > 0 ) { 15001 15002 this.morphTargetInfluences = []; 15003 this.morphTargetDictionary = {}; 15004 15005 for ( var m = 0, ml = morphTargets.length; m < ml; m ++ ) { 15006 15007 this.morphTargetInfluences.push( 0 ); 15008 this.morphTargetDictionary[ morphTargets[ m ].name ] = m; 15009 15010 } 15011 15012 } 15013 15014 }, 15015 15016 raycast: ( function () { 15017 15018 var inverseMatrix = new Matrix4(); 15019 var ray = new Ray(); 15020 var sphere = new Sphere(); 15021 15022 var vA = new Vector3(); 15023 var vB = new Vector3(); 15024 var vC = new Vector3(); 15025 15026 var tempA = new Vector3(); 15027 var tempB = new Vector3(); 15028 var tempC = new Vector3(); 15029 15030 var uvA = new Vector2(); 15031 var uvB = new Vector2(); 15032 var uvC = new Vector2(); 15033 15034 var barycoord = new Vector3(); 15035 15036 var intersectionPoint = new Vector3(); 15037 var intersectionPointWorld = new Vector3(); 15038 15039 function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { 15040 15041 Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); 15042 15043 uv1.multiplyScalar( barycoord.x ); 15044 uv2.multiplyScalar( barycoord.y ); 15045 uv3.multiplyScalar( barycoord.z ); 15046 15047 uv1.add( uv2 ).add( uv3 ); 15048 15049 return uv1.clone(); 15050 15051 } 15052 15053 function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) { 15054 15055 var intersect; 15056 var material = object.material; 15057 15058 if ( material.side === BackSide ) { 15059 15060 intersect = ray.intersectTriangle( pC, pB, pA, true, point ); 15061 15062 } else { 15063 15064 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); 15065 15066 } 15067 15068 if ( intersect === null ) return null; 15069 15070 intersectionPointWorld.copy( point ); 15071 intersectionPointWorld.applyMatrix4( object.matrixWorld ); 15072 15073 var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); 15074 15075 if ( distance < raycaster.near || distance > raycaster.far ) return null; 15076 15077 return { 15078 distance: distance, 15079 point: intersectionPointWorld.clone(), 15080 object: object 15081 }; 15082 15083 } 15084 15085 function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) { 15086 15087 vA.fromBufferAttribute( position, a ); 15088 vB.fromBufferAttribute( position, b ); 15089 vC.fromBufferAttribute( position, c ); 15090 15091 var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint ); 15092 15093 if ( intersection ) { 15094 15095 if ( uv ) { 15096 15097 uvA.fromBufferAttribute( uv, a ); 15098 uvB.fromBufferAttribute( uv, b ); 15099 uvC.fromBufferAttribute( uv, c ); 15100 15101 intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); 15102 15103 } 15104 15105 intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) ); 15106 intersection.faceIndex = a; 15107 15108 } 15109 15110 return intersection; 15111 15112 } 15113 15114 return function raycast( raycaster, intersects ) { 15115 15116 var geometry = this.geometry; 15117 var material = this.material; 15118 var matrixWorld = this.matrixWorld; 15119 15120 if ( material === undefined ) return; 15121 15122 // Checking boundingSphere distance to ray 15123 15124 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 15125 15126 sphere.copy( geometry.boundingSphere ); 15127 sphere.applyMatrix4( matrixWorld ); 15128 15129 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; 15130 15131 // 15132 15133 inverseMatrix.getInverse( matrixWorld ); 15134 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); 15135 15136 // Check boundingBox before continuing 15137 15138 if ( geometry.boundingBox !== null ) { 15139 15140 if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; 15141 15142 } 15143 15144 var intersection; 15145 15146 if ( geometry.isBufferGeometry ) { 15147 15148 var a, b, c; 15149 var index = geometry.index; 15150 var position = geometry.attributes.position; 15151 var uv = geometry.attributes.uv; 15152 var i, l; 15153 15154 if ( index !== null ) { 15155 15156 // indexed buffer geometry 15157 15158 for ( i = 0, l = index.count; i < l; i += 3 ) { 15159 15160 a = index.getX( i ); 15161 b = index.getX( i + 1 ); 15162 c = index.getX( i + 2 ); 15163 15164 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); 15165 15166 if ( intersection ) { 15167 15168 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics 15169 intersects.push( intersection ); 15170 15171 } 15172 15173 } 15174 15175 } else { 15176 15177 // non-indexed buffer geometry 15178 15179 for ( i = 0, l = position.count; i < l; i += 3 ) { 15180 15181 a = i; 15182 b = i + 1; 15183 c = i + 2; 15184 15185 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); 15186 15187 if ( intersection ) { 15188 15189 intersection.index = a; // triangle number in positions buffer semantics 15190 intersects.push( intersection ); 15191 15192 } 15193 15194 } 15195 15196 } 15197 15198 } else if ( geometry.isGeometry ) { 15199 15200 var fvA, fvB, fvC; 15201 var isFaceMaterial = ( material && material.isMultiMaterial ); 15202 var materials = isFaceMaterial === true ? material.materials : null; 15203 15204 var vertices = geometry.vertices; 15205 var faces = geometry.faces; 15206 var uvs; 15207 15208 var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; 15209 if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; 15210 15211 for ( var f = 0, fl = faces.length; f < fl; f ++ ) { 15212 15213 var face = faces[ f ]; 15214 var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material; 15215 15216 if ( faceMaterial === undefined ) continue; 15217 15218 fvA = vertices[ face.a ]; 15219 fvB = vertices[ face.b ]; 15220 fvC = vertices[ face.c ]; 15221 15222 if ( faceMaterial.morphTargets === true ) { 15223 15224 var morphTargets = geometry.morphTargets; 15225 var morphInfluences = this.morphTargetInfluences; 15226 15227 vA.set( 0, 0, 0 ); 15228 vB.set( 0, 0, 0 ); 15229 vC.set( 0, 0, 0 ); 15230 15231 for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { 15232 15233 var influence = morphInfluences[ t ]; 15234 15235 if ( influence === 0 ) continue; 15236 15237 var targets = morphTargets[ t ].vertices; 15238 15239 vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); 15240 vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); 15241 vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); 15242 15243 } 15244 15245 vA.add( fvA ); 15246 vB.add( fvB ); 15247 vC.add( fvC ); 15248 15249 fvA = vA; 15250 fvB = vB; 15251 fvC = vC; 15252 15253 } 15254 15255 intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); 15256 15257 if ( intersection ) { 15258 15259 if ( uvs ) { 15260 15261 var uvs_f = uvs[ f ]; 15262 uvA.copy( uvs_f[ 0 ] ); 15263 uvB.copy( uvs_f[ 1 ] ); 15264 uvC.copy( uvs_f[ 2 ] ); 15265 15266 intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC ); 15267 15268 } 15269 15270 intersection.face = face; 15271 intersection.faceIndex = f; 15272 intersects.push( intersection ); 15273 15274 } 15275 15276 } 15277 15278 } 15279 15280 }; 15281 15282 }() ), 15283 15284 clone: function () { 15285 15286 return new this.constructor( this.geometry, this.material ).copy( this ); 15287 15288 } 15289 15290 } ); 15291 15292 /** 15293 * @author mrdoob / http://mrdoob.com/ 15294 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as 15295 */ 15296 15297 function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { 15298 15299 Geometry.call( this ); 15300 15301 this.type = 'BoxGeometry'; 15302 15303 this.parameters = { 15304 width: width, 15305 height: height, 15306 depth: depth, 15307 widthSegments: widthSegments, 15308 heightSegments: heightSegments, 15309 depthSegments: depthSegments 15310 }; 15311 15312 this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); 15313 this.mergeVertices(); 15314 15315 } 15316 15317 BoxGeometry.prototype = Object.create( Geometry.prototype ); 15318 BoxGeometry.prototype.constructor = BoxGeometry; 15319 15320 /** 15321 * @author Mugen87 / https://github.com/Mugen87 15322 */ 15323 15324 function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { 15325 15326 BufferGeometry.call( this ); 15327 15328 this.type = 'BoxBufferGeometry'; 15329 15330 this.parameters = { 15331 width: width, 15332 height: height, 15333 depth: depth, 15334 widthSegments: widthSegments, 15335 heightSegments: heightSegments, 15336 depthSegments: depthSegments 15337 }; 15338 15339 var scope = this; 15340 15341 // segments 15342 15343 widthSegments = Math.floor( widthSegments ) || 1; 15344 heightSegments = Math.floor( heightSegments ) || 1; 15345 depthSegments = Math.floor( depthSegments ) || 1; 15346 15347 // buffers 15348 15349 var indices = []; 15350 var vertices = []; 15351 var normals = []; 15352 var uvs = []; 15353 15354 // helper variables 15355 15356 var numberOfVertices = 0; 15357 var groupStart = 0; 15358 15359 // build each side of the box geometry 15360 15361 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px 15362 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx 15363 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py 15364 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny 15365 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz 15366 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz 15367 15368 // build geometry 15369 15370 this.setIndex( indices ); 15371 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 15372 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 15373 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 15374 15375 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { 15376 15377 var segmentWidth = width / gridX; 15378 var segmentHeight = height / gridY; 15379 15380 var widthHalf = width / 2; 15381 var heightHalf = height / 2; 15382 var depthHalf = depth / 2; 15383 15384 var gridX1 = gridX + 1; 15385 var gridY1 = gridY + 1; 15386 15387 var vertexCounter = 0; 15388 var groupCount = 0; 15389 15390 var ix, iy; 15391 15392 var vector = new Vector3(); 15393 15394 // generate vertices, normals and uvs 15395 15396 for ( iy = 0; iy < gridY1; iy ++ ) { 15397 15398 var y = iy * segmentHeight - heightHalf; 15399 15400 for ( ix = 0; ix < gridX1; ix ++ ) { 15401 15402 var x = ix * segmentWidth - widthHalf; 15403 15404 // set values to correct vector component 15405 15406 vector[ u ] = x * udir; 15407 vector[ v ] = y * vdir; 15408 vector[ w ] = depthHalf; 15409 15410 // now apply vector to vertex buffer 15411 15412 vertices.push( vector.x, vector.y, vector.z ); 15413 15414 // set values to correct vector component 15415 15416 vector[ u ] = 0; 15417 vector[ v ] = 0; 15418 vector[ w ] = depth > 0 ? 1 : - 1; 15419 15420 // now apply vector to normal buffer 15421 15422 normals.push( vector.x, vector.y, vector.z ); 15423 15424 // uvs 15425 15426 uvs.push( ix / gridX ); 15427 uvs.push( 1 - ( iy / gridY ) ); 15428 15429 // counters 15430 15431 vertexCounter += 1; 15432 15433 } 15434 15435 } 15436 15437 // indices 15438 15439 // 1. you need three indices to draw a single face 15440 // 2. a single segment consists of two faces 15441 // 3. so we need to generate six (2*3) indices per segment 15442 15443 for ( iy = 0; iy < gridY; iy ++ ) { 15444 15445 for ( ix = 0; ix < gridX; ix ++ ) { 15446 15447 var a = numberOfVertices + ix + gridX1 * iy; 15448 var b = numberOfVertices + ix + gridX1 * ( iy + 1 ); 15449 var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); 15450 var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; 15451 15452 // faces 15453 15454 indices.push( a, b, d ); 15455 indices.push( b, c, d ); 15456 15457 // increase counter 15458 15459 groupCount += 6; 15460 15461 } 15462 15463 } 15464 15465 // add a group to the geometry. this will ensure multi material support 15466 15467 scope.addGroup( groupStart, groupCount, materialIndex ); 15468 15469 // calculate new start value for groups 15470 15471 groupStart += groupCount; 15472 15473 // update total number of vertices 15474 15475 numberOfVertices += vertexCounter; 15476 15477 } 15478 15479 } 15480 15481 BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 15482 BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; 15483 15484 /** 15485 * @author mrdoob / http://mrdoob.com/ 15486 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as 15487 */ 15488 15489 function PlaneGeometry( width, height, widthSegments, heightSegments ) { 15490 15491 Geometry.call( this ); 15492 15493 this.type = 'PlaneGeometry'; 15494 15495 this.parameters = { 15496 width: width, 15497 height: height, 15498 widthSegments: widthSegments, 15499 heightSegments: heightSegments 15500 }; 15501 15502 this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); 15503 15504 } 15505 15506 PlaneGeometry.prototype = Object.create( Geometry.prototype ); 15507 PlaneGeometry.prototype.constructor = PlaneGeometry; 15508 15509 /** 15510 * @author mrdoob / http://mrdoob.com/ 15511 * @author Mugen87 / https://github.com/Mugen87 15512 * 15513 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as 15514 */ 15515 15516 function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { 15517 15518 BufferGeometry.call( this ); 15519 15520 this.type = 'PlaneBufferGeometry'; 15521 15522 this.parameters = { 15523 width: width, 15524 height: height, 15525 widthSegments: widthSegments, 15526 heightSegments: heightSegments 15527 }; 15528 15529 var width_half = width / 2; 15530 var height_half = height / 2; 15531 15532 var gridX = Math.floor( widthSegments ) || 1; 15533 var gridY = Math.floor( heightSegments ) || 1; 15534 15535 var gridX1 = gridX + 1; 15536 var gridY1 = gridY + 1; 15537 15538 var segment_width = width / gridX; 15539 var segment_height = height / gridY; 15540 15541 var ix, iy; 15542 15543 // buffers 15544 15545 var indices = []; 15546 var vertices = []; 15547 var normals = []; 15548 var uvs = []; 15549 15550 // generate vertices, normals and uvs 15551 15552 for ( iy = 0; iy < gridY1; iy ++ ) { 15553 15554 var y = iy * segment_height - height_half; 15555 15556 for ( ix = 0; ix < gridX1; ix ++ ) { 15557 15558 var x = ix * segment_width - width_half; 15559 15560 vertices.push( x, - y, 0 ); 15561 15562 normals.push( 0, 0, 1 ); 15563 15564 uvs.push( ix / gridX ); 15565 uvs.push( 1 - ( iy / gridY ) ); 15566 15567 } 15568 15569 } 15570 15571 // indices 15572 15573 for ( iy = 0; iy < gridY; iy ++ ) { 15574 15575 for ( ix = 0; ix < gridX; ix ++ ) { 15576 15577 var a = ix + gridX1 * iy; 15578 var b = ix + gridX1 * ( iy + 1 ); 15579 var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); 15580 var d = ( ix + 1 ) + gridX1 * iy; 15581 15582 // faces 15583 15584 indices.push( a, b, d ); 15585 indices.push( b, c, d ); 15586 15587 } 15588 15589 } 15590 15591 // build geometry 15592 15593 this.setIndex( indices ); 15594 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 15595 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 15596 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 15597 15598 } 15599 15600 PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 15601 PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; 15602 15603 /** 15604 * @author mrdoob / http://mrdoob.com/ 15605 * @author mikael emtinger / http://gomo.se/ 15606 * @author WestLangley / http://github.com/WestLangley 15607 */ 15608 15609 function Camera() { 15610 15611 Object3D.call( this ); 15612 15613 this.type = 'Camera'; 15614 15615 this.matrixWorldInverse = new Matrix4(); 15616 this.projectionMatrix = new Matrix4(); 15617 15618 } 15619 15620 Camera.prototype = Object.create( Object3D.prototype ); 15621 Camera.prototype.constructor = Camera; 15622 15623 Camera.prototype.isCamera = true; 15624 15625 Camera.prototype.getWorldDirection = function () { 15626 15627 var quaternion = new Quaternion(); 15628 15629 return function getWorldDirection( optionalTarget ) { 15630 15631 var result = optionalTarget || new Vector3(); 15632 15633 this.getWorldQuaternion( quaternion ); 15634 15635 return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); 15636 15637 }; 15638 15639 }(); 15640 15641 Camera.prototype.lookAt = function () { 15642 15643 // This routine does not support cameras with rotated and/or translated parent(s) 15644 15645 var m1 = new Matrix4(); 15646 15647 return function lookAt( vector ) { 15648 15649 m1.lookAt( this.position, vector, this.up ); 15650 15651 this.quaternion.setFromRotationMatrix( m1 ); 15652 15653 }; 15654 15655 }(); 15656 15657 Camera.prototype.clone = function () { 15658 15659 return new this.constructor().copy( this ); 15660 15661 }; 15662 15663 Camera.prototype.copy = function ( source ) { 15664 15665 Object3D.prototype.copy.call( this, source ); 15666 15667 this.matrixWorldInverse.copy( source.matrixWorldInverse ); 15668 this.projectionMatrix.copy( source.projectionMatrix ); 15669 15670 return this; 15671 15672 }; 15673 15674 /** 15675 * @author mrdoob / http://mrdoob.com/ 15676 * @author greggman / http://games.greggman.com/ 15677 * @author zz85 / http://www.lab4games.net/zz85/blog 15678 * @author tschw 15679 */ 15680 15681 function PerspectiveCamera( fov, aspect, near, far ) { 15682 15683 Camera.call( this ); 15684 15685 this.type = 'PerspectiveCamera'; 15686 15687 this.fov = fov !== undefined ? fov : 50; 15688 this.zoom = 1; 15689 15690 this.near = near !== undefined ? near : 0.1; 15691 this.far = far !== undefined ? far : 2000; 15692 this.focus = 10; 15693 15694 this.aspect = aspect !== undefined ? aspect : 1; 15695 this.view = null; 15696 15697 this.filmGauge = 35; // width of the film (default in millimeters) 15698 this.filmOffset = 0; // horizontal film offset (same unit as gauge) 15699 15700 this.updateProjectionMatrix(); 15701 15702 } 15703 15704 PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { 15705 15706 constructor: PerspectiveCamera, 15707 15708 isPerspectiveCamera: true, 15709 15710 copy: function ( source ) { 15711 15712 Camera.prototype.copy.call( this, source ); 15713 15714 this.fov = source.fov; 15715 this.zoom = source.zoom; 15716 15717 this.near = source.near; 15718 this.far = source.far; 15719 this.focus = source.focus; 15720 15721 this.aspect = source.aspect; 15722 this.view = source.view === null ? null : Object.assign( {}, source.view ); 15723 15724 this.filmGauge = source.filmGauge; 15725 this.filmOffset = source.filmOffset; 15726 15727 return this; 15728 15729 }, 15730 15731 /** 15732 * Sets the FOV by focal length in respect to the current .filmGauge. 15733 * 15734 * The default film gauge is 35, so that the focal length can be specified for 15735 * a 35mm (full frame) camera. 15736 * 15737 * Values for focal length and film gauge must have the same unit. 15738 */ 15739 setFocalLength: function ( focalLength ) { 15740 15741 // see http://www.bobatkins.com/photography/technical/field_of_view.html 15742 var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; 15743 15744 this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); 15745 this.updateProjectionMatrix(); 15746 15747 }, 15748 15749 /** 15750 * Calculates the focal length from the current .fov and .filmGauge. 15751 */ 15752 getFocalLength: function () { 15753 15754 var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); 15755 15756 return 0.5 * this.getFilmHeight() / vExtentSlope; 15757 15758 }, 15759 15760 getEffectiveFOV: function () { 15761 15762 return _Math.RAD2DEG * 2 * Math.atan( 15763 Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); 15764 15765 }, 15766 15767 getFilmWidth: function () { 15768 15769 // film not completely covered in portrait format (aspect < 1) 15770 return this.filmGauge * Math.min( this.aspect, 1 ); 15771 15772 }, 15773 15774 getFilmHeight: function () { 15775 15776 // film not completely covered in landscape format (aspect > 1) 15777 return this.filmGauge / Math.max( this.aspect, 1 ); 15778 15779 }, 15780 15781 /** 15782 * Sets an offset in a larger frustum. This is useful for multi-window or 15783 * multi-monitor/multi-machine setups. 15784 * 15785 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and 15786 * the monitors are in grid like this 15787 * 15788 * +---+---+---+ 15789 * | A | B | C | 15790 * +---+---+---+ 15791 * | D | E | F | 15792 * +---+---+---+ 15793 * 15794 * then for each monitor you would call it like this 15795 * 15796 * var w = 1920; 15797 * var h = 1080; 15798 * var fullWidth = w * 3; 15799 * var fullHeight = h * 2; 15800 * 15801 * --A-- 15802 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); 15803 * --B-- 15804 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); 15805 * --C-- 15806 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); 15807 * --D-- 15808 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); 15809 * --E-- 15810 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); 15811 * --F-- 15812 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); 15813 * 15814 * Note there is no reason monitors have to be the same size or in a grid. 15815 */ 15816 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { 15817 15818 this.aspect = fullWidth / fullHeight; 15819 15820 this.view = { 15821 fullWidth: fullWidth, 15822 fullHeight: fullHeight, 15823 offsetX: x, 15824 offsetY: y, 15825 width: width, 15826 height: height 15827 }; 15828 15829 this.updateProjectionMatrix(); 15830 15831 }, 15832 15833 clearViewOffset: function() { 15834 15835 this.view = null; 15836 this.updateProjectionMatrix(); 15837 15838 }, 15839 15840 updateProjectionMatrix: function () { 15841 15842 var near = this.near, 15843 top = near * Math.tan( 15844 _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom, 15845 height = 2 * top, 15846 width = this.aspect * height, 15847 left = - 0.5 * width, 15848 view = this.view; 15849 15850 if ( view !== null ) { 15851 15852 var fullWidth = view.fullWidth, 15853 fullHeight = view.fullHeight; 15854 15855 left += view.offsetX * width / fullWidth; 15856 top -= view.offsetY * height / fullHeight; 15857 width *= view.width / fullWidth; 15858 height *= view.height / fullHeight; 15859 15860 } 15861 15862 var skew = this.filmOffset; 15863 if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); 15864 15865 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); 15866 15867 }, 15868 15869 toJSON: function ( meta ) { 15870 15871 var data = Object3D.prototype.toJSON.call( this, meta ); 15872 15873 data.object.fov = this.fov; 15874 data.object.zoom = this.zoom; 15875 15876 data.object.near = this.near; 15877 data.object.far = this.far; 15878 data.object.focus = this.focus; 15879 15880 data.object.aspect = this.aspect; 15881 15882 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 15883 15884 data.object.filmGauge = this.filmGauge; 15885 data.object.filmOffset = this.filmOffset; 15886 15887 return data; 15888 15889 } 15890 15891 } ); 15892 15893 /** 15894 * @author alteredq / http://alteredqualia.com/ 15895 * @author arose / http://github.com/arose 15896 */ 15897 15898 function OrthographicCamera( left, right, top, bottom, near, far ) { 15899 15900 Camera.call( this ); 15901 15902 this.type = 'OrthographicCamera'; 15903 15904 this.zoom = 1; 15905 this.view = null; 15906 15907 this.left = left; 15908 this.right = right; 15909 this.top = top; 15910 this.bottom = bottom; 15911 15912 this.near = ( near !== undefined ) ? near : 0.1; 15913 this.far = ( far !== undefined ) ? far : 2000; 15914 15915 this.updateProjectionMatrix(); 15916 15917 } 15918 15919 OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { 15920 15921 constructor: OrthographicCamera, 15922 15923 isOrthographicCamera: true, 15924 15925 copy: function ( source ) { 15926 15927 Camera.prototype.copy.call( this, source ); 15928 15929 this.left = source.left; 15930 this.right = source.right; 15931 this.top = source.top; 15932 this.bottom = source.bottom; 15933 this.near = source.near; 15934 this.far = source.far; 15935 15936 this.zoom = source.zoom; 15937 this.view = source.view === null ? null : Object.assign( {}, source.view ); 15938 15939 return this; 15940 15941 }, 15942 15943 setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) { 15944 15945 this.view = { 15946 fullWidth: fullWidth, 15947 fullHeight: fullHeight, 15948 offsetX: x, 15949 offsetY: y, 15950 width: width, 15951 height: height 15952 }; 15953 15954 this.updateProjectionMatrix(); 15955 15956 }, 15957 15958 clearViewOffset: function() { 15959 15960 this.view = null; 15961 this.updateProjectionMatrix(); 15962 15963 }, 15964 15965 updateProjectionMatrix: function () { 15966 15967 var dx = ( this.right - this.left ) / ( 2 * this.zoom ); 15968 var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); 15969 var cx = ( this.right + this.left ) / 2; 15970 var cy = ( this.top + this.bottom ) / 2; 15971 15972 var left = cx - dx; 15973 var right = cx + dx; 15974 var top = cy + dy; 15975 var bottom = cy - dy; 15976 15977 if ( this.view !== null ) { 15978 15979 var zoomW = this.zoom / ( this.view.width / this.view.fullWidth ); 15980 var zoomH = this.zoom / ( this.view.height / this.view.fullHeight ); 15981 var scaleW = ( this.right - this.left ) / this.view.width; 15982 var scaleH = ( this.top - this.bottom ) / this.view.height; 15983 15984 left += scaleW * ( this.view.offsetX / zoomW ); 15985 right = left + scaleW * ( this.view.width / zoomW ); 15986 top -= scaleH * ( this.view.offsetY / zoomH ); 15987 bottom = top - scaleH * ( this.view.height / zoomH ); 15988 15989 } 15990 15991 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); 15992 15993 }, 15994 15995 toJSON: function ( meta ) { 15996 15997 var data = Object3D.prototype.toJSON.call( this, meta ); 15998 15999 data.object.zoom = this.zoom; 16000 data.object.left = this.left; 16001 data.object.right = this.right; 16002 data.object.top = this.top; 16003 data.object.bottom = this.bottom; 16004 data.object.near = this.near; 16005 data.object.far = this.far; 16006 16007 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 16008 16009 return data; 16010 16011 } 16012 16013 } ); 16014 16015 /** 16016 * @author mrdoob / http://mrdoob.com/ 16017 */ 16018 16019 function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) { 16020 16021 var mode; 16022 16023 function setMode( value ) { 16024 16025 mode = value; 16026 16027 } 16028 16029 var type, size; 16030 16031 function setIndex( index ) { 16032 16033 if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { 16034 16035 type = gl.UNSIGNED_INT; 16036 size = 4; 16037 16038 } else if ( index.array instanceof Uint16Array ) { 16039 16040 type = gl.UNSIGNED_SHORT; 16041 size = 2; 16042 16043 } else { 16044 16045 type = gl.UNSIGNED_BYTE; 16046 size = 1; 16047 16048 } 16049 16050 } 16051 16052 function render( start, count ) { 16053 16054 gl.drawElements( mode, count, type, start * size ); 16055 16056 infoRender.calls ++; 16057 infoRender.vertices += count; 16058 16059 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; 16060 16061 } 16062 16063 function renderInstances( geometry, start, count ) { 16064 16065 var extension = extensions.get( 'ANGLE_instanced_arrays' ); 16066 16067 if ( extension === null ) { 16068 16069 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); 16070 return; 16071 16072 } 16073 16074 extension.drawElementsInstancedANGLE( mode, count, type, start * size, geometry.maxInstancedCount ); 16075 16076 infoRender.calls ++; 16077 infoRender.vertices += count * geometry.maxInstancedCount; 16078 16079 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; 16080 16081 } 16082 16083 return { 16084 16085 setMode: setMode, 16086 setIndex: setIndex, 16087 render: render, 16088 renderInstances: renderInstances 16089 16090 }; 16091 16092 } 16093 16094 /** 16095 * @author mrdoob / http://mrdoob.com/ 16096 */ 16097 16098 function WebGLBufferRenderer( gl, extensions, infoRender ) { 16099 16100 var mode; 16101 16102 function setMode( value ) { 16103 16104 mode = value; 16105 16106 } 16107 16108 function render( start, count ) { 16109 16110 gl.drawArrays( mode, start, count ); 16111 16112 infoRender.calls ++; 16113 infoRender.vertices += count; 16114 16115 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; 16116 16117 } 16118 16119 function renderInstances( geometry ) { 16120 16121 var extension = extensions.get( 'ANGLE_instanced_arrays' ); 16122 16123 if ( extension === null ) { 16124 16125 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); 16126 return; 16127 16128 } 16129 16130 var position = geometry.attributes.position; 16131 16132 var count = 0; 16133 16134 if ( position.isInterleavedBufferAttribute ) { 16135 16136 count = position.data.count; 16137 16138 extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); 16139 16140 } else { 16141 16142 count = position.count; 16143 16144 extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); 16145 16146 } 16147 16148 infoRender.calls ++; 16149 infoRender.vertices += count * geometry.maxInstancedCount; 16150 16151 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; 16152 16153 } 16154 16155 return { 16156 setMode: setMode, 16157 render: render, 16158 renderInstances: renderInstances 16159 }; 16160 16161 } 16162 16163 /** 16164 * @author mrdoob / http://mrdoob.com/ 16165 */ 16166 16167 function WebGLLights() { 16168 16169 var lights = {}; 16170 16171 return { 16172 16173 get: function ( light ) { 16174 16175 if ( lights[ light.id ] !== undefined ) { 16176 16177 return lights[ light.id ]; 16178 16179 } 16180 16181 var uniforms; 16182 16183 switch ( light.type ) { 16184 16185 case 'DirectionalLight': 16186 uniforms = { 16187 direction: new Vector3(), 16188 color: new Color(), 16189 16190 shadow: false, 16191 shadowBias: 0, 16192 shadowRadius: 1, 16193 shadowMapSize: new Vector2() 16194 }; 16195 break; 16196 16197 case 'SpotLight': 16198 uniforms = { 16199 position: new Vector3(), 16200 direction: new Vector3(), 16201 color: new Color(), 16202 distance: 0, 16203 coneCos: 0, 16204 penumbraCos: 0, 16205 decay: 0, 16206 16207 shadow: false, 16208 shadowBias: 0, 16209 shadowRadius: 1, 16210 shadowMapSize: new Vector2() 16211 }; 16212 break; 16213 16214 case 'PointLight': 16215 uniforms = { 16216 position: new Vector3(), 16217 color: new Color(), 16218 distance: 0, 16219 decay: 0, 16220 16221 shadow: false, 16222 shadowBias: 0, 16223 shadowRadius: 1, 16224 shadowMapSize: new Vector2() 16225 }; 16226 break; 16227 16228 case 'HemisphereLight': 16229 uniforms = { 16230 direction: new Vector3(), 16231 skyColor: new Color(), 16232 groundColor: new Color() 16233 }; 16234 break; 16235 16236 case 'RectAreaLight': 16237 uniforms = { 16238 color: new Color(), 16239 position: new Vector3(), 16240 halfWidth: new Vector3(), 16241 halfHeight: new Vector3() 16242 // TODO (abelnation): set RectAreaLight shadow uniforms 16243 }; 16244 break; 16245 16246 } 16247 16248 lights[ light.id ] = uniforms; 16249 16250 return uniforms; 16251 16252 } 16253 16254 }; 16255 16256 } 16257 16258 /** 16259 * @author mrdoob / http://mrdoob.com/ 16260 */ 16261 16262 function addLineNumbers( string ) { 16263 16264 var lines = string.split( '\n' ); 16265 16266 for ( var i = 0; i < lines.length; i ++ ) { 16267 16268 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; 16269 16270 } 16271 16272 return lines.join( '\n' ); 16273 16274 } 16275 16276 function WebGLShader( gl, type, string ) { 16277 16278 var shader = gl.createShader( type ); 16279 16280 gl.shaderSource( shader, string ); 16281 gl.compileShader( shader ); 16282 16283 if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { 16284 16285 console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); 16286 16287 } 16288 16289 if ( gl.getShaderInfoLog( shader ) !== '' ) { 16290 16291 console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); 16292 16293 } 16294 16295 // --enable-privileged-webgl-extension 16296 // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); 16297 16298 return shader; 16299 16300 } 16301 16302 /** 16303 * @author mrdoob / http://mrdoob.com/ 16304 */ 16305 16306 var programIdCount = 0; 16307 16308 function getEncodingComponents( encoding ) { 16309 16310 switch ( encoding ) { 16311 16312 case LinearEncoding: 16313 return [ 'Linear','( value )' ]; 16314 case sRGBEncoding: 16315 return [ 'sRGB','( value )' ]; 16316 case RGBEEncoding: 16317 return [ 'RGBE','( value )' ]; 16318 case RGBM7Encoding: 16319 return [ 'RGBM','( value, 7.0 )' ]; 16320 case RGBM16Encoding: 16321 return [ 'RGBM','( value, 16.0 )' ]; 16322 case RGBDEncoding: 16323 return [ 'RGBD','( value, 256.0 )' ]; 16324 case GammaEncoding: 16325 return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ]; 16326 default: 16327 throw new Error( 'unsupported encoding: ' + encoding ); 16328 16329 } 16330 16331 } 16332 16333 function getTexelDecodingFunction( functionName, encoding ) { 16334 16335 var components = getEncodingComponents( encoding ); 16336 return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }"; 16337 16338 } 16339 16340 function getTexelEncodingFunction( functionName, encoding ) { 16341 16342 var components = getEncodingComponents( encoding ); 16343 return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }"; 16344 16345 } 16346 16347 function getToneMappingFunction( functionName, toneMapping ) { 16348 16349 var toneMappingName; 16350 16351 switch ( toneMapping ) { 16352 16353 case LinearToneMapping: 16354 toneMappingName = "Linear"; 16355 break; 16356 16357 case ReinhardToneMapping: 16358 toneMappingName = "Reinhard"; 16359 break; 16360 16361 case Uncharted2ToneMapping: 16362 toneMappingName = "Uncharted2"; 16363 break; 16364 16365 case CineonToneMapping: 16366 toneMappingName = "OptimizedCineon"; 16367 break; 16368 16369 default: 16370 throw new Error( 'unsupported toneMapping: ' + toneMapping ); 16371 16372 } 16373 16374 return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }"; 16375 16376 } 16377 16378 function generateExtensions( extensions, parameters, rendererExtensions ) { 16379 16380 extensions = extensions || {}; 16381 16382 var chunks = [ 16383 ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', 16384 ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', 16385 ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', 16386 ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' 16387 ]; 16388 16389 return chunks.filter( filterEmptyLine ).join( '\n' ); 16390 16391 } 16392 16393 function generateDefines( defines ) { 16394 16395 var chunks = []; 16396 16397 for ( var name in defines ) { 16398 16399 var value = defines[ name ]; 16400 16401 if ( value === false ) continue; 16402 16403 chunks.push( '#define ' + name + ' ' + value ); 16404 16405 } 16406 16407 return chunks.join( '\n' ); 16408 16409 } 16410 16411 function fetchAttributeLocations( gl, program, identifiers ) { 16412 16413 var attributes = {}; 16414 16415 var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); 16416 16417 for ( var i = 0; i < n; i ++ ) { 16418 16419 var info = gl.getActiveAttrib( program, i ); 16420 var name = info.name; 16421 16422 // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i ); 16423 16424 attributes[ name ] = gl.getAttribLocation( program, name ); 16425 16426 } 16427 16428 return attributes; 16429 16430 } 16431 16432 function filterEmptyLine( string ) { 16433 16434 return string !== ''; 16435 16436 } 16437 16438 function replaceLightNums( string, parameters ) { 16439 16440 return string 16441 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) 16442 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) 16443 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) 16444 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) 16445 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ); 16446 16447 } 16448 16449 function parseIncludes( string ) { 16450 16451 var pattern = /#include +<([\w\d.]+)>/g; 16452 16453 function replace( match, include ) { 16454 16455 var replace = ShaderChunk[ include ]; 16456 16457 if ( replace === undefined ) { 16458 16459 throw new Error( 'Can not resolve #include <' + include + '>' ); 16460 16461 } 16462 16463 return parseIncludes( replace ); 16464 16465 } 16466 16467 return string.replace( pattern, replace ); 16468 16469 } 16470 16471 function unrollLoops( string ) { 16472 16473 var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; 16474 16475 function replace( match, start, end, snippet ) { 16476 16477 var unroll = ''; 16478 16479 for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { 16480 16481 unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' ); 16482 16483 } 16484 16485 return unroll; 16486 16487 } 16488 16489 return string.replace( pattern, replace ); 16490 16491 } 16492 16493 function WebGLProgram( renderer, code, material, parameters ) { 16494 16495 var gl = renderer.context; 16496 16497 var extensions = material.extensions; 16498 var defines = material.defines; 16499 16500 var vertexShader = material.__webglShader.vertexShader; 16501 var fragmentShader = material.__webglShader.fragmentShader; 16502 16503 var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; 16504 16505 if ( parameters.shadowMapType === PCFShadowMap ) { 16506 16507 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; 16508 16509 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { 16510 16511 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; 16512 16513 } 16514 16515 var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 16516 var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; 16517 var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; 16518 16519 if ( parameters.envMap ) { 16520 16521 switch ( material.envMap.mapping ) { 16522 16523 case CubeReflectionMapping: 16524 case CubeRefractionMapping: 16525 envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 16526 break; 16527 16528 case CubeUVReflectionMapping: 16529 case CubeUVRefractionMapping: 16530 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; 16531 break; 16532 16533 case EquirectangularReflectionMapping: 16534 case EquirectangularRefractionMapping: 16535 envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; 16536 break; 16537 16538 case SphericalReflectionMapping: 16539 envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; 16540 break; 16541 16542 } 16543 16544 switch ( material.envMap.mapping ) { 16545 16546 case CubeRefractionMapping: 16547 case EquirectangularRefractionMapping: 16548 envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; 16549 break; 16550 16551 } 16552 16553 switch ( material.combine ) { 16554 16555 case MultiplyOperation: 16556 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; 16557 break; 16558 16559 case MixOperation: 16560 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; 16561 break; 16562 16563 case AddOperation: 16564 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; 16565 break; 16566 16567 } 16568 16569 } 16570 16571 var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; 16572 16573 // console.log( 'building new program ' ); 16574 16575 // 16576 16577 var customExtensions = generateExtensions( extensions, parameters, renderer.extensions ); 16578 16579 var customDefines = generateDefines( defines ); 16580 16581 // 16582 16583 var program = gl.createProgram(); 16584 16585 var prefixVertex, prefixFragment; 16586 16587 if ( material.isRawShaderMaterial ) { 16588 16589 prefixVertex = [ 16590 16591 customDefines, 16592 16593 '\n' 16594 16595 ].filter( filterEmptyLine ).join( '\n' ); 16596 16597 prefixFragment = [ 16598 16599 customExtensions, 16600 customDefines, 16601 16602 '\n' 16603 16604 ].filter( filterEmptyLine ).join( '\n' ); 16605 16606 } else { 16607 16608 prefixVertex = [ 16609 16610 16611 'precision ' + parameters.precision + ' float;', 16612 'precision ' + parameters.precision + ' int;', 16613 16614 '#define SHADER_NAME ' + material.__webglShader.name, 16615 16616 customDefines, 16617 16618 parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', 16619 16620 '#define GAMMA_FACTOR ' + gammaFactorDefine, 16621 16622 '#define MAX_BONES ' + parameters.maxBones, 16623 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', 16624 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', 16625 16626 16627 parameters.map ? '#define USE_MAP' : '', 16628 parameters.envMap ? '#define USE_ENVMAP' : '', 16629 parameters.envMap ? '#define ' + envMapModeDefine : '', 16630 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 16631 parameters.aoMap ? '#define USE_AOMAP' : '', 16632 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 16633 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 16634 parameters.normalMap ? '#define USE_NORMALMAP' : '', 16635 parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', 16636 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 16637 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 16638 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 16639 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 16640 parameters.vertexColors ? '#define USE_COLOR' : '', 16641 16642 parameters.flatShading ? '#define FLAT_SHADED' : '', 16643 16644 parameters.skinning ? '#define USE_SKINNING' : '', 16645 parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', 16646 16647 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', 16648 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', 16649 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 16650 parameters.flipSided ? '#define FLIP_SIDED' : '', 16651 16652 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, 16653 16654 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 16655 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 16656 16657 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', 16658 16659 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 16660 parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 16661 16662 'uniform mat4 modelMatrix;', 16663 'uniform mat4 modelViewMatrix;', 16664 'uniform mat4 projectionMatrix;', 16665 'uniform mat4 viewMatrix;', 16666 'uniform mat3 normalMatrix;', 16667 'uniform vec3 cameraPosition;', 16668 16669 'attribute vec3 position;', 16670 'attribute vec3 normal;', 16671 'attribute vec2 uv;', 16672 16673 '#ifdef USE_COLOR', 16674 16675 ' attribute vec3 color;', 16676 16677 '#endif', 16678 16679 '#ifdef USE_MORPHTARGETS', 16680 16681 ' attribute vec3 morphTarget0;', 16682 ' attribute vec3 morphTarget1;', 16683 ' attribute vec3 morphTarget2;', 16684 ' attribute vec3 morphTarget3;', 16685 16686 ' #ifdef USE_MORPHNORMALS', 16687 16688 ' attribute vec3 morphNormal0;', 16689 ' attribute vec3 morphNormal1;', 16690 ' attribute vec3 morphNormal2;', 16691 ' attribute vec3 morphNormal3;', 16692 16693 ' #else', 16694 16695 ' attribute vec3 morphTarget4;', 16696 ' attribute vec3 morphTarget5;', 16697 ' attribute vec3 morphTarget6;', 16698 ' attribute vec3 morphTarget7;', 16699 16700 ' #endif', 16701 16702 '#endif', 16703 16704 '#ifdef USE_SKINNING', 16705 16706 ' attribute vec4 skinIndex;', 16707 ' attribute vec4 skinWeight;', 16708 16709 '#endif', 16710 16711 '\n' 16712 16713 ].filter( filterEmptyLine ).join( '\n' ); 16714 16715 prefixFragment = [ 16716 16717 customExtensions, 16718 16719 'precision ' + parameters.precision + ' float;', 16720 'precision ' + parameters.precision + ' int;', 16721 16722 '#define SHADER_NAME ' + material.__webglShader.name, 16723 16724 customDefines, 16725 16726 parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', 16727 16728 '#define GAMMA_FACTOR ' + gammaFactorDefine, 16729 16730 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', 16731 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', 16732 16733 parameters.map ? '#define USE_MAP' : '', 16734 parameters.envMap ? '#define USE_ENVMAP' : '', 16735 parameters.envMap ? '#define ' + envMapTypeDefine : '', 16736 parameters.envMap ? '#define ' + envMapModeDefine : '', 16737 parameters.envMap ? '#define ' + envMapBlendingDefine : '', 16738 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 16739 parameters.aoMap ? '#define USE_AOMAP' : '', 16740 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 16741 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 16742 parameters.normalMap ? '#define USE_NORMALMAP' : '', 16743 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 16744 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 16745 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 16746 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 16747 parameters.vertexColors ? '#define USE_COLOR' : '', 16748 16749 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', 16750 16751 parameters.flatShading ? '#define FLAT_SHADED' : '', 16752 16753 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 16754 parameters.flipSided ? '#define FLIP_SIDED' : '', 16755 16756 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, 16757 '#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection), 16758 16759 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 16760 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 16761 16762 parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '', 16763 16764 parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '', 16765 16766 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 16767 parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 16768 16769 parameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '', 16770 16771 'uniform mat4 viewMatrix;', 16772 'uniform vec3 cameraPosition;', 16773 16774 ( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '', 16775 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below 16776 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '', 16777 16778 ( 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 16779 parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', 16780 parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', 16781 parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', 16782 parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '', 16783 16784 parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '', 16785 16786 '\n' 16787 16788 ].filter( filterEmptyLine ).join( '\n' ); 16789 16790 } 16791 16792 vertexShader = parseIncludes( vertexShader, parameters ); 16793 vertexShader = replaceLightNums( vertexShader, parameters ); 16794 16795 fragmentShader = parseIncludes( fragmentShader, parameters ); 16796 fragmentShader = replaceLightNums( fragmentShader, parameters ); 16797 16798 if ( ! material.isShaderMaterial ) { 16799 16800 vertexShader = unrollLoops( vertexShader ); 16801 fragmentShader = unrollLoops( fragmentShader ); 16802 16803 } 16804 16805 var vertexGlsl = prefixVertex + vertexShader; 16806 var fragmentGlsl = prefixFragment + fragmentShader; 16807 16808 // console.log( '*VERTEX*', vertexGlsl ); 16809 // console.log( '*FRAGMENT*', fragmentGlsl ); 16810 16811 var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); 16812 var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); 16813 16814 gl.attachShader( program, glVertexShader ); 16815 gl.attachShader( program, glFragmentShader ); 16816 16817 // Force a particular attribute to index 0. 16818 16819 if ( material.index0AttributeName !== undefined ) { 16820 16821 gl.bindAttribLocation( program, 0, material.index0AttributeName ); 16822 16823 } else if ( parameters.morphTargets === true ) { 16824 16825 // programs with morphTargets displace position out of attribute 0 16826 gl.bindAttribLocation( program, 0, 'position' ); 16827 16828 } 16829 16830 gl.linkProgram( program ); 16831 16832 var programLog = gl.getProgramInfoLog( program ); 16833 var vertexLog = gl.getShaderInfoLog( glVertexShader ); 16834 var fragmentLog = gl.getShaderInfoLog( glFragmentShader ); 16835 16836 var runnable = true; 16837 var haveDiagnostics = true; 16838 16839 // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); 16840 // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); 16841 16842 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { 16843 16844 runnable = false; 16845 16846 console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); 16847 16848 } else if ( programLog !== '' ) { 16849 16850 console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); 16851 16852 } else if ( vertexLog === '' || fragmentLog === '' ) { 16853 16854 haveDiagnostics = false; 16855 16856 } 16857 16858 if ( haveDiagnostics ) { 16859 16860 this.diagnostics = { 16861 16862 runnable: runnable, 16863 material: material, 16864 16865 programLog: programLog, 16866 16867 vertexShader: { 16868 16869 log: vertexLog, 16870 prefix: prefixVertex 16871 16872 }, 16873 16874 fragmentShader: { 16875 16876 log: fragmentLog, 16877 prefix: prefixFragment 16878 16879 } 16880 16881 }; 16882 16883 } 16884 16885 // clean up 16886 16887 gl.deleteShader( glVertexShader ); 16888 gl.deleteShader( glFragmentShader ); 16889 16890 // set up caching for uniform locations 16891 16892 var cachedUniforms; 16893 16894 this.getUniforms = function() { 16895 16896 if ( cachedUniforms === undefined ) { 16897 16898 cachedUniforms = 16899 new WebGLUniforms( gl, program, renderer ); 16900 16901 } 16902 16903 return cachedUniforms; 16904 16905 }; 16906 16907 // set up caching for attribute locations 16908 16909 var cachedAttributes; 16910 16911 this.getAttributes = function() { 16912 16913 if ( cachedAttributes === undefined ) { 16914 16915 cachedAttributes = fetchAttributeLocations( gl, program ); 16916 16917 } 16918 16919 return cachedAttributes; 16920 16921 }; 16922 16923 // free resource 16924 16925 this.destroy = function() { 16926 16927 gl.deleteProgram( program ); 16928 this.program = undefined; 16929 16930 }; 16931 16932 // DEPRECATED 16933 16934 Object.defineProperties( this, { 16935 16936 uniforms: { 16937 get: function() { 16938 16939 console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); 16940 return this.getUniforms(); 16941 16942 } 16943 }, 16944 16945 attributes: { 16946 get: function() { 16947 16948 console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); 16949 return this.getAttributes(); 16950 16951 } 16952 } 16953 16954 } ); 16955 16956 16957 // 16958 16959 this.id = programIdCount ++; 16960 this.code = code; 16961 this.usedTimes = 1; 16962 this.program = program; 16963 this.vertexShader = glVertexShader; 16964 this.fragmentShader = glFragmentShader; 16965 16966 return this; 16967 16968 } 16969 16970 /** 16971 * @author mrdoob / http://mrdoob.com/ 16972 */ 16973 16974 function WebGLPrograms( renderer, capabilities ) { 16975 16976 var programs = []; 16977 16978 var shaderIDs = { 16979 MeshDepthMaterial: 'depth', 16980 MeshNormalMaterial: 'normal', 16981 MeshBasicMaterial: 'basic', 16982 MeshLambertMaterial: 'lambert', 16983 MeshPhongMaterial: 'phong', 16984 MeshToonMaterial: 'phong', 16985 MeshStandardMaterial: 'physical', 16986 MeshPhysicalMaterial: 'physical', 16987 LineBasicMaterial: 'basic', 16988 LineDashedMaterial: 'dashed', 16989 PointsMaterial: 'points' 16990 }; 16991 16992 var parameterNames = [ 16993 "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding", 16994 "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap", 16995 "roughnessMap", "metalnessMap", "gradientMap", 16996 "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", 16997 "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", 16998 "maxBones", "useVertexTexture", "morphTargets", "morphNormals", 16999 "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", 17000 "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", 17001 "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', 17002 "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking" 17003 ]; 17004 17005 17006 function allocateBones( object ) { 17007 17008 if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { 17009 17010 return 1024; 17011 17012 } else { 17013 17014 // default for when object is not specified 17015 // ( for example when prebuilding shader to be used with multiple objects ) 17016 // 17017 // - leave some extra space for other uniforms 17018 // - limit here is ANGLE's 254 max uniform vectors 17019 // (up to 54 should be safe) 17020 17021 var nVertexUniforms = capabilities.maxVertexUniforms; 17022 var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); 17023 17024 var maxBones = nVertexMatrices; 17025 17026 if ( object !== undefined && (object && object.isSkinnedMesh) ) { 17027 17028 maxBones = Math.min( object.skeleton.bones.length, maxBones ); 17029 17030 if ( maxBones < object.skeleton.bones.length ) { 17031 17032 console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); 17033 17034 } 17035 17036 } 17037 17038 return maxBones; 17039 17040 } 17041 17042 } 17043 17044 function getTextureEncodingFromMap( map, gammaOverrideLinear ) { 17045 17046 var encoding; 17047 17048 if ( ! map ) { 17049 17050 encoding = LinearEncoding; 17051 17052 } else if ( map.isTexture ) { 17053 17054 encoding = map.encoding; 17055 17056 } else if ( map.isWebGLRenderTarget ) { 17057 17058 console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); 17059 encoding = map.texture.encoding; 17060 17061 } 17062 17063 // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point. 17064 if ( encoding === LinearEncoding && gammaOverrideLinear ) { 17065 17066 encoding = GammaEncoding; 17067 17068 } 17069 17070 return encoding; 17071 17072 } 17073 17074 this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) { 17075 17076 var shaderID = shaderIDs[ material.type ]; 17077 17078 // heuristics to create shader parameters according to lights in the scene 17079 // (not to blow over maxLights budget) 17080 17081 var maxBones = allocateBones( object ); 17082 var precision = renderer.getPrecision(); 17083 17084 if ( material.precision !== null ) { 17085 17086 precision = capabilities.getMaxPrecision( material.precision ); 17087 17088 if ( precision !== material.precision ) { 17089 17090 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); 17091 17092 } 17093 17094 } 17095 17096 var currentRenderTarget = renderer.getCurrentRenderTarget(); 17097 17098 var parameters = { 17099 17100 shaderID: shaderID, 17101 17102 precision: precision, 17103 supportsVertexTextures: capabilities.vertexTextures, 17104 outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ), 17105 map: !! material.map, 17106 mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ), 17107 envMap: !! material.envMap, 17108 envMapMode: material.envMap && material.envMap.mapping, 17109 envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ), 17110 envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ), 17111 lightMap: !! material.lightMap, 17112 aoMap: !! material.aoMap, 17113 emissiveMap: !! material.emissiveMap, 17114 emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), 17115 bumpMap: !! material.bumpMap, 17116 normalMap: !! material.normalMap, 17117 displacementMap: !! material.displacementMap, 17118 roughnessMap: !! material.roughnessMap, 17119 metalnessMap: !! material.metalnessMap, 17120 specularMap: !! material.specularMap, 17121 alphaMap: !! material.alphaMap, 17122 17123 gradientMap: !! material.gradientMap, 17124 17125 combine: material.combine, 17126 17127 vertexColors: material.vertexColors, 17128 17129 fog: !! fog, 17130 useFog: material.fog, 17131 fogExp: (fog && fog.isFogExp2), 17132 17133 flatShading: material.shading === FlatShading, 17134 17135 sizeAttenuation: material.sizeAttenuation, 17136 logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, 17137 17138 skinning: material.skinning, 17139 maxBones: maxBones, 17140 useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture, 17141 17142 morphTargets: material.morphTargets, 17143 morphNormals: material.morphNormals, 17144 maxMorphTargets: renderer.maxMorphTargets, 17145 maxMorphNormals: renderer.maxMorphNormals, 17146 17147 numDirLights: lights.directional.length, 17148 numPointLights: lights.point.length, 17149 numSpotLights: lights.spot.length, 17150 numRectAreaLights: lights.rectArea.length, 17151 numHemiLights: lights.hemi.length, 17152 17153 numClippingPlanes: nClipPlanes, 17154 numClipIntersection: nClipIntersection, 17155 17156 shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0, 17157 shadowMapType: renderer.shadowMap.type, 17158 17159 toneMapping: renderer.toneMapping, 17160 physicallyCorrectLights: renderer.physicallyCorrectLights, 17161 17162 premultipliedAlpha: material.premultipliedAlpha, 17163 17164 alphaTest: material.alphaTest, 17165 doubleSided: material.side === DoubleSide, 17166 flipSided: material.side === BackSide, 17167 17168 depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false 17169 17170 }; 17171 17172 return parameters; 17173 17174 }; 17175 17176 this.getProgramCode = function ( material, parameters ) { 17177 17178 var array = []; 17179 17180 if ( parameters.shaderID ) { 17181 17182 array.push( parameters.shaderID ); 17183 17184 } else { 17185 17186 array.push( material.fragmentShader ); 17187 array.push( material.vertexShader ); 17188 17189 } 17190 17191 if ( material.defines !== undefined ) { 17192 17193 for ( var name in material.defines ) { 17194 17195 array.push( name ); 17196 array.push( material.defines[ name ] ); 17197 17198 } 17199 17200 } 17201 17202 for ( var i = 0; i < parameterNames.length; i ++ ) { 17203 17204 array.push( parameters[ parameterNames[ i ] ] ); 17205 17206 } 17207 17208 return array.join(); 17209 17210 }; 17211 17212 this.acquireProgram = function ( material, parameters, code ) { 17213 17214 var program; 17215 17216 // Check if code has been already compiled 17217 for ( var p = 0, pl = programs.length; p < pl; p ++ ) { 17218 17219 var programInfo = programs[ p ]; 17220 17221 if ( programInfo.code === code ) { 17222 17223 program = programInfo; 17224 ++ program.usedTimes; 17225 17226 break; 17227 17228 } 17229 17230 } 17231 17232 if ( program === undefined ) { 17233 17234 program = new WebGLProgram( renderer, code, material, parameters ); 17235 programs.push( program ); 17236 17237 } 17238 17239 return program; 17240 17241 }; 17242 17243 this.releaseProgram = function( program ) { 17244 17245 if ( -- program.usedTimes === 0 ) { 17246 17247 // Remove from unordered set 17248 var i = programs.indexOf( program ); 17249 programs[ i ] = programs[ programs.length - 1 ]; 17250 programs.pop(); 17251 17252 // Free WebGL resources 17253 program.destroy(); 17254 17255 } 17256 17257 }; 17258 17259 // Exposed for resource monitoring & error feedback via renderer.info: 17260 this.programs = programs; 17261 17262 } 17263 17264 /** 17265 * @author mrdoob / http://mrdoob.com/ 17266 */ 17267 17268 function WebGLGeometries( gl, properties, info ) { 17269 17270 var geometries = {}; 17271 17272 function onGeometryDispose( event ) { 17273 17274 var geometry = event.target; 17275 var buffergeometry = geometries[ geometry.id ]; 17276 17277 if ( buffergeometry.index !== null ) { 17278 17279 deleteAttribute( buffergeometry.index ); 17280 17281 } 17282 17283 deleteAttributes( buffergeometry.attributes ); 17284 17285 geometry.removeEventListener( 'dispose', onGeometryDispose ); 17286 17287 delete geometries[ geometry.id ]; 17288 17289 // TODO 17290 17291 var property = properties.get( geometry ); 17292 17293 if ( property.wireframe ) { 17294 17295 deleteAttribute( property.wireframe ); 17296 17297 } 17298 17299 properties.delete( geometry ); 17300 17301 var bufferproperty = properties.get( buffergeometry ); 17302 17303 if ( bufferproperty.wireframe ) { 17304 17305 deleteAttribute( bufferproperty.wireframe ); 17306 17307 } 17308 17309 properties.delete( buffergeometry ); 17310 17311 // 17312 17313 info.memory.geometries --; 17314 17315 } 17316 17317 function getAttributeBuffer( attribute ) { 17318 17319 if ( attribute.isInterleavedBufferAttribute ) { 17320 17321 return properties.get( attribute.data ).__webglBuffer; 17322 17323 } 17324 17325 return properties.get( attribute ).__webglBuffer; 17326 17327 } 17328 17329 function deleteAttribute( attribute ) { 17330 17331 var buffer = getAttributeBuffer( attribute ); 17332 17333 if ( buffer !== undefined ) { 17334 17335 gl.deleteBuffer( buffer ); 17336 removeAttributeBuffer( attribute ); 17337 17338 } 17339 17340 } 17341 17342 function deleteAttributes( attributes ) { 17343 17344 for ( var name in attributes ) { 17345 17346 deleteAttribute( attributes[ name ] ); 17347 17348 } 17349 17350 } 17351 17352 function removeAttributeBuffer( attribute ) { 17353 17354 if ( attribute.isInterleavedBufferAttribute ) { 17355 17356 properties.delete( attribute.data ); 17357 17358 } else { 17359 17360 properties.delete( attribute ); 17361 17362 } 17363 17364 } 17365 17366 return { 17367 17368 get: function ( object ) { 17369 17370 var geometry = object.geometry; 17371 17372 if ( geometries[ geometry.id ] !== undefined ) { 17373 17374 return geometries[ geometry.id ]; 17375 17376 } 17377 17378 geometry.addEventListener( 'dispose', onGeometryDispose ); 17379 17380 var buffergeometry; 17381 17382 if ( geometry.isBufferGeometry ) { 17383 17384 buffergeometry = geometry; 17385 17386 } else if ( geometry.isGeometry ) { 17387 17388 if ( geometry._bufferGeometry === undefined ) { 17389 17390 geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); 17391 17392 } 17393 17394 buffergeometry = geometry._bufferGeometry; 17395 17396 } 17397 17398 geometries[ geometry.id ] = buffergeometry; 17399 17400 info.memory.geometries ++; 17401 17402 return buffergeometry; 17403 17404 } 17405 17406 }; 17407 17408 } 17409 17410 /** 17411 * @author mrdoob / http://mrdoob.com/ 17412 */ 17413 17414 function WebGLObjects( gl, properties, info ) { 17415 17416 var geometries = new WebGLGeometries( gl, properties, info ); 17417 17418 // 17419 17420 function update( object ) { 17421 17422 // TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter. 17423 17424 var geometry = geometries.get( object ); 17425 17426 if ( object.geometry.isGeometry ) { 17427 17428 geometry.updateFromObject( object ); 17429 17430 } 17431 17432 var index = geometry.index; 17433 var attributes = geometry.attributes; 17434 17435 if ( index !== null ) { 17436 17437 updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER ); 17438 17439 } 17440 17441 for ( var name in attributes ) { 17442 17443 updateAttribute( attributes[ name ], gl.ARRAY_BUFFER ); 17444 17445 } 17446 17447 // morph targets 17448 17449 var morphAttributes = geometry.morphAttributes; 17450 17451 for ( var name in morphAttributes ) { 17452 17453 var array = morphAttributes[ name ]; 17454 17455 for ( var i = 0, l = array.length; i < l; i ++ ) { 17456 17457 updateAttribute( array[ i ], gl.ARRAY_BUFFER ); 17458 17459 } 17460 17461 } 17462 17463 return geometry; 17464 17465 } 17466 17467 function updateAttribute( attribute, bufferType ) { 17468 17469 var data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute; 17470 17471 var attributeProperties = properties.get( data ); 17472 17473 if ( attributeProperties.__webglBuffer === undefined ) { 17474 17475 createBuffer( attributeProperties, data, bufferType ); 17476 17477 } else if ( attributeProperties.version !== data.version ) { 17478 17479 updateBuffer( attributeProperties, data, bufferType ); 17480 17481 } 17482 17483 } 17484 17485 function createBuffer( attributeProperties, data, bufferType ) { 17486 17487 attributeProperties.__webglBuffer = gl.createBuffer(); 17488 gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); 17489 17490 var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; 17491 17492 gl.bufferData( bufferType, data.array, usage ); 17493 17494 var type = gl.FLOAT; 17495 var array = data.array; 17496 17497 if ( array instanceof Float32Array ) { 17498 17499 type = gl.FLOAT; 17500 17501 } else if ( array instanceof Float64Array ) { 17502 17503 console.warn( "Unsupported data buffer format: Float64Array" ); 17504 17505 } else if ( array instanceof Uint16Array ) { 17506 17507 type = gl.UNSIGNED_SHORT; 17508 17509 } else if ( array instanceof Int16Array ) { 17510 17511 type = gl.SHORT; 17512 17513 } else if ( array instanceof Uint32Array ) { 17514 17515 type = gl.UNSIGNED_INT; 17516 17517 } else if ( array instanceof Int32Array ) { 17518 17519 type = gl.INT; 17520 17521 } else if ( array instanceof Int8Array ) { 17522 17523 type = gl.BYTE; 17524 17525 } else if ( array instanceof Uint8Array ) { 17526 17527 type = gl.UNSIGNED_BYTE; 17528 17529 } 17530 17531 attributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT; 17532 attributeProperties.type = type; 17533 attributeProperties.version = data.version; 17534 17535 data.onUploadCallback(); 17536 17537 } 17538 17539 function updateBuffer( attributeProperties, data, bufferType ) { 17540 17541 gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); 17542 17543 if ( data.dynamic === false ) { 17544 17545 gl.bufferData( bufferType, data.array, gl.STATIC_DRAW ); 17546 17547 } else if ( data.updateRange.count === - 1 ) { 17548 17549 // Not using update ranges 17550 17551 gl.bufferSubData( bufferType, 0, data.array ); 17552 17553 } else if ( data.updateRange.count === 0 ) { 17554 17555 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.' ); 17556 17557 } else { 17558 17559 gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, 17560 data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) ); 17561 17562 data.updateRange.count = 0; // reset range 17563 17564 } 17565 17566 attributeProperties.version = data.version; 17567 17568 } 17569 17570 function getAttributeBuffer( attribute ) { 17571 17572 if ( attribute.isInterleavedBufferAttribute ) { 17573 17574 return properties.get( attribute.data ).__webglBuffer; 17575 17576 } 17577 17578 return properties.get( attribute ).__webglBuffer; 17579 17580 } 17581 17582 function getAttributeProperties( attribute ) { 17583 17584 if ( attribute.isInterleavedBufferAttribute ) { 17585 17586 return properties.get( attribute.data ); 17587 17588 } 17589 17590 return properties.get( attribute ); 17591 17592 } 17593 17594 function getWireframeAttribute( geometry ) { 17595 17596 var property = properties.get( geometry ); 17597 17598 if ( property.wireframe !== undefined ) { 17599 17600 return property.wireframe; 17601 17602 } 17603 17604 var indices = []; 17605 17606 var index = geometry.index; 17607 var attributes = geometry.attributes; 17608 17609 // console.time( 'wireframe' ); 17610 17611 if ( index !== null ) { 17612 17613 var array = index.array; 17614 17615 for ( var i = 0, l = array.length; i < l; i += 3 ) { 17616 17617 var a = array[ i + 0 ]; 17618 var b = array[ i + 1 ]; 17619 var c = array[ i + 2 ]; 17620 17621 indices.push( a, b, b, c, c, a ); 17622 17623 } 17624 17625 } else { 17626 17627 var array = attributes.position.array; 17628 17629 for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { 17630 17631 var a = i + 0; 17632 var b = i + 1; 17633 var c = i + 2; 17634 17635 indices.push( a, b, b, c, c, a ); 17636 17637 } 17638 17639 } 17640 17641 // console.timeEnd( 'wireframe' ); 17642 17643 var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); 17644 17645 updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); 17646 17647 property.wireframe = attribute; 17648 17649 return attribute; 17650 17651 } 17652 17653 return { 17654 17655 getAttributeBuffer: getAttributeBuffer, 17656 getAttributeProperties: getAttributeProperties, 17657 getWireframeAttribute: getWireframeAttribute, 17658 17659 update: update 17660 17661 }; 17662 17663 } 17664 17665 /** 17666 * @author mrdoob / http://mrdoob.com/ 17667 */ 17668 17669 function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) { 17670 17671 var _infoMemory = info.memory; 17672 var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); 17673 17674 // 17675 17676 function clampToMaxSize( image, maxSize ) { 17677 17678 if ( image.width > maxSize || image.height > maxSize ) { 17679 17680 // Warning: Scaling through the canvas will only work with images that use 17681 // premultiplied alpha. 17682 17683 var scale = maxSize / Math.max( image.width, image.height ); 17684 17685 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); 17686 canvas.width = Math.floor( image.width * scale ); 17687 canvas.height = Math.floor( image.height * scale ); 17688 17689 var context = canvas.getContext( '2d' ); 17690 context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); 17691 17692 console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); 17693 17694 return canvas; 17695 17696 } 17697 17698 return image; 17699 17700 } 17701 17702 function isPowerOfTwo( image ) { 17703 17704 return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); 17705 17706 } 17707 17708 function makePowerOfTwo( image ) { 17709 17710 if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) { 17711 17712 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); 17713 canvas.width = _Math.nearestPowerOfTwo( image.width ); 17714 canvas.height = _Math.nearestPowerOfTwo( image.height ); 17715 17716 var context = canvas.getContext( '2d' ); 17717 context.drawImage( image, 0, 0, canvas.width, canvas.height ); 17718 17719 console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); 17720 17721 return canvas; 17722 17723 } 17724 17725 return image; 17726 17727 } 17728 17729 function textureNeedsPowerOfTwo( texture ) { 17730 17731 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || 17732 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); 17733 17734 } 17735 17736 // Fallback filters for non-power-of-2 textures 17737 17738 function filterFallback( f ) { 17739 17740 if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { 17741 17742 return _gl.NEAREST; 17743 17744 } 17745 17746 return _gl.LINEAR; 17747 17748 } 17749 17750 // 17751 17752 function onTextureDispose( event ) { 17753 17754 var texture = event.target; 17755 17756 texture.removeEventListener( 'dispose', onTextureDispose ); 17757 17758 deallocateTexture( texture ); 17759 17760 _infoMemory.textures --; 17761 17762 17763 } 17764 17765 function onRenderTargetDispose( event ) { 17766 17767 var renderTarget = event.target; 17768 17769 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); 17770 17771 deallocateRenderTarget( renderTarget ); 17772 17773 _infoMemory.textures --; 17774 17775 } 17776 17777 // 17778 17779 function deallocateTexture( texture ) { 17780 17781 var textureProperties = properties.get( texture ); 17782 17783 if ( texture.image && textureProperties.__image__webglTextureCube ) { 17784 17785 // cube texture 17786 17787 _gl.deleteTexture( textureProperties.__image__webglTextureCube ); 17788 17789 } else { 17790 17791 // 2D texture 17792 17793 if ( textureProperties.__webglInit === undefined ) return; 17794 17795 _gl.deleteTexture( textureProperties.__webglTexture ); 17796 17797 } 17798 17799 // remove all webgl properties 17800 properties.delete( texture ); 17801 17802 } 17803 17804 function deallocateRenderTarget( renderTarget ) { 17805 17806 var renderTargetProperties = properties.get( renderTarget ); 17807 var textureProperties = properties.get( renderTarget.texture ); 17808 17809 if ( ! renderTarget ) return; 17810 17811 if ( textureProperties.__webglTexture !== undefined ) { 17812 17813 _gl.deleteTexture( textureProperties.__webglTexture ); 17814 17815 } 17816 17817 if ( renderTarget.depthTexture ) { 17818 17819 renderTarget.depthTexture.dispose(); 17820 17821 } 17822 17823 if ( renderTarget.isWebGLRenderTargetCube ) { 17824 17825 for ( var i = 0; i < 6; i ++ ) { 17826 17827 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); 17828 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); 17829 17830 } 17831 17832 } else { 17833 17834 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); 17835 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); 17836 17837 } 17838 17839 properties.delete( renderTarget.texture ); 17840 properties.delete( renderTarget ); 17841 17842 } 17843 17844 // 17845 17846 17847 17848 function setTexture2D( texture, slot ) { 17849 17850 var textureProperties = properties.get( texture ); 17851 17852 if ( texture.version > 0 && textureProperties.__version !== texture.version ) { 17853 17854 var image = texture.image; 17855 17856 if ( image === undefined ) { 17857 17858 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); 17859 17860 } else if ( image.complete === false ) { 17861 17862 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); 17863 17864 } else { 17865 17866 uploadTexture( textureProperties, texture, slot ); 17867 return; 17868 17869 } 17870 17871 } 17872 17873 state.activeTexture( _gl.TEXTURE0 + slot ); 17874 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); 17875 17876 } 17877 17878 function setTextureCube( texture, slot ) { 17879 17880 var textureProperties = properties.get( texture ); 17881 17882 if ( texture.image.length === 6 ) { 17883 17884 if ( texture.version > 0 && textureProperties.__version !== texture.version ) { 17885 17886 if ( ! textureProperties.__image__webglTextureCube ) { 17887 17888 texture.addEventListener( 'dispose', onTextureDispose ); 17889 17890 textureProperties.__image__webglTextureCube = _gl.createTexture(); 17891 17892 _infoMemory.textures ++; 17893 17894 } 17895 17896 state.activeTexture( _gl.TEXTURE0 + slot ); 17897 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); 17898 17899 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 17900 17901 var isCompressed = ( texture && texture.isCompressedTexture ); 17902 var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); 17903 17904 var cubeImage = []; 17905 17906 for ( var i = 0; i < 6; i ++ ) { 17907 17908 if ( ! isCompressed && ! isDataTexture ) { 17909 17910 cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); 17911 17912 } else { 17913 17914 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; 17915 17916 } 17917 17918 } 17919 17920 var image = cubeImage[ 0 ], 17921 isPowerOfTwoImage = isPowerOfTwo( image ), 17922 glFormat = paramThreeToGL( texture.format ), 17923 glType = paramThreeToGL( texture.type ); 17924 17925 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage ); 17926 17927 for ( var i = 0; i < 6; i ++ ) { 17928 17929 if ( ! isCompressed ) { 17930 17931 if ( isDataTexture ) { 17932 17933 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); 17934 17935 } else { 17936 17937 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); 17938 17939 } 17940 17941 } else { 17942 17943 var mipmap, mipmaps = cubeImage[ i ].mipmaps; 17944 17945 for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { 17946 17947 mipmap = mipmaps[ j ]; 17948 17949 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { 17950 17951 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { 17952 17953 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 17954 17955 } else { 17956 17957 console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()" ); 17958 17959 } 17960 17961 } else { 17962 17963 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 17964 17965 } 17966 17967 } 17968 17969 } 17970 17971 } 17972 17973 if ( texture.generateMipmaps && isPowerOfTwoImage ) { 17974 17975 _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); 17976 17977 } 17978 17979 textureProperties.__version = texture.version; 17980 17981 if ( texture.onUpdate ) texture.onUpdate( texture ); 17982 17983 } else { 17984 17985 state.activeTexture( _gl.TEXTURE0 + slot ); 17986 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); 17987 17988 } 17989 17990 } 17991 17992 } 17993 17994 function setTextureCubeDynamic( texture, slot ) { 17995 17996 state.activeTexture( _gl.TEXTURE0 + slot ); 17997 state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); 17998 17999 } 18000 18001 function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { 18002 18003 var extension; 18004 18005 if ( isPowerOfTwoImage ) { 18006 18007 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); 18008 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); 18009 18010 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); 18011 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); 18012 18013 } else { 18014 18015 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); 18016 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); 18017 18018 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { 18019 18020 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture ); 18021 18022 } 18023 18024 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); 18025 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); 18026 18027 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { 18028 18029 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture ); 18030 18031 } 18032 18033 } 18034 18035 extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 18036 18037 if ( extension ) { 18038 18039 if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; 18040 if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; 18041 18042 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { 18043 18044 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); 18045 properties.get( texture ).__currentAnisotropy = texture.anisotropy; 18046 18047 } 18048 18049 } 18050 18051 } 18052 18053 function uploadTexture( textureProperties, texture, slot ) { 18054 18055 if ( textureProperties.__webglInit === undefined ) { 18056 18057 textureProperties.__webglInit = true; 18058 18059 texture.addEventListener( 'dispose', onTextureDispose ); 18060 18061 textureProperties.__webglTexture = _gl.createTexture(); 18062 18063 _infoMemory.textures ++; 18064 18065 } 18066 18067 state.activeTexture( _gl.TEXTURE0 + slot ); 18068 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); 18069 18070 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 18071 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); 18072 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); 18073 18074 var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); 18075 18076 if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { 18077 18078 image = makePowerOfTwo( image ); 18079 18080 } 18081 18082 var isPowerOfTwoImage = isPowerOfTwo( image ), 18083 glFormat = paramThreeToGL( texture.format ), 18084 glType = paramThreeToGL( texture.type ); 18085 18086 setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage ); 18087 18088 var mipmap, mipmaps = texture.mipmaps; 18089 18090 if ( texture.isDepthTexture ) { 18091 18092 // populate depth texture with dummy data 18093 18094 var internalFormat = _gl.DEPTH_COMPONENT; 18095 18096 if ( texture.type === FloatType ) { 18097 18098 if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0'); 18099 internalFormat = _gl.DEPTH_COMPONENT32F; 18100 18101 } else if ( _isWebGL2 ) { 18102 18103 // WebGL 2.0 requires signed internalformat for glTexImage2D 18104 internalFormat = _gl.DEPTH_COMPONENT16; 18105 18106 } 18107 18108 if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) { 18109 18110 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 18111 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT 18112 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 18113 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { 18114 18115 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); 18116 18117 texture.type = UnsignedShortType; 18118 glType = paramThreeToGL( texture.type ); 18119 18120 } 18121 18122 } 18123 18124 // Depth stencil textures need the DEPTH_STENCIL internal format 18125 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 18126 if ( texture.format === DepthStencilFormat ) { 18127 18128 internalFormat = _gl.DEPTH_STENCIL; 18129 18130 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 18131 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. 18132 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 18133 if ( texture.type !== UnsignedInt248Type ) { 18134 18135 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); 18136 18137 texture.type = UnsignedInt248Type; 18138 glType = paramThreeToGL( texture.type ); 18139 18140 } 18141 18142 } 18143 18144 state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null ); 18145 18146 } else if ( texture.isDataTexture ) { 18147 18148 // use manually created mipmaps if available 18149 // if there are no manual mipmaps 18150 // set 0 level mipmap and then use GL to generate other mipmap levels 18151 18152 if ( mipmaps.length > 0 && isPowerOfTwoImage ) { 18153 18154 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { 18155 18156 mipmap = mipmaps[ i ]; 18157 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 18158 18159 } 18160 18161 texture.generateMipmaps = false; 18162 18163 } else { 18164 18165 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); 18166 18167 } 18168 18169 } else if ( texture.isCompressedTexture ) { 18170 18171 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { 18172 18173 mipmap = mipmaps[ i ]; 18174 18175 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { 18176 18177 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { 18178 18179 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 18180 18181 } else { 18182 18183 console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); 18184 18185 } 18186 18187 } else { 18188 18189 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 18190 18191 } 18192 18193 } 18194 18195 } else { 18196 18197 // regular Texture (image, video, canvas) 18198 18199 // use manually created mipmaps if available 18200 // if there are no manual mipmaps 18201 // set 0 level mipmap and then use GL to generate other mipmap levels 18202 18203 if ( mipmaps.length > 0 && isPowerOfTwoImage ) { 18204 18205 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { 18206 18207 mipmap = mipmaps[ i ]; 18208 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); 18209 18210 } 18211 18212 texture.generateMipmaps = false; 18213 18214 } else { 18215 18216 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image ); 18217 18218 } 18219 18220 } 18221 18222 if ( texture.generateMipmaps && isPowerOfTwoImage ) _gl.generateMipmap( _gl.TEXTURE_2D ); 18223 18224 textureProperties.__version = texture.version; 18225 18226 if ( texture.onUpdate ) texture.onUpdate( texture ); 18227 18228 } 18229 18230 // Render targets 18231 18232 // Setup storage for target texture and bind it to correct framebuffer 18233 function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { 18234 18235 var glFormat = paramThreeToGL( renderTarget.texture.format ); 18236 var glType = paramThreeToGL( renderTarget.texture.type ); 18237 state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); 18238 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 18239 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); 18240 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); 18241 18242 } 18243 18244 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer 18245 function setupRenderBufferStorage( renderbuffer, renderTarget ) { 18246 18247 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); 18248 18249 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { 18250 18251 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); 18252 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); 18253 18254 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { 18255 18256 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); 18257 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); 18258 18259 } else { 18260 18261 // FIXME: We don't support !depth !stencil 18262 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); 18263 18264 } 18265 18266 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); 18267 18268 } 18269 18270 // Setup resources for a Depth Texture for a FBO (needs an extension) 18271 function setupDepthTexture( framebuffer, renderTarget ) { 18272 18273 var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); 18274 if ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!'); 18275 18276 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 18277 18278 if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { 18279 18280 throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture'); 18281 18282 } 18283 18284 // upload an empty depth texture with framebuffer size 18285 if ( !properties.get( renderTarget.depthTexture ).__webglTexture || 18286 renderTarget.depthTexture.image.width !== renderTarget.width || 18287 renderTarget.depthTexture.image.height !== renderTarget.height ) { 18288 renderTarget.depthTexture.image.width = renderTarget.width; 18289 renderTarget.depthTexture.image.height = renderTarget.height; 18290 renderTarget.depthTexture.needsUpdate = true; 18291 } 18292 18293 setTexture2D( renderTarget.depthTexture, 0 ); 18294 18295 var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; 18296 18297 if ( renderTarget.depthTexture.format === DepthFormat ) { 18298 18299 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); 18300 18301 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { 18302 18303 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); 18304 18305 } else { 18306 18307 throw new Error('Unknown depthTexture format') 18308 18309 } 18310 18311 } 18312 18313 // Setup GL resources for a non-texture depth buffer 18314 function setupDepthRenderbuffer( renderTarget ) { 18315 18316 var renderTargetProperties = properties.get( renderTarget ); 18317 18318 var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); 18319 18320 if ( renderTarget.depthTexture ) { 18321 18322 if ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets'); 18323 18324 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); 18325 18326 } else { 18327 18328 if ( isCube ) { 18329 18330 renderTargetProperties.__webglDepthbuffer = []; 18331 18332 for ( var i = 0; i < 6; i ++ ) { 18333 18334 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); 18335 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); 18336 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); 18337 18338 } 18339 18340 } else { 18341 18342 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 18343 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); 18344 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); 18345 18346 } 18347 18348 } 18349 18350 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); 18351 18352 } 18353 18354 // Set up GL resources for the render target 18355 function setupRenderTarget( renderTarget ) { 18356 18357 var renderTargetProperties = properties.get( renderTarget ); 18358 var textureProperties = properties.get( renderTarget.texture ); 18359 18360 renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); 18361 18362 textureProperties.__webglTexture = _gl.createTexture(); 18363 18364 _infoMemory.textures ++; 18365 18366 var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); 18367 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); 18368 18369 // Setup framebuffer 18370 18371 if ( isCube ) { 18372 18373 renderTargetProperties.__webglFramebuffer = []; 18374 18375 for ( var i = 0; i < 6; i ++ ) { 18376 18377 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); 18378 18379 } 18380 18381 } else { 18382 18383 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); 18384 18385 } 18386 18387 // Setup color buffer 18388 18389 if ( isCube ) { 18390 18391 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); 18392 setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); 18393 18394 for ( var i = 0; i < 6; i ++ ) { 18395 18396 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); 18397 18398 } 18399 18400 if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); 18401 state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); 18402 18403 } else { 18404 18405 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); 18406 setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); 18407 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D ); 18408 18409 if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); 18410 state.bindTexture( _gl.TEXTURE_2D, null ); 18411 18412 } 18413 18414 // Setup depth and stencil buffers 18415 18416 if ( renderTarget.depthBuffer ) { 18417 18418 setupDepthRenderbuffer( renderTarget ); 18419 18420 } 18421 18422 } 18423 18424 function updateRenderTargetMipmap( renderTarget ) { 18425 18426 var texture = renderTarget.texture; 18427 18428 if ( texture.generateMipmaps && isPowerOfTwo( renderTarget ) && 18429 texture.minFilter !== NearestFilter && 18430 texture.minFilter !== LinearFilter ) { 18431 18432 var target = (renderTarget && renderTarget.isWebGLRenderTargetCube) ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; 18433 var webglTexture = properties.get( texture ).__webglTexture; 18434 18435 state.bindTexture( target, webglTexture ); 18436 _gl.generateMipmap( target ); 18437 state.bindTexture( target, null ); 18438 18439 } 18440 18441 } 18442 18443 this.setTexture2D = setTexture2D; 18444 this.setTextureCube = setTextureCube; 18445 this.setTextureCubeDynamic = setTextureCubeDynamic; 18446 this.setupRenderTarget = setupRenderTarget; 18447 this.updateRenderTargetMipmap = updateRenderTargetMipmap; 18448 18449 } 18450 18451 /** 18452 * @author fordacious / fordacious.github.io 18453 */ 18454 18455 function WebGLProperties() { 18456 18457 var properties = {}; 18458 18459 return { 18460 18461 get: function ( object ) { 18462 18463 var uuid = object.uuid; 18464 var map = properties[ uuid ]; 18465 18466 if ( map === undefined ) { 18467 18468 map = {}; 18469 properties[ uuid ] = map; 18470 18471 } 18472 18473 return map; 18474 18475 }, 18476 18477 delete: function ( object ) { 18478 18479 delete properties[ object.uuid ]; 18480 18481 }, 18482 18483 clear: function () { 18484 18485 properties = {}; 18486 18487 } 18488 18489 }; 18490 18491 } 18492 18493 /** 18494 * @author mrdoob / http://mrdoob.com/ 18495 */ 18496 18497 function WebGLState( gl, extensions, paramThreeToGL ) { 18498 18499 function ColorBuffer() { 18500 18501 var locked = false; 18502 18503 var color = new Vector4(); 18504 var currentColorMask = null; 18505 var currentColorClear = new Vector4(); 18506 18507 return { 18508 18509 setMask: function ( colorMask ) { 18510 18511 if ( currentColorMask !== colorMask && ! locked ) { 18512 18513 gl.colorMask( colorMask, colorMask, colorMask, colorMask ); 18514 currentColorMask = colorMask; 18515 18516 } 18517 18518 }, 18519 18520 setLocked: function ( lock ) { 18521 18522 locked = lock; 18523 18524 }, 18525 18526 setClear: function ( r, g, b, a, premultipliedAlpha ) { 18527 18528 if ( premultipliedAlpha === true ) { 18529 18530 r *= a; g *= a; b *= a; 18531 18532 } 18533 18534 color.set( r, g, b, a ); 18535 18536 if ( currentColorClear.equals( color ) === false ) { 18537 18538 gl.clearColor( r, g, b, a ); 18539 currentColorClear.copy( color ); 18540 18541 } 18542 18543 }, 18544 18545 reset: function () { 18546 18547 locked = false; 18548 18549 currentColorMask = null; 18550 currentColorClear.set( 0, 0, 0, 1 ); 18551 18552 } 18553 18554 }; 18555 18556 } 18557 18558 function DepthBuffer() { 18559 18560 var locked = false; 18561 18562 var currentDepthMask = null; 18563 var currentDepthFunc = null; 18564 var currentDepthClear = null; 18565 18566 return { 18567 18568 setTest: function ( depthTest ) { 18569 18570 if ( depthTest ) { 18571 18572 enable( gl.DEPTH_TEST ); 18573 18574 } else { 18575 18576 disable( gl.DEPTH_TEST ); 18577 18578 } 18579 18580 }, 18581 18582 setMask: function ( depthMask ) { 18583 18584 if ( currentDepthMask !== depthMask && ! locked ) { 18585 18586 gl.depthMask( depthMask ); 18587 currentDepthMask = depthMask; 18588 18589 } 18590 18591 }, 18592 18593 setFunc: function ( depthFunc ) { 18594 18595 if ( currentDepthFunc !== depthFunc ) { 18596 18597 if ( depthFunc ) { 18598 18599 switch ( depthFunc ) { 18600 18601 case NeverDepth: 18602 18603 gl.depthFunc( gl.NEVER ); 18604 break; 18605 18606 case AlwaysDepth: 18607 18608 gl.depthFunc( gl.ALWAYS ); 18609 break; 18610 18611 case LessDepth: 18612 18613 gl.depthFunc( gl.LESS ); 18614 break; 18615 18616 case LessEqualDepth: 18617 18618 gl.depthFunc( gl.LEQUAL ); 18619 break; 18620 18621 case EqualDepth: 18622 18623 gl.depthFunc( gl.EQUAL ); 18624 break; 18625 18626 case GreaterEqualDepth: 18627 18628 gl.depthFunc( gl.GEQUAL ); 18629 break; 18630 18631 case GreaterDepth: 18632 18633 gl.depthFunc( gl.GREATER ); 18634 break; 18635 18636 case NotEqualDepth: 18637 18638 gl.depthFunc( gl.NOTEQUAL ); 18639 break; 18640 18641 default: 18642 18643 gl.depthFunc( gl.LEQUAL ); 18644 18645 } 18646 18647 } else { 18648 18649 gl.depthFunc( gl.LEQUAL ); 18650 18651 } 18652 18653 currentDepthFunc = depthFunc; 18654 18655 } 18656 18657 }, 18658 18659 setLocked: function ( lock ) { 18660 18661 locked = lock; 18662 18663 }, 18664 18665 setClear: function ( depth ) { 18666 18667 if ( currentDepthClear !== depth ) { 18668 18669 gl.clearDepth( depth ); 18670 currentDepthClear = depth; 18671 18672 } 18673 18674 }, 18675 18676 reset: function () { 18677 18678 locked = false; 18679 18680 currentDepthMask = null; 18681 currentDepthFunc = null; 18682 currentDepthClear = null; 18683 18684 } 18685 18686 }; 18687 18688 } 18689 18690 function StencilBuffer() { 18691 18692 var locked = false; 18693 18694 var currentStencilMask = null; 18695 var currentStencilFunc = null; 18696 var currentStencilRef = null; 18697 var currentStencilFuncMask = null; 18698 var currentStencilFail = null; 18699 var currentStencilZFail = null; 18700 var currentStencilZPass = null; 18701 var currentStencilClear = null; 18702 18703 return { 18704 18705 setTest: function ( stencilTest ) { 18706 18707 if ( stencilTest ) { 18708 18709 enable( gl.STENCIL_TEST ); 18710 18711 } else { 18712 18713 disable( gl.STENCIL_TEST ); 18714 18715 } 18716 18717 }, 18718 18719 setMask: function ( stencilMask ) { 18720 18721 if ( currentStencilMask !== stencilMask && ! locked ) { 18722 18723 gl.stencilMask( stencilMask ); 18724 currentStencilMask = stencilMask; 18725 18726 } 18727 18728 }, 18729 18730 setFunc: function ( stencilFunc, stencilRef, stencilMask ) { 18731 18732 if ( currentStencilFunc !== stencilFunc || 18733 currentStencilRef !== stencilRef || 18734 currentStencilFuncMask !== stencilMask ) { 18735 18736 gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); 18737 18738 currentStencilFunc = stencilFunc; 18739 currentStencilRef = stencilRef; 18740 currentStencilFuncMask = stencilMask; 18741 18742 } 18743 18744 }, 18745 18746 setOp: function ( stencilFail, stencilZFail, stencilZPass ) { 18747 18748 if ( currentStencilFail !== stencilFail || 18749 currentStencilZFail !== stencilZFail || 18750 currentStencilZPass !== stencilZPass ) { 18751 18752 gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); 18753 18754 currentStencilFail = stencilFail; 18755 currentStencilZFail = stencilZFail; 18756 currentStencilZPass = stencilZPass; 18757 18758 } 18759 18760 }, 18761 18762 setLocked: function ( lock ) { 18763 18764 locked = lock; 18765 18766 }, 18767 18768 setClear: function ( stencil ) { 18769 18770 if ( currentStencilClear !== stencil ) { 18771 18772 gl.clearStencil( stencil ); 18773 currentStencilClear = stencil; 18774 18775 } 18776 18777 }, 18778 18779 reset: function () { 18780 18781 locked = false; 18782 18783 currentStencilMask = null; 18784 currentStencilFunc = null; 18785 currentStencilRef = null; 18786 currentStencilFuncMask = null; 18787 currentStencilFail = null; 18788 currentStencilZFail = null; 18789 currentStencilZPass = null; 18790 currentStencilClear = null; 18791 18792 } 18793 18794 }; 18795 18796 } 18797 18798 // 18799 18800 var colorBuffer = new ColorBuffer(); 18801 var depthBuffer = new DepthBuffer(); 18802 var stencilBuffer = new StencilBuffer(); 18803 18804 var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 18805 var newAttributes = new Uint8Array( maxVertexAttributes ); 18806 var enabledAttributes = new Uint8Array( maxVertexAttributes ); 18807 var attributeDivisors = new Uint8Array( maxVertexAttributes ); 18808 18809 var capabilities = {}; 18810 18811 var compressedTextureFormats = null; 18812 18813 var currentBlending = null; 18814 var currentBlendEquation = null; 18815 var currentBlendSrc = null; 18816 var currentBlendDst = null; 18817 var currentBlendEquationAlpha = null; 18818 var currentBlendSrcAlpha = null; 18819 var currentBlendDstAlpha = null; 18820 var currentPremultipledAlpha = false; 18821 18822 var currentFlipSided = null; 18823 var currentCullFace = null; 18824 18825 var currentLineWidth = null; 18826 18827 var currentPolygonOffsetFactor = null; 18828 var currentPolygonOffsetUnits = null; 18829 18830 var currentScissorTest = null; 18831 18832 var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); 18833 18834 var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] ); 18835 var lineWidthAvailable = parseFloat( version ) >= 1.0; 18836 18837 var currentTextureSlot = null; 18838 var currentBoundTextures = {}; 18839 18840 var currentScissor = new Vector4(); 18841 var currentViewport = new Vector4(); 18842 18843 function createTexture( type, target, count ) { 18844 18845 var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. 18846 var texture = gl.createTexture(); 18847 18848 gl.bindTexture( type, texture ); 18849 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); 18850 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); 18851 18852 for ( var i = 0; i < count; i ++ ) { 18853 18854 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); 18855 18856 } 18857 18858 return texture; 18859 18860 } 18861 18862 var emptyTextures = {}; 18863 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); 18864 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); 18865 18866 // 18867 18868 function init() { 18869 18870 colorBuffer.setClear( 0, 0, 0, 1 ); 18871 depthBuffer.setClear( 1 ); 18872 stencilBuffer.setClear( 0 ); 18873 18874 enable( gl.DEPTH_TEST ); 18875 setDepthFunc( LessEqualDepth ); 18876 18877 setFlipSided( false ); 18878 setCullFace( CullFaceBack ); 18879 enable( gl.CULL_FACE ); 18880 18881 enable( gl.BLEND ); 18882 setBlending( NormalBlending ); 18883 18884 } 18885 18886 function initAttributes() { 18887 18888 for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { 18889 18890 newAttributes[ i ] = 0; 18891 18892 } 18893 18894 } 18895 18896 function enableAttribute( attribute ) { 18897 18898 newAttributes[ attribute ] = 1; 18899 18900 if ( enabledAttributes[ attribute ] === 0 ) { 18901 18902 gl.enableVertexAttribArray( attribute ); 18903 enabledAttributes[ attribute ] = 1; 18904 18905 } 18906 18907 if ( attributeDivisors[ attribute ] !== 0 ) { 18908 18909 var extension = extensions.get( 'ANGLE_instanced_arrays' ); 18910 18911 extension.vertexAttribDivisorANGLE( attribute, 0 ); 18912 attributeDivisors[ attribute ] = 0; 18913 18914 } 18915 18916 } 18917 18918 function enableAttributeAndDivisor( attribute, meshPerAttribute, extension ) { 18919 18920 newAttributes[ attribute ] = 1; 18921 18922 if ( enabledAttributes[ attribute ] === 0 ) { 18923 18924 gl.enableVertexAttribArray( attribute ); 18925 enabledAttributes[ attribute ] = 1; 18926 18927 } 18928 18929 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { 18930 18931 extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); 18932 attributeDivisors[ attribute ] = meshPerAttribute; 18933 18934 } 18935 18936 } 18937 18938 function disableUnusedAttributes() { 18939 18940 for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) { 18941 18942 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { 18943 18944 gl.disableVertexAttribArray( i ); 18945 enabledAttributes[ i ] = 0; 18946 18947 } 18948 18949 } 18950 18951 } 18952 18953 function enable( id ) { 18954 18955 if ( capabilities[ id ] !== true ) { 18956 18957 gl.enable( id ); 18958 capabilities[ id ] = true; 18959 18960 } 18961 18962 } 18963 18964 function disable( id ) { 18965 18966 if ( capabilities[ id ] !== false ) { 18967 18968 gl.disable( id ); 18969 capabilities[ id ] = false; 18970 18971 } 18972 18973 } 18974 18975 function getCompressedTextureFormats() { 18976 18977 if ( compressedTextureFormats === null ) { 18978 18979 compressedTextureFormats = []; 18980 18981 if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || 18982 extensions.get( 'WEBGL_compressed_texture_s3tc' ) || 18983 extensions.get( 'WEBGL_compressed_texture_etc1' ) ) { 18984 18985 var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); 18986 18987 for ( var i = 0; i < formats.length; i ++ ) { 18988 18989 compressedTextureFormats.push( formats[ i ] ); 18990 18991 } 18992 18993 } 18994 18995 } 18996 18997 return compressedTextureFormats; 18998 18999 } 19000 19001 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { 19002 19003 if ( blending !== NoBlending ) { 19004 19005 enable( gl.BLEND ); 19006 19007 } else { 19008 19009 disable( gl.BLEND ); 19010 19011 } 19012 19013 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { 19014 19015 if ( blending === AdditiveBlending ) { 19016 19017 if ( premultipliedAlpha ) { 19018 19019 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); 19020 gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE ); 19021 19022 } else { 19023 19024 gl.blendEquation( gl.FUNC_ADD ); 19025 gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); 19026 19027 } 19028 19029 } else if ( blending === SubtractiveBlending ) { 19030 19031 if ( premultipliedAlpha ) { 19032 19033 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); 19034 gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA ); 19035 19036 } else { 19037 19038 gl.blendEquation( gl.FUNC_ADD ); 19039 gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); 19040 19041 } 19042 19043 } else if ( blending === MultiplyBlending ) { 19044 19045 if ( premultipliedAlpha ) { 19046 19047 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); 19048 gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); 19049 19050 } else { 19051 19052 gl.blendEquation( gl.FUNC_ADD ); 19053 gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); 19054 19055 } 19056 19057 } else { 19058 19059 if ( premultipliedAlpha ) { 19060 19061 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); 19062 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 19063 19064 } else { 19065 19066 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); 19067 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 19068 19069 } 19070 19071 } 19072 19073 currentBlending = blending; 19074 currentPremultipledAlpha = premultipliedAlpha; 19075 19076 } 19077 19078 if ( blending === CustomBlending ) { 19079 19080 blendEquationAlpha = blendEquationAlpha || blendEquation; 19081 blendSrcAlpha = blendSrcAlpha || blendSrc; 19082 blendDstAlpha = blendDstAlpha || blendDst; 19083 19084 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { 19085 19086 gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); 19087 19088 currentBlendEquation = blendEquation; 19089 currentBlendEquationAlpha = blendEquationAlpha; 19090 19091 } 19092 19093 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { 19094 19095 gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); 19096 19097 currentBlendSrc = blendSrc; 19098 currentBlendDst = blendDst; 19099 currentBlendSrcAlpha = blendSrcAlpha; 19100 currentBlendDstAlpha = blendDstAlpha; 19101 19102 } 19103 19104 } else { 19105 19106 currentBlendEquation = null; 19107 currentBlendSrc = null; 19108 currentBlendDst = null; 19109 currentBlendEquationAlpha = null; 19110 currentBlendSrcAlpha = null; 19111 currentBlendDstAlpha = null; 19112 19113 } 19114 19115 } 19116 19117 // TODO Deprecate 19118 19119 function setColorWrite( colorWrite ) { 19120 19121 colorBuffer.setMask( colorWrite ); 19122 19123 } 19124 19125 function setDepthTest( depthTest ) { 19126 19127 depthBuffer.setTest( depthTest ); 19128 19129 } 19130 19131 function setDepthWrite( depthWrite ) { 19132 19133 depthBuffer.setMask( depthWrite ); 19134 19135 } 19136 19137 function setDepthFunc( depthFunc ) { 19138 19139 depthBuffer.setFunc( depthFunc ); 19140 19141 } 19142 19143 function setStencilTest( stencilTest ) { 19144 19145 stencilBuffer.setTest( stencilTest ); 19146 19147 } 19148 19149 function setStencilWrite( stencilWrite ) { 19150 19151 stencilBuffer.setMask( stencilWrite ); 19152 19153 } 19154 19155 function setStencilFunc( stencilFunc, stencilRef, stencilMask ) { 19156 19157 stencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask ); 19158 19159 } 19160 19161 function setStencilOp( stencilFail, stencilZFail, stencilZPass ) { 19162 19163 stencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass ); 19164 19165 } 19166 19167 // 19168 19169 function setFlipSided( flipSided ) { 19170 19171 if ( currentFlipSided !== flipSided ) { 19172 19173 if ( flipSided ) { 19174 19175 gl.frontFace( gl.CW ); 19176 19177 } else { 19178 19179 gl.frontFace( gl.CCW ); 19180 19181 } 19182 19183 currentFlipSided = flipSided; 19184 19185 } 19186 19187 } 19188 19189 function setCullFace( cullFace ) { 19190 19191 if ( cullFace !== CullFaceNone ) { 19192 19193 enable( gl.CULL_FACE ); 19194 19195 if ( cullFace !== currentCullFace ) { 19196 19197 if ( cullFace === CullFaceBack ) { 19198 19199 gl.cullFace( gl.BACK ); 19200 19201 } else if ( cullFace === CullFaceFront ) { 19202 19203 gl.cullFace( gl.FRONT ); 19204 19205 } else { 19206 19207 gl.cullFace( gl.FRONT_AND_BACK ); 19208 19209 } 19210 19211 } 19212 19213 } else { 19214 19215 disable( gl.CULL_FACE ); 19216 19217 } 19218 19219 currentCullFace = cullFace; 19220 19221 } 19222 19223 function setLineWidth( width ) { 19224 19225 if ( width !== currentLineWidth ) { 19226 19227 if ( lineWidthAvailable ) gl.lineWidth( width ); 19228 19229 currentLineWidth = width; 19230 19231 } 19232 19233 } 19234 19235 function setPolygonOffset( polygonOffset, factor, units ) { 19236 19237 if ( polygonOffset ) { 19238 19239 enable( gl.POLYGON_OFFSET_FILL ); 19240 19241 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { 19242 19243 gl.polygonOffset( factor, units ); 19244 19245 currentPolygonOffsetFactor = factor; 19246 currentPolygonOffsetUnits = units; 19247 19248 } 19249 19250 } else { 19251 19252 disable( gl.POLYGON_OFFSET_FILL ); 19253 19254 } 19255 19256 } 19257 19258 function getScissorTest() { 19259 19260 return currentScissorTest; 19261 19262 } 19263 19264 function setScissorTest( scissorTest ) { 19265 19266 currentScissorTest = scissorTest; 19267 19268 if ( scissorTest ) { 19269 19270 enable( gl.SCISSOR_TEST ); 19271 19272 } else { 19273 19274 disable( gl.SCISSOR_TEST ); 19275 19276 } 19277 19278 } 19279 19280 // texture 19281 19282 function activeTexture( webglSlot ) { 19283 19284 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; 19285 19286 if ( currentTextureSlot !== webglSlot ) { 19287 19288 gl.activeTexture( webglSlot ); 19289 currentTextureSlot = webglSlot; 19290 19291 } 19292 19293 } 19294 19295 function bindTexture( webglType, webglTexture ) { 19296 19297 if ( currentTextureSlot === null ) { 19298 19299 activeTexture(); 19300 19301 } 19302 19303 var boundTexture = currentBoundTextures[ currentTextureSlot ]; 19304 19305 if ( boundTexture === undefined ) { 19306 19307 boundTexture = { type: undefined, texture: undefined }; 19308 currentBoundTextures[ currentTextureSlot ] = boundTexture; 19309 19310 } 19311 19312 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { 19313 19314 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); 19315 19316 boundTexture.type = webglType; 19317 boundTexture.texture = webglTexture; 19318 19319 } 19320 19321 } 19322 19323 function compressedTexImage2D() { 19324 19325 try { 19326 19327 gl.compressedTexImage2D.apply( gl, arguments ); 19328 19329 } catch ( error ) { 19330 19331 console.error( error ); 19332 19333 } 19334 19335 } 19336 19337 function texImage2D() { 19338 19339 try { 19340 19341 gl.texImage2D.apply( gl, arguments ); 19342 19343 } catch ( error ) { 19344 19345 console.error( error ); 19346 19347 } 19348 19349 } 19350 19351 // 19352 19353 function scissor( scissor ) { 19354 19355 if ( currentScissor.equals( scissor ) === false ) { 19356 19357 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); 19358 currentScissor.copy( scissor ); 19359 19360 } 19361 19362 } 19363 19364 function viewport( viewport ) { 19365 19366 if ( currentViewport.equals( viewport ) === false ) { 19367 19368 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); 19369 currentViewport.copy( viewport ); 19370 19371 } 19372 19373 } 19374 19375 // 19376 19377 function reset() { 19378 19379 for ( var i = 0; i < enabledAttributes.length; i ++ ) { 19380 19381 if ( enabledAttributes[ i ] === 1 ) { 19382 19383 gl.disableVertexAttribArray( i ); 19384 enabledAttributes[ i ] = 0; 19385 19386 } 19387 19388 } 19389 19390 capabilities = {}; 19391 19392 compressedTextureFormats = null; 19393 19394 currentTextureSlot = null; 19395 currentBoundTextures = {}; 19396 19397 currentBlending = null; 19398 19399 currentFlipSided = null; 19400 currentCullFace = null; 19401 19402 colorBuffer.reset(); 19403 depthBuffer.reset(); 19404 stencilBuffer.reset(); 19405 19406 } 19407 19408 return { 19409 19410 buffers: { 19411 color: colorBuffer, 19412 depth: depthBuffer, 19413 stencil: stencilBuffer 19414 }, 19415 19416 init: init, 19417 initAttributes: initAttributes, 19418 enableAttribute: enableAttribute, 19419 enableAttributeAndDivisor: enableAttributeAndDivisor, 19420 disableUnusedAttributes: disableUnusedAttributes, 19421 enable: enable, 19422 disable: disable, 19423 getCompressedTextureFormats: getCompressedTextureFormats, 19424 19425 setBlending: setBlending, 19426 19427 setColorWrite: setColorWrite, 19428 setDepthTest: setDepthTest, 19429 setDepthWrite: setDepthWrite, 19430 setDepthFunc: setDepthFunc, 19431 setStencilTest: setStencilTest, 19432 setStencilWrite: setStencilWrite, 19433 setStencilFunc: setStencilFunc, 19434 setStencilOp: setStencilOp, 19435 19436 setFlipSided: setFlipSided, 19437 setCullFace: setCullFace, 19438 19439 setLineWidth: setLineWidth, 19440 setPolygonOffset: setPolygonOffset, 19441 19442 getScissorTest: getScissorTest, 19443 setScissorTest: setScissorTest, 19444 19445 activeTexture: activeTexture, 19446 bindTexture: bindTexture, 19447 compressedTexImage2D: compressedTexImage2D, 19448 texImage2D: texImage2D, 19449 19450 scissor: scissor, 19451 viewport: viewport, 19452 19453 reset: reset 19454 19455 }; 19456 19457 } 19458 19459 /** 19460 * @author mrdoob / http://mrdoob.com/ 19461 */ 19462 19463 function WebGLCapabilities( gl, extensions, parameters ) { 19464 19465 var maxAnisotropy; 19466 19467 function getMaxAnisotropy() { 19468 19469 if ( maxAnisotropy !== undefined ) return maxAnisotropy; 19470 19471 var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 19472 19473 if ( extension !== null ) { 19474 19475 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); 19476 19477 } else { 19478 19479 maxAnisotropy = 0; 19480 19481 } 19482 19483 return maxAnisotropy; 19484 19485 } 19486 19487 function getMaxPrecision( precision ) { 19488 19489 if ( precision === 'highp' ) { 19490 19491 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && 19492 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { 19493 19494 return 'highp'; 19495 19496 } 19497 19498 precision = 'mediump'; 19499 19500 } 19501 19502 if ( precision === 'mediump' ) { 19503 19504 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && 19505 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { 19506 19507 return 'mediump'; 19508 19509 } 19510 19511 } 19512 19513 return 'lowp'; 19514 19515 } 19516 19517 var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; 19518 var maxPrecision = getMaxPrecision( precision ); 19519 19520 if ( maxPrecision !== precision ) { 19521 19522 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); 19523 precision = maxPrecision; 19524 19525 } 19526 19527 var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' ); 19528 19529 var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); 19530 var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); 19531 var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); 19532 var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); 19533 19534 var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 19535 var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); 19536 var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); 19537 var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); 19538 19539 var vertexTextures = maxVertexTextures > 0; 19540 var floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); 19541 var floatVertexTextures = vertexTextures && floatFragmentTextures; 19542 19543 return { 19544 19545 getMaxAnisotropy: getMaxAnisotropy, 19546 getMaxPrecision: getMaxPrecision, 19547 19548 precision: precision, 19549 logarithmicDepthBuffer: logarithmicDepthBuffer, 19550 19551 maxTextures: maxTextures, 19552 maxVertexTextures: maxVertexTextures, 19553 maxTextureSize: maxTextureSize, 19554 maxCubemapSize: maxCubemapSize, 19555 19556 maxAttributes: maxAttributes, 19557 maxVertexUniforms: maxVertexUniforms, 19558 maxVaryings: maxVaryings, 19559 maxFragmentUniforms: maxFragmentUniforms, 19560 19561 vertexTextures: vertexTextures, 19562 floatFragmentTextures: floatFragmentTextures, 19563 floatVertexTextures: floatVertexTextures 19564 19565 }; 19566 19567 } 19568 19569 /** 19570 * @author mrdoob / http://mrdoob.com/ 19571 */ 19572 19573 function WebGLExtensions( gl ) { 19574 19575 var extensions = {}; 19576 19577 return { 19578 19579 get: function ( name ) { 19580 19581 if ( extensions[ name ] !== undefined ) { 19582 19583 return extensions[ name ]; 19584 19585 } 19586 19587 var extension; 19588 19589 switch ( name ) { 19590 19591 case 'WEBGL_depth_texture': 19592 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); 19593 break; 19594 19595 case 'EXT_texture_filter_anisotropic': 19596 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); 19597 break; 19598 19599 case 'WEBGL_compressed_texture_s3tc': 19600 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); 19601 break; 19602 19603 case 'WEBGL_compressed_texture_pvrtc': 19604 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); 19605 break; 19606 19607 case 'WEBGL_compressed_texture_etc1': 19608 extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' ); 19609 break; 19610 19611 default: 19612 extension = gl.getExtension( name ); 19613 19614 } 19615 19616 if ( extension === null ) { 19617 19618 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); 19619 19620 } 19621 19622 extensions[ name ] = extension; 19623 19624 return extension; 19625 19626 } 19627 19628 }; 19629 19630 } 19631 19632 /** 19633 * @author tschw 19634 */ 19635 19636 function WebGLClipping() { 19637 19638 var scope = this, 19639 19640 globalState = null, 19641 numGlobalPlanes = 0, 19642 localClippingEnabled = false, 19643 renderingShadows = false, 19644 19645 plane = new Plane(), 19646 viewNormalMatrix = new Matrix3(), 19647 19648 uniform = { value: null, needsUpdate: false }; 19649 19650 this.uniform = uniform; 19651 this.numPlanes = 0; 19652 this.numIntersection = 0; 19653 19654 this.init = function( planes, enableLocalClipping, camera ) { 19655 19656 var enabled = 19657 planes.length !== 0 || 19658 enableLocalClipping || 19659 // enable state of previous frame - the clipping code has to 19660 // run another frame in order to reset the state: 19661 numGlobalPlanes !== 0 || 19662 localClippingEnabled; 19663 19664 localClippingEnabled = enableLocalClipping; 19665 19666 globalState = projectPlanes( planes, camera, 0 ); 19667 numGlobalPlanes = planes.length; 19668 19669 return enabled; 19670 19671 }; 19672 19673 this.beginShadows = function() { 19674 19675 renderingShadows = true; 19676 projectPlanes( null ); 19677 19678 }; 19679 19680 this.endShadows = function() { 19681 19682 renderingShadows = false; 19683 resetGlobalState(); 19684 19685 }; 19686 19687 this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { 19688 19689 if ( ! localClippingEnabled || 19690 planes === null || planes.length === 0 || 19691 renderingShadows && ! clipShadows ) { 19692 // there's no local clipping 19693 19694 if ( renderingShadows ) { 19695 // there's no global clipping 19696 19697 projectPlanes( null ); 19698 19699 } else { 19700 19701 resetGlobalState(); 19702 } 19703 19704 } else { 19705 19706 var nGlobal = renderingShadows ? 0 : numGlobalPlanes, 19707 lGlobal = nGlobal * 4, 19708 19709 dstArray = cache.clippingState || null; 19710 19711 uniform.value = dstArray; // ensure unique state 19712 19713 dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); 19714 19715 for ( var i = 0; i !== lGlobal; ++ i ) { 19716 19717 dstArray[ i ] = globalState[ i ]; 19718 19719 } 19720 19721 cache.clippingState = dstArray; 19722 this.numIntersection = clipIntersection ? this.numPlanes : 0; 19723 this.numPlanes += nGlobal; 19724 19725 } 19726 19727 19728 }; 19729 19730 function resetGlobalState() { 19731 19732 if ( uniform.value !== globalState ) { 19733 19734 uniform.value = globalState; 19735 uniform.needsUpdate = numGlobalPlanes > 0; 19736 19737 } 19738 19739 scope.numPlanes = numGlobalPlanes; 19740 scope.numIntersection = 0; 19741 19742 } 19743 19744 function projectPlanes( planes, camera, dstOffset, skipTransform ) { 19745 19746 var nPlanes = planes !== null ? planes.length : 0, 19747 dstArray = null; 19748 19749 if ( nPlanes !== 0 ) { 19750 19751 dstArray = uniform.value; 19752 19753 if ( skipTransform !== true || dstArray === null ) { 19754 19755 var flatSize = dstOffset + nPlanes * 4, 19756 viewMatrix = camera.matrixWorldInverse; 19757 19758 viewNormalMatrix.getNormalMatrix( viewMatrix ); 19759 19760 if ( dstArray === null || dstArray.length < flatSize ) { 19761 19762 dstArray = new Float32Array( flatSize ); 19763 19764 } 19765 19766 for ( var i = 0, i4 = dstOffset; 19767 i !== nPlanes; ++ i, i4 += 4 ) { 19768 19769 plane.copy( planes[ i ] ). 19770 applyMatrix4( viewMatrix, viewNormalMatrix ); 19771 19772 plane.normal.toArray( dstArray, i4 ); 19773 dstArray[ i4 + 3 ] = plane.constant; 19774 19775 } 19776 19777 } 19778 19779 uniform.value = dstArray; 19780 uniform.needsUpdate = true; 19781 19782 } 19783 19784 scope.numPlanes = nPlanes; 19785 19786 return dstArray; 19787 19788 } 19789 19790 } 19791 19792 /** 19793 * @author supereggbert / http://www.paulbrunt.co.uk/ 19794 * @author mrdoob / http://mrdoob.com/ 19795 * @author alteredq / http://alteredqualia.com/ 19796 * @author szimek / https://github.com/szimek/ 19797 * @author tschw 19798 */ 19799 19800 function WebGLRenderer( parameters ) { 19801 19802 console.log( 'THREE.WebGLRenderer', REVISION ); 19803 19804 parameters = parameters || {}; 19805 19806 var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), 19807 _context = parameters.context !== undefined ? parameters.context : null, 19808 19809 _alpha = parameters.alpha !== undefined ? parameters.alpha : false, 19810 _depth = parameters.depth !== undefined ? parameters.depth : true, 19811 _stencil = parameters.stencil !== undefined ? parameters.stencil : true, 19812 _antialias = parameters.antialias !== undefined ? parameters.antialias : false, 19813 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, 19814 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false; 19815 19816 var lights = []; 19817 19818 var opaqueObjects = []; 19819 var opaqueObjectsLastIndex = - 1; 19820 var transparentObjects = []; 19821 var transparentObjectsLastIndex = - 1; 19822 19823 var morphInfluences = new Float32Array( 8 ); 19824 19825 var sprites = []; 19826 var lensFlares = []; 19827 19828 // public properties 19829 19830 this.domElement = _canvas; 19831 this.context = null; 19832 19833 // clearing 19834 19835 this.autoClear = true; 19836 this.autoClearColor = true; 19837 this.autoClearDepth = true; 19838 this.autoClearStencil = true; 19839 19840 // scene graph 19841 19842 this.sortObjects = true; 19843 19844 // user-defined clipping 19845 19846 this.clippingPlanes = []; 19847 this.localClippingEnabled = false; 19848 19849 // physically based shading 19850 19851 this.gammaFactor = 2.0; // for backwards compatibility 19852 this.gammaInput = false; 19853 this.gammaOutput = false; 19854 19855 // physical lights 19856 19857 this.physicallyCorrectLights = false; 19858 19859 // tone mapping 19860 19861 this.toneMapping = LinearToneMapping; 19862 this.toneMappingExposure = 1.0; 19863 this.toneMappingWhitePoint = 1.0; 19864 19865 // morphs 19866 19867 this.maxMorphTargets = 8; 19868 this.maxMorphNormals = 4; 19869 19870 // internal properties 19871 19872 var _this = this, 19873 19874 // internal state cache 19875 19876 _currentProgram = null, 19877 _currentRenderTarget = null, 19878 _currentFramebuffer = null, 19879 _currentMaterialId = - 1, 19880 _currentGeometryProgram = '', 19881 _currentCamera = null, 19882 19883 _currentScissor = new Vector4(), 19884 _currentScissorTest = null, 19885 19886 _currentViewport = new Vector4(), 19887 19888 // 19889 19890 _usedTextureUnits = 0, 19891 19892 // 19893 19894 _clearColor = new Color( 0x000000 ), 19895 _clearAlpha = 0, 19896 19897 _width = _canvas.width, 19898 _height = _canvas.height, 19899 19900 _pixelRatio = 1, 19901 19902 _scissor = new Vector4( 0, 0, _width, _height ), 19903 _scissorTest = false, 19904 19905 _viewport = new Vector4( 0, 0, _width, _height ), 19906 19907 // frustum 19908 19909 _frustum = new Frustum(), 19910 19911 // clipping 19912 19913 _clipping = new WebGLClipping(), 19914 _clippingEnabled = false, 19915 _localClippingEnabled = false, 19916 19917 _sphere = new Sphere(), 19918 19919 // camera matrices cache 19920 19921 _projScreenMatrix = new Matrix4(), 19922 19923 _vector3 = new Vector3(), 19924 _matrix4 = new Matrix4(), 19925 _matrix42 = new Matrix4(), 19926 19927 // light arrays cache 19928 19929 _lights = { 19930 19931 hash: '', 19932 19933 ambient: [ 0, 0, 0 ], 19934 directional: [], 19935 directionalShadowMap: [], 19936 directionalShadowMatrix: [], 19937 spot: [], 19938 spotShadowMap: [], 19939 spotShadowMatrix: [], 19940 rectArea: [], 19941 point: [], 19942 pointShadowMap: [], 19943 pointShadowMatrix: [], 19944 hemi: [], 19945 19946 shadows: [] 19947 19948 }, 19949 19950 // info 19951 19952 _infoRender = { 19953 19954 calls: 0, 19955 vertices: 0, 19956 faces: 0, 19957 points: 0 19958 19959 }; 19960 19961 this.info = { 19962 19963 render: _infoRender, 19964 memory: { 19965 19966 geometries: 0, 19967 textures: 0 19968 19969 }, 19970 programs: null 19971 19972 }; 19973 19974 19975 // initialize 19976 19977 var _gl; 19978 19979 try { 19980 19981 var attributes = { 19982 alpha: _alpha, 19983 depth: _depth, 19984 stencil: _stencil, 19985 antialias: _antialias, 19986 premultipliedAlpha: _premultipliedAlpha, 19987 preserveDrawingBuffer: _preserveDrawingBuffer 19988 }; 19989 19990 _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); 19991 19992 if ( _gl === null ) { 19993 19994 if ( _canvas.getContext( 'webgl' ) !== null ) { 19995 19996 throw 'Error creating WebGL context with your selected attributes.'; 19997 19998 } else { 19999 20000 throw 'Error creating WebGL context.'; 20001 20002 } 20003 20004 } 20005 20006 // Some experimental-webgl implementations do not have getShaderPrecisionFormat 20007 20008 if ( _gl.getShaderPrecisionFormat === undefined ) { 20009 20010 _gl.getShaderPrecisionFormat = function () { 20011 20012 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; 20013 20014 }; 20015 20016 } 20017 20018 _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); 20019 20020 } catch ( error ) { 20021 20022 console.error( 'THREE.WebGLRenderer: ' + error ); 20023 20024 } 20025 20026 var extensions = new WebGLExtensions( _gl ); 20027 20028 extensions.get( 'WEBGL_depth_texture' ); 20029 extensions.get( 'OES_texture_float' ); 20030 extensions.get( 'OES_texture_float_linear' ); 20031 extensions.get( 'OES_texture_half_float' ); 20032 extensions.get( 'OES_texture_half_float_linear' ); 20033 extensions.get( 'OES_standard_derivatives' ); 20034 extensions.get( 'ANGLE_instanced_arrays' ); 20035 20036 if ( extensions.get( 'OES_element_index_uint' ) ) { 20037 20038 BufferGeometry.MaxIndex = 4294967296; 20039 20040 } 20041 20042 var capabilities = new WebGLCapabilities( _gl, extensions, parameters ); 20043 20044 var state = new WebGLState( _gl, extensions, paramThreeToGL ); 20045 var properties = new WebGLProperties(); 20046 var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info ); 20047 var objects = new WebGLObjects( _gl, properties, this.info ); 20048 var programCache = new WebGLPrograms( this, capabilities ); 20049 var lightCache = new WebGLLights(); 20050 20051 this.info.programs = programCache.programs; 20052 20053 var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender ); 20054 var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); 20055 20056 // 20057 20058 var backgroundPlaneCamera, backgroundPlaneMesh; 20059 var backgroundBoxCamera, backgroundBoxMesh; 20060 20061 // 20062 20063 function getTargetPixelRatio() { 20064 20065 return _currentRenderTarget === null ? _pixelRatio : 1; 20066 20067 } 20068 20069 function setDefaultGLState() { 20070 20071 state.init(); 20072 20073 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); 20074 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); 20075 20076 state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); 20077 20078 } 20079 20080 function resetGLState() { 20081 20082 _currentProgram = null; 20083 _currentCamera = null; 20084 20085 _currentGeometryProgram = ''; 20086 _currentMaterialId = - 1; 20087 20088 state.reset(); 20089 20090 } 20091 20092 setDefaultGLState(); 20093 20094 this.context = _gl; 20095 this.capabilities = capabilities; 20096 this.extensions = extensions; 20097 this.properties = properties; 20098 this.state = state; 20099 20100 // shadow map 20101 20102 var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities ); 20103 20104 this.shadowMap = shadowMap; 20105 20106 20107 // Plugins 20108 20109 var spritePlugin = new SpritePlugin( this, sprites ); 20110 var lensFlarePlugin = new LensFlarePlugin( this, lensFlares ); 20111 20112 // API 20113 20114 this.getContext = function () { 20115 20116 return _gl; 20117 20118 }; 20119 20120 this.getContextAttributes = function () { 20121 20122 return _gl.getContextAttributes(); 20123 20124 }; 20125 20126 this.forceContextLoss = function () { 20127 20128 extensions.get( 'WEBGL_lose_context' ).loseContext(); 20129 20130 }; 20131 20132 this.getMaxAnisotropy = function () { 20133 20134 return capabilities.getMaxAnisotropy(); 20135 20136 }; 20137 20138 this.getPrecision = function () { 20139 20140 return capabilities.precision; 20141 20142 }; 20143 20144 this.getPixelRatio = function () { 20145 20146 return _pixelRatio; 20147 20148 }; 20149 20150 this.setPixelRatio = function ( value ) { 20151 20152 if ( value === undefined ) return; 20153 20154 _pixelRatio = value; 20155 20156 this.setSize( _viewport.z, _viewport.w, false ); 20157 20158 }; 20159 20160 this.getSize = function () { 20161 20162 return { 20163 width: _width, 20164 height: _height 20165 }; 20166 20167 }; 20168 20169 this.setSize = function ( width, height, updateStyle ) { 20170 20171 _width = width; 20172 _height = height; 20173 20174 _canvas.width = width * _pixelRatio; 20175 _canvas.height = height * _pixelRatio; 20176 20177 if ( updateStyle !== false ) { 20178 20179 _canvas.style.width = width + 'px'; 20180 _canvas.style.height = height + 'px'; 20181 20182 } 20183 20184 this.setViewport( 0, 0, width, height ); 20185 20186 }; 20187 20188 this.setViewport = function ( x, y, width, height ) { 20189 20190 state.viewport( _viewport.set( x, y, width, height ) ); 20191 20192 }; 20193 20194 this.setScissor = function ( x, y, width, height ) { 20195 20196 state.scissor( _scissor.set( x, y, width, height ) ); 20197 20198 }; 20199 20200 this.setScissorTest = function ( boolean ) { 20201 20202 state.setScissorTest( _scissorTest = boolean ); 20203 20204 }; 20205 20206 // Clearing 20207 20208 this.getClearColor = function () { 20209 20210 return _clearColor; 20211 20212 }; 20213 20214 this.setClearColor = function ( color, alpha ) { 20215 20216 _clearColor.set( color ); 20217 20218 _clearAlpha = alpha !== undefined ? alpha : 1; 20219 20220 state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); 20221 20222 }; 20223 20224 this.getClearAlpha = function () { 20225 20226 return _clearAlpha; 20227 20228 }; 20229 20230 this.setClearAlpha = function ( alpha ) { 20231 20232 _clearAlpha = alpha; 20233 20234 state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); 20235 20236 }; 20237 20238 this.clear = function ( color, depth, stencil ) { 20239 20240 var bits = 0; 20241 20242 if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; 20243 if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; 20244 if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; 20245 20246 _gl.clear( bits ); 20247 20248 }; 20249 20250 this.clearColor = function () { 20251 20252 this.clear( true, false, false ); 20253 20254 }; 20255 20256 this.clearDepth = function () { 20257 20258 this.clear( false, true, false ); 20259 20260 }; 20261 20262 this.clearStencil = function () { 20263 20264 this.clear( false, false, true ); 20265 20266 }; 20267 20268 this.clearTarget = function ( renderTarget, color, depth, stencil ) { 20269 20270 this.setRenderTarget( renderTarget ); 20271 this.clear( color, depth, stencil ); 20272 20273 }; 20274 20275 // Reset 20276 20277 this.resetGLState = resetGLState; 20278 20279 this.dispose = function() { 20280 20281 transparentObjects = []; 20282 transparentObjectsLastIndex = -1; 20283 opaqueObjects = []; 20284 opaqueObjectsLastIndex = -1; 20285 20286 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); 20287 20288 }; 20289 20290 // Events 20291 20292 function onContextLost( event ) { 20293 20294 event.preventDefault(); 20295 20296 resetGLState(); 20297 setDefaultGLState(); 20298 20299 properties.clear(); 20300 20301 } 20302 20303 function onMaterialDispose( event ) { 20304 20305 var material = event.target; 20306 20307 material.removeEventListener( 'dispose', onMaterialDispose ); 20308 20309 deallocateMaterial( material ); 20310 20311 } 20312 20313 // Buffer deallocation 20314 20315 function deallocateMaterial( material ) { 20316 20317 releaseMaterialProgramReference( material ); 20318 20319 properties.delete( material ); 20320 20321 } 20322 20323 20324 function releaseMaterialProgramReference( material ) { 20325 20326 var programInfo = properties.get( material ).program; 20327 20328 material.program = undefined; 20329 20330 if ( programInfo !== undefined ) { 20331 20332 programCache.releaseProgram( programInfo ); 20333 20334 } 20335 20336 } 20337 20338 // Buffer rendering 20339 20340 this.renderBufferImmediate = function ( object, program, material ) { 20341 20342 state.initAttributes(); 20343 20344 var buffers = properties.get( object ); 20345 20346 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); 20347 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); 20348 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); 20349 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); 20350 20351 var attributes = program.getAttributes(); 20352 20353 if ( object.hasPositions ) { 20354 20355 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); 20356 _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); 20357 20358 state.enableAttribute( attributes.position ); 20359 _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); 20360 20361 } 20362 20363 if ( object.hasNormals ) { 20364 20365 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); 20366 20367 if ( ! material.isMeshPhongMaterial && 20368 ! material.isMeshStandardMaterial && 20369 ! material.isMeshNormalMaterial && 20370 material.shading === FlatShading ) { 20371 20372 for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { 20373 20374 var array = object.normalArray; 20375 20376 var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; 20377 var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; 20378 var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; 20379 20380 array[ i + 0 ] = nx; 20381 array[ i + 1 ] = ny; 20382 array[ i + 2 ] = nz; 20383 20384 array[ i + 3 ] = nx; 20385 array[ i + 4 ] = ny; 20386 array[ i + 5 ] = nz; 20387 20388 array[ i + 6 ] = nx; 20389 array[ i + 7 ] = ny; 20390 array[ i + 8 ] = nz; 20391 20392 } 20393 20394 } 20395 20396 _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); 20397 20398 state.enableAttribute( attributes.normal ); 20399 20400 _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); 20401 20402 } 20403 20404 if ( object.hasUvs && material.map ) { 20405 20406 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); 20407 _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); 20408 20409 state.enableAttribute( attributes.uv ); 20410 20411 _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); 20412 20413 } 20414 20415 if ( object.hasColors && material.vertexColors !== NoColors ) { 20416 20417 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); 20418 _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); 20419 20420 state.enableAttribute( attributes.color ); 20421 20422 _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); 20423 20424 } 20425 20426 state.disableUnusedAttributes(); 20427 20428 _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); 20429 20430 object.count = 0; 20431 20432 }; 20433 20434 this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { 20435 20436 setMaterial( material ); 20437 20438 var program = setProgram( camera, fog, material, object ); 20439 20440 var updateBuffers = false; 20441 var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe; 20442 20443 if ( geometryProgram !== _currentGeometryProgram ) { 20444 20445 _currentGeometryProgram = geometryProgram; 20446 updateBuffers = true; 20447 20448 } 20449 20450 // morph targets 20451 20452 var morphTargetInfluences = object.morphTargetInfluences; 20453 20454 if ( morphTargetInfluences !== undefined ) { 20455 20456 var activeInfluences = []; 20457 20458 for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { 20459 20460 var influence = morphTargetInfluences[ i ]; 20461 activeInfluences.push( [ influence, i ] ); 20462 20463 } 20464 20465 activeInfluences.sort( absNumericalSort ); 20466 20467 if ( activeInfluences.length > 8 ) { 20468 20469 activeInfluences.length = 8; 20470 20471 } 20472 20473 var morphAttributes = geometry.morphAttributes; 20474 20475 for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) { 20476 20477 var influence = activeInfluences[ i ]; 20478 morphInfluences[ i ] = influence[ 0 ]; 20479 20480 if ( influence[ 0 ] !== 0 ) { 20481 20482 var index = influence[ 1 ]; 20483 20484 if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] ); 20485 if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] ); 20486 20487 } else { 20488 20489 if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i ); 20490 if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i ); 20491 20492 } 20493 20494 } 20495 20496 for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) { 20497 20498 morphInfluences[ i ] = 0.0; 20499 20500 } 20501 20502 program.getUniforms().setValue( 20503 _gl, 'morphTargetInfluences', morphInfluences ); 20504 20505 updateBuffers = true; 20506 20507 } 20508 20509 // 20510 20511 var index = geometry.index; 20512 var position = geometry.attributes.position; 20513 var rangeFactor = 1; 20514 20515 if ( material.wireframe === true ) { 20516 20517 index = objects.getWireframeAttribute( geometry ); 20518 rangeFactor = 2; 20519 20520 } 20521 20522 var renderer; 20523 20524 if ( index !== null ) { 20525 20526 renderer = indexedBufferRenderer; 20527 renderer.setIndex( index ); 20528 20529 } else { 20530 20531 renderer = bufferRenderer; 20532 20533 } 20534 20535 if ( updateBuffers ) { 20536 20537 setupVertexAttributes( material, program, geometry ); 20538 20539 if ( index !== null ) { 20540 20541 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) ); 20542 20543 } 20544 20545 } 20546 20547 // 20548 20549 var dataCount = 0; 20550 20551 if ( index !== null ) { 20552 20553 dataCount = index.count; 20554 20555 } else if ( position !== undefined ) { 20556 20557 dataCount = position.count; 20558 20559 } 20560 20561 var rangeStart = geometry.drawRange.start * rangeFactor; 20562 var rangeCount = geometry.drawRange.count * rangeFactor; 20563 20564 var groupStart = group !== null ? group.start * rangeFactor : 0; 20565 var groupCount = group !== null ? group.count * rangeFactor : Infinity; 20566 20567 var drawStart = Math.max( rangeStart, groupStart ); 20568 var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; 20569 20570 var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); 20571 20572 if ( drawCount === 0 ) return; 20573 20574 // 20575 20576 if ( object.isMesh ) { 20577 20578 if ( material.wireframe === true ) { 20579 20580 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); 20581 renderer.setMode( _gl.LINES ); 20582 20583 } else { 20584 20585 switch ( object.drawMode ) { 20586 20587 case TrianglesDrawMode: 20588 renderer.setMode( _gl.TRIANGLES ); 20589 break; 20590 20591 case TriangleStripDrawMode: 20592 renderer.setMode( _gl.TRIANGLE_STRIP ); 20593 break; 20594 20595 case TriangleFanDrawMode: 20596 renderer.setMode( _gl.TRIANGLE_FAN ); 20597 break; 20598 20599 } 20600 20601 } 20602 20603 20604 } else if ( object.isLine ) { 20605 20606 var lineWidth = material.linewidth; 20607 20608 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material 20609 20610 state.setLineWidth( lineWidth * getTargetPixelRatio() ); 20611 20612 if ( object.isLineSegments ) { 20613 20614 renderer.setMode( _gl.LINES ); 20615 20616 } else { 20617 20618 renderer.setMode( _gl.LINE_STRIP ); 20619 20620 } 20621 20622 } else if ( object.isPoints ) { 20623 20624 renderer.setMode( _gl.POINTS ); 20625 20626 } 20627 20628 if ( geometry && geometry.isInstancedBufferGeometry ) { 20629 20630 if ( geometry.maxInstancedCount > 0 ) { 20631 20632 renderer.renderInstances( geometry, drawStart, drawCount ); 20633 20634 } 20635 20636 } else { 20637 20638 renderer.render( drawStart, drawCount ); 20639 20640 } 20641 20642 }; 20643 20644 function setupVertexAttributes( material, program, geometry, startIndex ) { 20645 20646 var extension; 20647 20648 if ( geometry && geometry.isInstancedBufferGeometry ) { 20649 20650 extension = extensions.get( 'ANGLE_instanced_arrays' ); 20651 20652 if ( extension === null ) { 20653 20654 console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); 20655 return; 20656 20657 } 20658 20659 } 20660 20661 if ( startIndex === undefined ) startIndex = 0; 20662 20663 state.initAttributes(); 20664 20665 var geometryAttributes = geometry.attributes; 20666 20667 var programAttributes = program.getAttributes(); 20668 20669 var materialDefaultAttributeValues = material.defaultAttributeValues; 20670 20671 for ( var name in programAttributes ) { 20672 20673 var programAttribute = programAttributes[ name ]; 20674 20675 if ( programAttribute >= 0 ) { 20676 20677 var geometryAttribute = geometryAttributes[ name ]; 20678 20679 if ( geometryAttribute !== undefined ) { 20680 20681 var normalized = geometryAttribute.normalized; 20682 var size = geometryAttribute.itemSize; 20683 20684 var attributeProperties = objects.getAttributeProperties( geometryAttribute ); 20685 20686 var buffer = attributeProperties.__webglBuffer; 20687 var type = attributeProperties.type; 20688 var bytesPerElement = attributeProperties.bytesPerElement; 20689 20690 if ( geometryAttribute.isInterleavedBufferAttribute ) { 20691 20692 var data = geometryAttribute.data; 20693 var stride = data.stride; 20694 var offset = geometryAttribute.offset; 20695 20696 if ( data && data.isInstancedInterleavedBuffer ) { 20697 20698 state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension ); 20699 20700 if ( geometry.maxInstancedCount === undefined ) { 20701 20702 geometry.maxInstancedCount = data.meshPerAttribute * data.count; 20703 20704 } 20705 20706 } else { 20707 20708 state.enableAttribute( programAttribute ); 20709 20710 } 20711 20712 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); 20713 _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement ); 20714 20715 } else { 20716 20717 if ( geometryAttribute.isInstancedBufferAttribute ) { 20718 20719 state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension ); 20720 20721 if ( geometry.maxInstancedCount === undefined ) { 20722 20723 geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; 20724 20725 } 20726 20727 } else { 20728 20729 state.enableAttribute( programAttribute ); 20730 20731 } 20732 20733 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); 20734 _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement ); 20735 20736 } 20737 20738 } else if ( materialDefaultAttributeValues !== undefined ) { 20739 20740 var value = materialDefaultAttributeValues[ name ]; 20741 20742 if ( value !== undefined ) { 20743 20744 switch ( value.length ) { 20745 20746 case 2: 20747 _gl.vertexAttrib2fv( programAttribute, value ); 20748 break; 20749 20750 case 3: 20751 _gl.vertexAttrib3fv( programAttribute, value ); 20752 break; 20753 20754 case 4: 20755 _gl.vertexAttrib4fv( programAttribute, value ); 20756 break; 20757 20758 default: 20759 _gl.vertexAttrib1fv( programAttribute, value ); 20760 20761 } 20762 20763 } 20764 20765 } 20766 20767 } 20768 20769 } 20770 20771 state.disableUnusedAttributes(); 20772 20773 } 20774 20775 // Sorting 20776 20777 function absNumericalSort( a, b ) { 20778 20779 return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] ); 20780 20781 } 20782 20783 function painterSortStable( a, b ) { 20784 20785 if ( a.object.renderOrder !== b.object.renderOrder ) { 20786 20787 return a.object.renderOrder - b.object.renderOrder; 20788 20789 } else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) { 20790 20791 return a.material.program.id - b.material.program.id; 20792 20793 } else if ( a.material.id !== b.material.id ) { 20794 20795 return a.material.id - b.material.id; 20796 20797 } else if ( a.z !== b.z ) { 20798 20799 return a.z - b.z; 20800 20801 } else { 20802 20803 return a.id - b.id; 20804 20805 } 20806 20807 } 20808 20809 function reversePainterSortStable( a, b ) { 20810 20811 if ( a.object.renderOrder !== b.object.renderOrder ) { 20812 20813 return a.object.renderOrder - b.object.renderOrder; 20814 20815 } if ( a.z !== b.z ) { 20816 20817 return b.z - a.z; 20818 20819 } else { 20820 20821 return a.id - b.id; 20822 20823 } 20824 20825 } 20826 20827 // Rendering 20828 20829 this.render = function ( scene, camera, renderTarget, forceClear ) { 20830 20831 if ( camera !== undefined && camera.isCamera !== true ) { 20832 20833 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); 20834 return; 20835 20836 } 20837 20838 // reset caching for this frame 20839 20840 _currentGeometryProgram = ''; 20841 _currentMaterialId = - 1; 20842 _currentCamera = null; 20843 20844 // update scene graph 20845 20846 if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); 20847 20848 // update camera matrices and frustum 20849 20850 if ( camera.parent === null ) camera.updateMatrixWorld(); 20851 20852 camera.matrixWorldInverse.getInverse( camera.matrixWorld ); 20853 20854 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 20855 _frustum.setFromMatrix( _projScreenMatrix ); 20856 20857 lights.length = 0; 20858 20859 opaqueObjectsLastIndex = - 1; 20860 transparentObjectsLastIndex = - 1; 20861 20862 sprites.length = 0; 20863 lensFlares.length = 0; 20864 20865 _localClippingEnabled = this.localClippingEnabled; 20866 _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); 20867 20868 projectObject( scene, camera ); 20869 20870 opaqueObjects.length = opaqueObjectsLastIndex + 1; 20871 transparentObjects.length = transparentObjectsLastIndex + 1; 20872 20873 if ( _this.sortObjects === true ) { 20874 20875 opaqueObjects.sort( painterSortStable ); 20876 transparentObjects.sort( reversePainterSortStable ); 20877 20878 } 20879 20880 // 20881 20882 if ( _clippingEnabled ) _clipping.beginShadows(); 20883 20884 setupShadows( lights ); 20885 20886 shadowMap.render( scene, camera ); 20887 20888 setupLights( lights, camera ); 20889 20890 if ( _clippingEnabled ) _clipping.endShadows(); 20891 20892 // 20893 20894 _infoRender.calls = 0; 20895 _infoRender.vertices = 0; 20896 _infoRender.faces = 0; 20897 _infoRender.points = 0; 20898 20899 if ( renderTarget === undefined ) { 20900 20901 renderTarget = null; 20902 20903 } 20904 20905 this.setRenderTarget( renderTarget ); 20906 20907 // 20908 20909 var background = scene.background; 20910 20911 if ( background === null ) { 20912 20913 state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); 20914 20915 } else if ( background && background.isColor ) { 20916 20917 state.buffers.color.setClear( background.r, background.g, background.b, 1, _premultipliedAlpha ); 20918 forceClear = true; 20919 20920 } 20921 20922 if ( this.autoClear || forceClear ) { 20923 20924 this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); 20925 20926 } 20927 20928 if ( background && background.isCubeTexture ) { 20929 20930 if ( backgroundBoxCamera === undefined ) { 20931 20932 backgroundBoxCamera = new PerspectiveCamera(); 20933 20934 backgroundBoxMesh = new Mesh( 20935 new BoxBufferGeometry( 5, 5, 5 ), 20936 new ShaderMaterial( { 20937 uniforms: ShaderLib.cube.uniforms, 20938 vertexShader: ShaderLib.cube.vertexShader, 20939 fragmentShader: ShaderLib.cube.fragmentShader, 20940 side: BackSide, 20941 depthTest: false, 20942 depthWrite: false, 20943 fog: false 20944 } ) 20945 ); 20946 20947 } 20948 20949 backgroundBoxCamera.projectionMatrix.copy( camera.projectionMatrix ); 20950 20951 backgroundBoxCamera.matrixWorld.extractRotation( camera.matrixWorld ); 20952 backgroundBoxCamera.matrixWorldInverse.getInverse( backgroundBoxCamera.matrixWorld ); 20953 20954 20955 backgroundBoxMesh.material.uniforms[ "tCube" ].value = background; 20956 backgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundBoxCamera.matrixWorldInverse, backgroundBoxMesh.matrixWorld ); 20957 20958 objects.update( backgroundBoxMesh ); 20959 20960 _this.renderBufferDirect( backgroundBoxCamera, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null ); 20961 20962 } else if ( background && background.isTexture ) { 20963 20964 if ( backgroundPlaneCamera === undefined ) { 20965 20966 backgroundPlaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); 20967 20968 backgroundPlaneMesh = new Mesh( 20969 new PlaneBufferGeometry( 2, 2 ), 20970 new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } ) 20971 ); 20972 20973 } 20974 20975 backgroundPlaneMesh.material.map = background; 20976 20977 objects.update( backgroundPlaneMesh ); 20978 20979 _this.renderBufferDirect( backgroundPlaneCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null ); 20980 20981 } 20982 20983 // 20984 20985 if ( scene.overrideMaterial ) { 20986 20987 var overrideMaterial = scene.overrideMaterial; 20988 20989 renderObjects( opaqueObjects, scene, camera, overrideMaterial ); 20990 renderObjects( transparentObjects, scene, camera, overrideMaterial ); 20991 20992 } else { 20993 20994 // opaque pass (front-to-back order) 20995 20996 state.setBlending( NoBlending ); 20997 renderObjects( opaqueObjects, scene, camera ); 20998 20999 // transparent pass (back-to-front order) 21000 21001 renderObjects( transparentObjects, scene, camera ); 21002 21003 } 21004 21005 // custom render plugins (post pass) 21006 21007 spritePlugin.render( scene, camera ); 21008 lensFlarePlugin.render( scene, camera, _currentViewport ); 21009 21010 // Generate mipmap if we're using any kind of mipmap filtering 21011 21012 if ( renderTarget ) { 21013 21014 textures.updateRenderTargetMipmap( renderTarget ); 21015 21016 } 21017 21018 // Ensure depth buffer writing is enabled so it can be cleared on next render 21019 21020 state.setDepthTest( true ); 21021 state.setDepthWrite( true ); 21022 state.setColorWrite( true ); 21023 21024 // _gl.finish(); 21025 21026 }; 21027 21028 function pushRenderItem( object, geometry, material, z, group ) { 21029 21030 var array, index; 21031 21032 // allocate the next position in the appropriate array 21033 21034 if ( material.transparent ) { 21035 21036 array = transparentObjects; 21037 index = ++ transparentObjectsLastIndex; 21038 21039 } else { 21040 21041 array = opaqueObjects; 21042 index = ++ opaqueObjectsLastIndex; 21043 21044 } 21045 21046 // recycle existing render item or grow the array 21047 21048 var renderItem = array[ index ]; 21049 21050 if ( renderItem !== undefined ) { 21051 21052 renderItem.id = object.id; 21053 renderItem.object = object; 21054 renderItem.geometry = geometry; 21055 renderItem.material = material; 21056 renderItem.z = _vector3.z; 21057 renderItem.group = group; 21058 21059 } else { 21060 21061 renderItem = { 21062 id: object.id, 21063 object: object, 21064 geometry: geometry, 21065 material: material, 21066 z: _vector3.z, 21067 group: group 21068 }; 21069 21070 // assert( index === array.length ); 21071 array.push( renderItem ); 21072 21073 } 21074 21075 } 21076 21077 // TODO Duplicated code (Frustum) 21078 21079 function isObjectViewable( object ) { 21080 21081 var geometry = object.geometry; 21082 21083 if ( geometry.boundingSphere === null ) 21084 geometry.computeBoundingSphere(); 21085 21086 _sphere.copy( geometry.boundingSphere ). 21087 applyMatrix4( object.matrixWorld ); 21088 21089 return isSphereViewable( _sphere ); 21090 21091 } 21092 21093 function isSpriteViewable( sprite ) { 21094 21095 _sphere.center.set( 0, 0, 0 ); 21096 _sphere.radius = 0.7071067811865476; 21097 _sphere.applyMatrix4( sprite.matrixWorld ); 21098 21099 return isSphereViewable( _sphere ); 21100 21101 } 21102 21103 function isSphereViewable( sphere ) { 21104 21105 if ( ! _frustum.intersectsSphere( sphere ) ) return false; 21106 21107 var numPlanes = _clipping.numPlanes; 21108 21109 if ( numPlanes === 0 ) return true; 21110 21111 var planes = _this.clippingPlanes, 21112 21113 center = sphere.center, 21114 negRad = - sphere.radius, 21115 i = 0; 21116 21117 do { 21118 21119 // out when deeper than radius in the negative halfspace 21120 if ( planes[ i ].distanceToPoint( center ) < negRad ) return false; 21121 21122 } while ( ++ i !== numPlanes ); 21123 21124 return true; 21125 21126 } 21127 21128 function projectObject( object, camera ) { 21129 21130 if ( object.visible === false ) return; 21131 21132 var visible = ( object.layers.mask & camera.layers.mask ) !== 0; 21133 21134 if ( visible ) { 21135 21136 if ( object.isLight ) { 21137 21138 lights.push( object ); 21139 21140 } else if ( object.isSprite ) { 21141 21142 if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) { 21143 21144 sprites.push( object ); 21145 21146 } 21147 21148 } else if ( object.isLensFlare ) { 21149 21150 lensFlares.push( object ); 21151 21152 } else if ( object.isImmediateRenderObject ) { 21153 21154 if ( _this.sortObjects === true ) { 21155 21156 _vector3.setFromMatrixPosition( object.matrixWorld ); 21157 _vector3.applyMatrix4( _projScreenMatrix ); 21158 21159 } 21160 21161 pushRenderItem( object, null, object.material, _vector3.z, null ); 21162 21163 } else if ( object.isMesh || object.isLine || object.isPoints ) { 21164 21165 if ( object.isSkinnedMesh ) { 21166 21167 object.skeleton.update(); 21168 21169 } 21170 21171 if ( object.frustumCulled === false || isObjectViewable( object ) === true ) { 21172 21173 var material = object.material; 21174 21175 if ( material.visible === true ) { 21176 21177 if ( _this.sortObjects === true ) { 21178 21179 _vector3.setFromMatrixPosition( object.matrixWorld ); 21180 _vector3.applyMatrix4( _projScreenMatrix ); 21181 21182 } 21183 21184 var geometry = objects.update( object ); 21185 21186 if ( material.isMultiMaterial ) { 21187 21188 var groups = geometry.groups; 21189 var materials = material.materials; 21190 21191 for ( var i = 0, l = groups.length; i < l; i ++ ) { 21192 21193 var group = groups[ i ]; 21194 var groupMaterial = materials[ group.materialIndex ]; 21195 21196 if ( groupMaterial.visible === true ) { 21197 21198 pushRenderItem( object, geometry, groupMaterial, _vector3.z, group ); 21199 21200 } 21201 21202 } 21203 21204 } else { 21205 21206 pushRenderItem( object, geometry, material, _vector3.z, null ); 21207 21208 } 21209 21210 } 21211 21212 } 21213 21214 } 21215 21216 } 21217 21218 var children = object.children; 21219 21220 for ( var i = 0, l = children.length; i < l; i ++ ) { 21221 21222 projectObject( children[ i ], camera ); 21223 21224 } 21225 21226 } 21227 21228 function renderObjects( renderList, scene, camera, overrideMaterial ) { 21229 21230 for ( var i = 0, l = renderList.length; i < l; i ++ ) { 21231 21232 var renderItem = renderList[ i ]; 21233 21234 var object = renderItem.object; 21235 var geometry = renderItem.geometry; 21236 var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; 21237 var group = renderItem.group; 21238 21239 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); 21240 object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); 21241 21242 object.onBeforeRender( _this, scene, camera, geometry, material, group ); 21243 21244 if ( object.isImmediateRenderObject ) { 21245 21246 setMaterial( material ); 21247 21248 var program = setProgram( camera, scene.fog, material, object ); 21249 21250 _currentGeometryProgram = ''; 21251 21252 object.render( function ( object ) { 21253 21254 _this.renderBufferImmediate( object, program, material ); 21255 21256 } ); 21257 21258 } else { 21259 21260 _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); 21261 21262 } 21263 21264 object.onAfterRender( _this, scene, camera, geometry, material, group ); 21265 21266 21267 } 21268 21269 } 21270 21271 function initMaterial( material, fog, object ) { 21272 21273 var materialProperties = properties.get( material ); 21274 21275 var parameters = programCache.getParameters( 21276 material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object ); 21277 21278 var code = programCache.getProgramCode( material, parameters ); 21279 21280 var program = materialProperties.program; 21281 var programChange = true; 21282 21283 if ( program === undefined ) { 21284 21285 // new material 21286 material.addEventListener( 'dispose', onMaterialDispose ); 21287 21288 } else if ( program.code !== code ) { 21289 21290 // changed glsl or parameters 21291 releaseMaterialProgramReference( material ); 21292 21293 } else if ( parameters.shaderID !== undefined ) { 21294 21295 // same glsl and uniform list 21296 return; 21297 21298 } else { 21299 21300 // only rebuild uniform list 21301 programChange = false; 21302 21303 } 21304 21305 if ( programChange ) { 21306 21307 if ( parameters.shaderID ) { 21308 21309 var shader = ShaderLib[ parameters.shaderID ]; 21310 21311 materialProperties.__webglShader = { 21312 name: material.type, 21313 uniforms: UniformsUtils.clone( shader.uniforms ), 21314 vertexShader: shader.vertexShader, 21315 fragmentShader: shader.fragmentShader 21316 }; 21317 21318 } else { 21319 21320 materialProperties.__webglShader = { 21321 name: material.type, 21322 uniforms: material.uniforms, 21323 vertexShader: material.vertexShader, 21324 fragmentShader: material.fragmentShader 21325 }; 21326 21327 } 21328 21329 material.__webglShader = materialProperties.__webglShader; 21330 21331 program = programCache.acquireProgram( material, parameters, code ); 21332 21333 materialProperties.program = program; 21334 material.program = program; 21335 21336 } 21337 21338 var attributes = program.getAttributes(); 21339 21340 if ( material.morphTargets ) { 21341 21342 material.numSupportedMorphTargets = 0; 21343 21344 for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { 21345 21346 if ( attributes[ 'morphTarget' + i ] >= 0 ) { 21347 21348 material.numSupportedMorphTargets ++; 21349 21350 } 21351 21352 } 21353 21354 } 21355 21356 if ( material.morphNormals ) { 21357 21358 material.numSupportedMorphNormals = 0; 21359 21360 for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { 21361 21362 if ( attributes[ 'morphNormal' + i ] >= 0 ) { 21363 21364 material.numSupportedMorphNormals ++; 21365 21366 } 21367 21368 } 21369 21370 } 21371 21372 var uniforms = materialProperties.__webglShader.uniforms; 21373 21374 if ( ! material.isShaderMaterial && 21375 ! material.isRawShaderMaterial || 21376 material.clipping === true ) { 21377 21378 materialProperties.numClippingPlanes = _clipping.numPlanes; 21379 materialProperties.numIntersection = _clipping.numIntersection; 21380 uniforms.clippingPlanes = _clipping.uniform; 21381 21382 } 21383 21384 materialProperties.fog = fog; 21385 21386 // store the light setup it was created for 21387 21388 materialProperties.lightsHash = _lights.hash; 21389 21390 if ( material.lights ) { 21391 21392 // wire up the material to this renderer's lighting state 21393 21394 uniforms.ambientLightColor.value = _lights.ambient; 21395 uniforms.directionalLights.value = _lights.directional; 21396 uniforms.spotLights.value = _lights.spot; 21397 uniforms.rectAreaLights.value = _lights.rectArea; 21398 uniforms.pointLights.value = _lights.point; 21399 uniforms.hemisphereLights.value = _lights.hemi; 21400 21401 uniforms.directionalShadowMap.value = _lights.directionalShadowMap; 21402 uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix; 21403 uniforms.spotShadowMap.value = _lights.spotShadowMap; 21404 uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix; 21405 uniforms.pointShadowMap.value = _lights.pointShadowMap; 21406 uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix; 21407 // TODO (abelnation): add area lights shadow info to uniforms 21408 21409 } 21410 21411 var progUniforms = materialProperties.program.getUniforms(), 21412 uniformsList = 21413 WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); 21414 21415 materialProperties.uniformsList = uniformsList; 21416 21417 } 21418 21419 function setMaterial( material ) { 21420 21421 material.side === DoubleSide 21422 ? state.disable( _gl.CULL_FACE ) 21423 : state.enable( _gl.CULL_FACE ); 21424 21425 state.setFlipSided( material.side === BackSide ); 21426 21427 material.transparent === true 21428 ? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) 21429 : state.setBlending( NoBlending ); 21430 21431 state.setDepthFunc( material.depthFunc ); 21432 state.setDepthTest( material.depthTest ); 21433 state.setDepthWrite( material.depthWrite ); 21434 state.setColorWrite( material.colorWrite ); 21435 state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); 21436 21437 } 21438 21439 function setProgram( camera, fog, material, object ) { 21440 21441 _usedTextureUnits = 0; 21442 21443 var materialProperties = properties.get( material ); 21444 21445 if ( _clippingEnabled ) { 21446 21447 if ( _localClippingEnabled || camera !== _currentCamera ) { 21448 21449 var useCache = 21450 camera === _currentCamera && 21451 material.id === _currentMaterialId; 21452 21453 // we might want to call this function with some ClippingGroup 21454 // object instead of the material, once it becomes feasible 21455 // (#8465, #8379) 21456 _clipping.setState( 21457 material.clippingPlanes, material.clipIntersection, material.clipShadows, 21458 camera, materialProperties, useCache ); 21459 21460 } 21461 21462 } 21463 21464 if ( material.needsUpdate === false ) { 21465 21466 if ( materialProperties.program === undefined ) { 21467 21468 material.needsUpdate = true; 21469 21470 } else if ( material.fog && materialProperties.fog !== fog ) { 21471 21472 material.needsUpdate = true; 21473 21474 } else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) { 21475 21476 material.needsUpdate = true; 21477 21478 } else if ( materialProperties.numClippingPlanes !== undefined && 21479 ( materialProperties.numClippingPlanes !== _clipping.numPlanes || 21480 materialProperties.numIntersection !== _clipping.numIntersection ) ) { 21481 21482 material.needsUpdate = true; 21483 21484 } 21485 21486 } 21487 21488 if ( material.needsUpdate ) { 21489 21490 initMaterial( material, fog, object ); 21491 material.needsUpdate = false; 21492 21493 } 21494 21495 var refreshProgram = false; 21496 var refreshMaterial = false; 21497 var refreshLights = false; 21498 21499 var program = materialProperties.program, 21500 p_uniforms = program.getUniforms(), 21501 m_uniforms = materialProperties.__webglShader.uniforms; 21502 21503 if ( program.id !== _currentProgram ) { 21504 21505 _gl.useProgram( program.program ); 21506 _currentProgram = program.id; 21507 21508 refreshProgram = true; 21509 refreshMaterial = true; 21510 refreshLights = true; 21511 21512 } 21513 21514 if ( material.id !== _currentMaterialId ) { 21515 21516 _currentMaterialId = material.id; 21517 21518 refreshMaterial = true; 21519 21520 } 21521 21522 if ( refreshProgram || camera !== _currentCamera ) { 21523 21524 p_uniforms.set( _gl, camera, 'projectionMatrix' ); 21525 21526 if ( capabilities.logarithmicDepthBuffer ) { 21527 21528 p_uniforms.setValue( _gl, 'logDepthBufFC', 21529 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); 21530 21531 } 21532 21533 21534 if ( camera !== _currentCamera ) { 21535 21536 _currentCamera = camera; 21537 21538 // lighting uniforms depend on the camera so enforce an update 21539 // now, in case this material supports lights - or later, when 21540 // the next material that does gets activated: 21541 21542 refreshMaterial = true; // set to true on material change 21543 refreshLights = true; // remains set until update done 21544 21545 } 21546 21547 // load material specific uniforms 21548 // (shader material also gets them for the sake of genericity) 21549 21550 if ( material.isShaderMaterial || 21551 material.isMeshPhongMaterial || 21552 material.isMeshStandardMaterial || 21553 material.envMap ) { 21554 21555 var uCamPos = p_uniforms.map.cameraPosition; 21556 21557 if ( uCamPos !== undefined ) { 21558 21559 uCamPos.setValue( _gl, 21560 _vector3.setFromMatrixPosition( camera.matrixWorld ) ); 21561 21562 } 21563 21564 } 21565 21566 if ( material.isMeshPhongMaterial || 21567 material.isMeshLambertMaterial || 21568 material.isMeshBasicMaterial || 21569 material.isMeshStandardMaterial || 21570 material.isShaderMaterial || 21571 material.skinning ) { 21572 21573 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); 21574 21575 } 21576 21577 p_uniforms.set( _gl, _this, 'toneMappingExposure' ); 21578 p_uniforms.set( _gl, _this, 'toneMappingWhitePoint' ); 21579 21580 } 21581 21582 // skinning uniforms must be set even if material didn't change 21583 // auto-setting of texture unit for bone texture must go before other textures 21584 // not sure why, but otherwise weird things happen 21585 21586 if ( material.skinning ) { 21587 21588 p_uniforms.setOptional( _gl, object, 'bindMatrix' ); 21589 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); 21590 21591 var skeleton = object.skeleton; 21592 21593 if ( skeleton ) { 21594 21595 if ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) { 21596 21597 p_uniforms.set( _gl, skeleton, 'boneTexture' ); 21598 p_uniforms.set( _gl, skeleton, 'boneTextureWidth' ); 21599 p_uniforms.set( _gl, skeleton, 'boneTextureHeight' ); 21600 21601 } else { 21602 21603 p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); 21604 21605 } 21606 21607 } 21608 21609 } 21610 21611 if ( refreshMaterial ) { 21612 21613 if ( material.lights ) { 21614 21615 // the current material requires lighting info 21616 21617 // note: all lighting uniforms are always set correctly 21618 // they simply reference the renderer's state for their 21619 // values 21620 // 21621 // use the current material's .needsUpdate flags to set 21622 // the GL state when required 21623 21624 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); 21625 21626 } 21627 21628 // refresh uniforms common to several materials 21629 21630 if ( fog && material.fog ) { 21631 21632 refreshUniformsFog( m_uniforms, fog ); 21633 21634 } 21635 21636 if ( material.isMeshBasicMaterial || 21637 material.isMeshLambertMaterial || 21638 material.isMeshPhongMaterial || 21639 material.isMeshStandardMaterial || 21640 material.isMeshNormalMaterial || 21641 material.isMeshDepthMaterial ) { 21642 21643 refreshUniformsCommon( m_uniforms, material ); 21644 21645 } 21646 21647 // refresh single material specific uniforms 21648 21649 if ( material.isLineBasicMaterial ) { 21650 21651 refreshUniformsLine( m_uniforms, material ); 21652 21653 } else if ( material.isLineDashedMaterial ) { 21654 21655 refreshUniformsLine( m_uniforms, material ); 21656 refreshUniformsDash( m_uniforms, material ); 21657 21658 } else if ( material.isPointsMaterial ) { 21659 21660 refreshUniformsPoints( m_uniforms, material ); 21661 21662 } else if ( material.isMeshLambertMaterial ) { 21663 21664 refreshUniformsLambert( m_uniforms, material ); 21665 21666 } else if ( material.isMeshToonMaterial ) { 21667 21668 refreshUniformsToon( m_uniforms, material ); 21669 21670 } else if ( material.isMeshPhongMaterial ) { 21671 21672 refreshUniformsPhong( m_uniforms, material ); 21673 21674 } else if ( material.isMeshPhysicalMaterial ) { 21675 21676 refreshUniformsPhysical( m_uniforms, material ); 21677 21678 } else if ( material.isMeshStandardMaterial ) { 21679 21680 refreshUniformsStandard( m_uniforms, material ); 21681 21682 } else if ( material.isMeshDepthMaterial ) { 21683 21684 if ( material.displacementMap ) { 21685 21686 m_uniforms.displacementMap.value = material.displacementMap; 21687 m_uniforms.displacementScale.value = material.displacementScale; 21688 m_uniforms.displacementBias.value = material.displacementBias; 21689 21690 } 21691 21692 } else if ( material.isMeshNormalMaterial ) { 21693 21694 refreshUniformsNormal( m_uniforms, material ); 21695 21696 } 21697 21698 // RectAreaLight Texture 21699 // TODO (mrdoob): Find a nicer implementation 21700 21701 if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = THREE.UniformsLib.LTC_MAT_TEXTURE; 21702 if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = THREE.UniformsLib.LTC_MAG_TEXTURE; 21703 21704 WebGLUniforms.upload( 21705 _gl, materialProperties.uniformsList, m_uniforms, _this ); 21706 21707 } 21708 21709 21710 // common matrices 21711 21712 p_uniforms.set( _gl, object, 'modelViewMatrix' ); 21713 p_uniforms.set( _gl, object, 'normalMatrix' ); 21714 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); 21715 21716 return program; 21717 21718 } 21719 21720 // Uniforms (refresh uniforms objects) 21721 21722 function refreshUniformsCommon( uniforms, material ) { 21723 21724 uniforms.opacity.value = material.opacity; 21725 21726 uniforms.diffuse.value = material.color; 21727 21728 if ( material.emissive ) { 21729 21730 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); 21731 21732 } 21733 21734 uniforms.map.value = material.map; 21735 uniforms.specularMap.value = material.specularMap; 21736 uniforms.alphaMap.value = material.alphaMap; 21737 21738 if ( material.lightMap ) { 21739 21740 uniforms.lightMap.value = material.lightMap; 21741 uniforms.lightMapIntensity.value = material.lightMapIntensity; 21742 21743 } 21744 21745 if ( material.aoMap ) { 21746 21747 uniforms.aoMap.value = material.aoMap; 21748 uniforms.aoMapIntensity.value = material.aoMapIntensity; 21749 21750 } 21751 21752 // uv repeat and offset setting priorities 21753 // 1. color map 21754 // 2. specular map 21755 // 3. normal map 21756 // 4. bump map 21757 // 5. alpha map 21758 // 6. emissive map 21759 21760 var uvScaleMap; 21761 21762 if ( material.map ) { 21763 21764 uvScaleMap = material.map; 21765 21766 } else if ( material.specularMap ) { 21767 21768 uvScaleMap = material.specularMap; 21769 21770 } else if ( material.displacementMap ) { 21771 21772 uvScaleMap = material.displacementMap; 21773 21774 } else if ( material.normalMap ) { 21775 21776 uvScaleMap = material.normalMap; 21777 21778 } else if ( material.bumpMap ) { 21779 21780 uvScaleMap = material.bumpMap; 21781 21782 } else if ( material.roughnessMap ) { 21783 21784 uvScaleMap = material.roughnessMap; 21785 21786 } else if ( material.metalnessMap ) { 21787 21788 uvScaleMap = material.metalnessMap; 21789 21790 } else if ( material.alphaMap ) { 21791 21792 uvScaleMap = material.alphaMap; 21793 21794 } else if ( material.emissiveMap ) { 21795 21796 uvScaleMap = material.emissiveMap; 21797 21798 } 21799 21800 if ( uvScaleMap !== undefined ) { 21801 21802 // backwards compatibility 21803 if ( uvScaleMap.isWebGLRenderTarget ) { 21804 21805 uvScaleMap = uvScaleMap.texture; 21806 21807 } 21808 21809 var offset = uvScaleMap.offset; 21810 var repeat = uvScaleMap.repeat; 21811 21812 uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); 21813 21814 } 21815 21816 uniforms.envMap.value = material.envMap; 21817 21818 // don't flip CubeTexture envMaps, flip everything else: 21819 // WebGLRenderTargetCube will be flipped for backwards compatibility 21820 // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture 21821 // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future 21822 uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1; 21823 21824 uniforms.reflectivity.value = material.reflectivity; 21825 uniforms.refractionRatio.value = material.refractionRatio; 21826 21827 } 21828 21829 function refreshUniformsLine( uniforms, material ) { 21830 21831 uniforms.diffuse.value = material.color; 21832 uniforms.opacity.value = material.opacity; 21833 21834 } 21835 21836 function refreshUniformsDash( uniforms, material ) { 21837 21838 uniforms.dashSize.value = material.dashSize; 21839 uniforms.totalSize.value = material.dashSize + material.gapSize; 21840 uniforms.scale.value = material.scale; 21841 21842 } 21843 21844 function refreshUniformsPoints( uniforms, material ) { 21845 21846 uniforms.diffuse.value = material.color; 21847 uniforms.opacity.value = material.opacity; 21848 uniforms.size.value = material.size * _pixelRatio; 21849 uniforms.scale.value = _height * 0.5; 21850 21851 uniforms.map.value = material.map; 21852 21853 if ( material.map !== null ) { 21854 21855 var offset = material.map.offset; 21856 var repeat = material.map.repeat; 21857 21858 uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); 21859 21860 } 21861 21862 } 21863 21864 function refreshUniformsFog( uniforms, fog ) { 21865 21866 uniforms.fogColor.value = fog.color; 21867 21868 if ( fog.isFog ) { 21869 21870 uniforms.fogNear.value = fog.near; 21871 uniforms.fogFar.value = fog.far; 21872 21873 } else if ( fog.isFogExp2 ) { 21874 21875 uniforms.fogDensity.value = fog.density; 21876 21877 } 21878 21879 } 21880 21881 function refreshUniformsLambert( uniforms, material ) { 21882 21883 if ( material.emissiveMap ) { 21884 21885 uniforms.emissiveMap.value = material.emissiveMap; 21886 21887 } 21888 21889 } 21890 21891 function refreshUniformsPhong( uniforms, material ) { 21892 21893 uniforms.specular.value = material.specular; 21894 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) 21895 21896 if ( material.emissiveMap ) { 21897 21898 uniforms.emissiveMap.value = material.emissiveMap; 21899 21900 } 21901 21902 if ( material.bumpMap ) { 21903 21904 uniforms.bumpMap.value = material.bumpMap; 21905 uniforms.bumpScale.value = material.bumpScale; 21906 21907 } 21908 21909 if ( material.normalMap ) { 21910 21911 uniforms.normalMap.value = material.normalMap; 21912 uniforms.normalScale.value.copy( material.normalScale ); 21913 21914 } 21915 21916 if ( material.displacementMap ) { 21917 21918 uniforms.displacementMap.value = material.displacementMap; 21919 uniforms.displacementScale.value = material.displacementScale; 21920 uniforms.displacementBias.value = material.displacementBias; 21921 21922 } 21923 21924 } 21925 21926 function refreshUniformsToon( uniforms, material ) { 21927 21928 refreshUniformsPhong( uniforms, material ); 21929 21930 if ( material.gradientMap ) { 21931 21932 uniforms.gradientMap.value = material.gradientMap; 21933 21934 } 21935 21936 } 21937 21938 function refreshUniformsStandard( uniforms, material ) { 21939 21940 uniforms.roughness.value = material.roughness; 21941 uniforms.metalness.value = material.metalness; 21942 21943 if ( material.roughnessMap ) { 21944 21945 uniforms.roughnessMap.value = material.roughnessMap; 21946 21947 } 21948 21949 if ( material.metalnessMap ) { 21950 21951 uniforms.metalnessMap.value = material.metalnessMap; 21952 21953 } 21954 21955 if ( material.emissiveMap ) { 21956 21957 uniforms.emissiveMap.value = material.emissiveMap; 21958 21959 } 21960 21961 if ( material.bumpMap ) { 21962 21963 uniforms.bumpMap.value = material.bumpMap; 21964 uniforms.bumpScale.value = material.bumpScale; 21965 21966 } 21967 21968 if ( material.normalMap ) { 21969 21970 uniforms.normalMap.value = material.normalMap; 21971 uniforms.normalScale.value.copy( material.normalScale ); 21972 21973 } 21974 21975 if ( material.displacementMap ) { 21976 21977 uniforms.displacementMap.value = material.displacementMap; 21978 uniforms.displacementScale.value = material.displacementScale; 21979 uniforms.displacementBias.value = material.displacementBias; 21980 21981 } 21982 21983 if ( material.envMap ) { 21984 21985 //uniforms.envMap.value = material.envMap; // part of uniforms common 21986 uniforms.envMapIntensity.value = material.envMapIntensity; 21987 21988 } 21989 21990 } 21991 21992 function refreshUniformsPhysical( uniforms, material ) { 21993 21994 uniforms.clearCoat.value = material.clearCoat; 21995 uniforms.clearCoatRoughness.value = material.clearCoatRoughness; 21996 21997 refreshUniformsStandard( uniforms, material ); 21998 21999 } 22000 22001 function refreshUniformsNormal( uniforms, material ) { 22002 22003 if ( material.bumpMap ) { 22004 22005 uniforms.bumpMap.value = material.bumpMap; 22006 uniforms.bumpScale.value = material.bumpScale; 22007 22008 } 22009 22010 if ( material.normalMap ) { 22011 22012 uniforms.normalMap.value = material.normalMap; 22013 uniforms.normalScale.value.copy( material.normalScale ); 22014 22015 } 22016 22017 if ( material.displacementMap ) { 22018 22019 uniforms.displacementMap.value = material.displacementMap; 22020 uniforms.displacementScale.value = material.displacementScale; 22021 uniforms.displacementBias.value = material.displacementBias; 22022 22023 } 22024 22025 } 22026 22027 // If uniforms are marked as clean, they don't need to be loaded to the GPU. 22028 22029 function markUniformsLightsNeedsUpdate( uniforms, value ) { 22030 22031 uniforms.ambientLightColor.needsUpdate = value; 22032 22033 uniforms.directionalLights.needsUpdate = value; 22034 uniforms.pointLights.needsUpdate = value; 22035 uniforms.spotLights.needsUpdate = value; 22036 uniforms.rectAreaLights.needsUpdate = value; 22037 uniforms.hemisphereLights.needsUpdate = value; 22038 22039 } 22040 22041 // Lighting 22042 22043 function setupShadows( lights ) { 22044 22045 var lightShadowsLength = 0; 22046 22047 for ( var i = 0, l = lights.length; i < l; i ++ ) { 22048 22049 var light = lights[ i ]; 22050 22051 if ( light.castShadow ) { 22052 22053 _lights.shadows[ lightShadowsLength ++ ] = light; 22054 22055 } 22056 22057 } 22058 22059 _lights.shadows.length = lightShadowsLength; 22060 22061 } 22062 22063 function setupLights( lights, camera ) { 22064 22065 var l, ll, light, 22066 r = 0, g = 0, b = 0, 22067 color, 22068 intensity, 22069 distance, 22070 shadowMap, 22071 22072 viewMatrix = camera.matrixWorldInverse, 22073 22074 directionalLength = 0, 22075 pointLength = 0, 22076 spotLength = 0, 22077 rectAreaLength = 0, 22078 hemiLength = 0; 22079 22080 for ( l = 0, ll = lights.length; l < ll; l ++ ) { 22081 22082 light = lights[ l ]; 22083 22084 color = light.color; 22085 intensity = light.intensity; 22086 distance = light.distance; 22087 22088 shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; 22089 22090 if ( light.isAmbientLight ) { 22091 22092 r += color.r * intensity; 22093 g += color.g * intensity; 22094 b += color.b * intensity; 22095 22096 } else if ( light.isDirectionalLight ) { 22097 22098 var uniforms = lightCache.get( light ); 22099 22100 uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); 22101 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22102 _vector3.setFromMatrixPosition( light.target.matrixWorld ); 22103 uniforms.direction.sub( _vector3 ); 22104 uniforms.direction.transformDirection( viewMatrix ); 22105 22106 uniforms.shadow = light.castShadow; 22107 22108 if ( light.castShadow ) { 22109 22110 uniforms.shadowBias = light.shadow.bias; 22111 uniforms.shadowRadius = light.shadow.radius; 22112 uniforms.shadowMapSize = light.shadow.mapSize; 22113 22114 } 22115 22116 _lights.directionalShadowMap[ directionalLength ] = shadowMap; 22117 _lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; 22118 _lights.directional[ directionalLength ++ ] = uniforms; 22119 22120 } else if ( light.isSpotLight ) { 22121 22122 var uniforms = lightCache.get( light ); 22123 22124 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22125 uniforms.position.applyMatrix4( viewMatrix ); 22126 22127 uniforms.color.copy( color ).multiplyScalar( intensity ); 22128 uniforms.distance = distance; 22129 22130 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22131 _vector3.setFromMatrixPosition( light.target.matrixWorld ); 22132 uniforms.direction.sub( _vector3 ); 22133 uniforms.direction.transformDirection( viewMatrix ); 22134 22135 uniforms.coneCos = Math.cos( light.angle ); 22136 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); 22137 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; 22138 22139 uniforms.shadow = light.castShadow; 22140 22141 if ( light.castShadow ) { 22142 22143 uniforms.shadowBias = light.shadow.bias; 22144 uniforms.shadowRadius = light.shadow.radius; 22145 uniforms.shadowMapSize = light.shadow.mapSize; 22146 22147 } 22148 22149 _lights.spotShadowMap[ spotLength ] = shadowMap; 22150 _lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix; 22151 _lights.spot[ spotLength ++ ] = uniforms; 22152 22153 } else if ( light.isRectAreaLight ) { 22154 22155 var uniforms = lightCache.get( light ); 22156 22157 // (a) intensity controls irradiance of entire light 22158 uniforms.color 22159 .copy( color ) 22160 .multiplyScalar( intensity / ( light.width * light.height ) ); 22161 22162 // (b) intensity controls the radiance per light area 22163 // uniforms.color.copy( color ).multiplyScalar( intensity ); 22164 22165 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22166 uniforms.position.applyMatrix4( viewMatrix ); 22167 22168 // extract local rotation of light to derive width/height half vectors 22169 _matrix42.identity(); 22170 _matrix4.copy( light.matrixWorld ); 22171 _matrix4.premultiply( viewMatrix ); 22172 _matrix42.extractRotation( _matrix4 ); 22173 22174 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); 22175 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); 22176 22177 uniforms.halfWidth.applyMatrix4( _matrix42 ); 22178 uniforms.halfHeight.applyMatrix4( _matrix42 ); 22179 22180 // TODO (abelnation): RectAreaLight distance? 22181 // uniforms.distance = distance; 22182 22183 _lights.rectArea[ rectAreaLength ++ ] = uniforms; 22184 22185 } else if ( light.isPointLight ) { 22186 22187 var uniforms = lightCache.get( light ); 22188 22189 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22190 uniforms.position.applyMatrix4( viewMatrix ); 22191 22192 uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); 22193 uniforms.distance = light.distance; 22194 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; 22195 22196 uniforms.shadow = light.castShadow; 22197 22198 if ( light.castShadow ) { 22199 22200 uniforms.shadowBias = light.shadow.bias; 22201 uniforms.shadowRadius = light.shadow.radius; 22202 uniforms.shadowMapSize = light.shadow.mapSize; 22203 22204 } 22205 22206 _lights.pointShadowMap[ pointLength ] = shadowMap; 22207 22208 if ( _lights.pointShadowMatrix[ pointLength ] === undefined ) { 22209 22210 _lights.pointShadowMatrix[ pointLength ] = new Matrix4(); 22211 22212 } 22213 22214 // for point lights we set the shadow matrix to be a translation-only matrix 22215 // equal to inverse of the light's position 22216 _vector3.setFromMatrixPosition( light.matrixWorld ).negate(); 22217 _lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 ); 22218 22219 _lights.point[ pointLength ++ ] = uniforms; 22220 22221 } else if ( light.isHemisphereLight ) { 22222 22223 var uniforms = lightCache.get( light ); 22224 22225 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22226 uniforms.direction.transformDirection( viewMatrix ); 22227 uniforms.direction.normalize(); 22228 22229 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); 22230 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); 22231 22232 _lights.hemi[ hemiLength ++ ] = uniforms; 22233 22234 } 22235 22236 } 22237 22238 _lights.ambient[ 0 ] = r; 22239 _lights.ambient[ 1 ] = g; 22240 _lights.ambient[ 2 ] = b; 22241 22242 _lights.directional.length = directionalLength; 22243 _lights.spot.length = spotLength; 22244 _lights.rectArea.length = rectAreaLength; 22245 _lights.point.length = pointLength; 22246 _lights.hemi.length = hemiLength; 22247 22248 // TODO (sam-g-steel) why aren't we using join 22249 _lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length; 22250 22251 } 22252 22253 // GL state setting 22254 22255 this.setFaceCulling = function ( cullFace, frontFaceDirection ) { 22256 22257 state.setCullFace( cullFace ); 22258 state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW ); 22259 22260 }; 22261 22262 // Textures 22263 22264 function allocTextureUnit() { 22265 22266 var textureUnit = _usedTextureUnits; 22267 22268 if ( textureUnit >= capabilities.maxTextures ) { 22269 22270 console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); 22271 22272 } 22273 22274 _usedTextureUnits += 1; 22275 22276 return textureUnit; 22277 22278 } 22279 22280 this.allocTextureUnit = allocTextureUnit; 22281 22282 // this.setTexture2D = setTexture2D; 22283 this.setTexture2D = ( function() { 22284 22285 var warned = false; 22286 22287 // backwards compatibility: peel texture.texture 22288 return function setTexture2D( texture, slot ) { 22289 22290 if ( texture && texture.isWebGLRenderTarget ) { 22291 22292 if ( ! warned ) { 22293 22294 console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); 22295 warned = true; 22296 22297 } 22298 22299 texture = texture.texture; 22300 22301 } 22302 22303 textures.setTexture2D( texture, slot ); 22304 22305 }; 22306 22307 }() ); 22308 22309 this.setTexture = ( function() { 22310 22311 var warned = false; 22312 22313 return function setTexture( texture, slot ) { 22314 22315 if ( ! warned ) { 22316 22317 console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); 22318 warned = true; 22319 22320 } 22321 22322 textures.setTexture2D( texture, slot ); 22323 22324 }; 22325 22326 }() ); 22327 22328 this.setTextureCube = ( function() { 22329 22330 var warned = false; 22331 22332 return function setTextureCube( texture, slot ) { 22333 22334 // backwards compatibility: peel texture.texture 22335 if ( texture && texture.isWebGLRenderTargetCube ) { 22336 22337 if ( ! warned ) { 22338 22339 console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); 22340 warned = true; 22341 22342 } 22343 22344 texture = texture.texture; 22345 22346 } 22347 22348 // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture 22349 // TODO: unify these code paths 22350 if ( ( texture && texture.isCubeTexture ) || 22351 ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { 22352 22353 // CompressedTexture can have Array in image :/ 22354 22355 // this function alone should take care of cube textures 22356 textures.setTextureCube( texture, slot ); 22357 22358 } else { 22359 22360 // assumed: texture property of THREE.WebGLRenderTargetCube 22361 22362 textures.setTextureCubeDynamic( texture, slot ); 22363 22364 } 22365 22366 }; 22367 22368 }() ); 22369 22370 this.getCurrentRenderTarget = function() { 22371 22372 return _currentRenderTarget; 22373 22374 }; 22375 22376 this.setRenderTarget = function ( renderTarget ) { 22377 22378 _currentRenderTarget = renderTarget; 22379 22380 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { 22381 22382 textures.setupRenderTarget( renderTarget ); 22383 22384 } 22385 22386 var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); 22387 var framebuffer; 22388 22389 if ( renderTarget ) { 22390 22391 var renderTargetProperties = properties.get( renderTarget ); 22392 22393 if ( isCube ) { 22394 22395 framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ]; 22396 22397 } else { 22398 22399 framebuffer = renderTargetProperties.__webglFramebuffer; 22400 22401 } 22402 22403 _currentScissor.copy( renderTarget.scissor ); 22404 _currentScissorTest = renderTarget.scissorTest; 22405 22406 _currentViewport.copy( renderTarget.viewport ); 22407 22408 } else { 22409 22410 framebuffer = null; 22411 22412 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); 22413 _currentScissorTest = _scissorTest; 22414 22415 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); 22416 22417 } 22418 22419 if ( _currentFramebuffer !== framebuffer ) { 22420 22421 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 22422 _currentFramebuffer = framebuffer; 22423 22424 } 22425 22426 state.scissor( _currentScissor ); 22427 state.setScissorTest( _currentScissorTest ); 22428 22429 state.viewport( _currentViewport ); 22430 22431 if ( isCube ) { 22432 22433 var textureProperties = properties.get( renderTarget.texture ); 22434 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); 22435 22436 } 22437 22438 }; 22439 22440 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { 22441 22442 if ( ( renderTarget && renderTarget.isWebGLRenderTarget ) === false ) { 22443 22444 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); 22445 return; 22446 22447 } 22448 22449 var framebuffer = properties.get( renderTarget ).__webglFramebuffer; 22450 22451 if ( framebuffer ) { 22452 22453 var restore = false; 22454 22455 if ( framebuffer !== _currentFramebuffer ) { 22456 22457 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 22458 22459 restore = true; 22460 22461 } 22462 22463 try { 22464 22465 var texture = renderTarget.texture; 22466 var textureFormat = texture.format; 22467 var textureType = texture.type; 22468 22469 if ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { 22470 22471 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); 22472 return; 22473 22474 } 22475 22476 if ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513) 22477 ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox 22478 ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) { 22479 22480 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); 22481 return; 22482 22483 } 22484 22485 if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { 22486 22487 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 22488 22489 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { 22490 22491 _gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer ); 22492 22493 } 22494 22495 } else { 22496 22497 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); 22498 22499 } 22500 22501 } finally { 22502 22503 if ( restore ) { 22504 22505 _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); 22506 22507 } 22508 22509 } 22510 22511 } 22512 22513 }; 22514 22515 // Map three.js constants to WebGL constants 22516 22517 function paramThreeToGL( p ) { 22518 22519 var extension; 22520 22521 if ( p === RepeatWrapping ) return _gl.REPEAT; 22522 if ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; 22523 if ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; 22524 22525 if ( p === NearestFilter ) return _gl.NEAREST; 22526 if ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; 22527 if ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; 22528 22529 if ( p === LinearFilter ) return _gl.LINEAR; 22530 if ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; 22531 if ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; 22532 22533 if ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE; 22534 if ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; 22535 if ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; 22536 if ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; 22537 22538 if ( p === ByteType ) return _gl.BYTE; 22539 if ( p === ShortType ) return _gl.SHORT; 22540 if ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT; 22541 if ( p === IntType ) return _gl.INT; 22542 if ( p === UnsignedIntType ) return _gl.UNSIGNED_INT; 22543 if ( p === FloatType ) return _gl.FLOAT; 22544 22545 if ( p === HalfFloatType ) { 22546 22547 extension = extensions.get( 'OES_texture_half_float' ); 22548 22549 if ( extension !== null ) return extension.HALF_FLOAT_OES; 22550 22551 } 22552 22553 if ( p === AlphaFormat ) return _gl.ALPHA; 22554 if ( p === RGBFormat ) return _gl.RGB; 22555 if ( p === RGBAFormat ) return _gl.RGBA; 22556 if ( p === LuminanceFormat ) return _gl.LUMINANCE; 22557 if ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; 22558 if ( p === DepthFormat ) return _gl.DEPTH_COMPONENT; 22559 if ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL; 22560 22561 if ( p === AddEquation ) return _gl.FUNC_ADD; 22562 if ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT; 22563 if ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; 22564 22565 if ( p === ZeroFactor ) return _gl.ZERO; 22566 if ( p === OneFactor ) return _gl.ONE; 22567 if ( p === SrcColorFactor ) return _gl.SRC_COLOR; 22568 if ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; 22569 if ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA; 22570 if ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; 22571 if ( p === DstAlphaFactor ) return _gl.DST_ALPHA; 22572 if ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; 22573 22574 if ( p === DstColorFactor ) return _gl.DST_COLOR; 22575 if ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; 22576 if ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; 22577 22578 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || 22579 p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { 22580 22581 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); 22582 22583 if ( extension !== null ) { 22584 22585 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 22586 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 22587 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 22588 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 22589 22590 } 22591 22592 } 22593 22594 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || 22595 p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { 22596 22597 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); 22598 22599 if ( extension !== null ) { 22600 22601 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 22602 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 22603 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 22604 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 22605 22606 } 22607 22608 } 22609 22610 if ( p === RGB_ETC1_Format ) { 22611 22612 extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); 22613 22614 if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; 22615 22616 } 22617 22618 if ( p === MinEquation || p === MaxEquation ) { 22619 22620 extension = extensions.get( 'EXT_blend_minmax' ); 22621 22622 if ( extension !== null ) { 22623 22624 if ( p === MinEquation ) return extension.MIN_EXT; 22625 if ( p === MaxEquation ) return extension.MAX_EXT; 22626 22627 } 22628 22629 } 22630 22631 if ( p === UnsignedInt248Type ) { 22632 22633 extension = extensions.get( 'WEBGL_depth_texture' ); 22634 22635 if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; 22636 22637 } 22638 22639 return 0; 22640 22641 } 22642 22643 } 22644 22645 /** 22646 * @author mrdoob / http://mrdoob.com/ 22647 * @author alteredq / http://alteredqualia.com/ 22648 */ 22649 22650 function FogExp2 ( color, density ) { 22651 22652 this.name = ''; 22653 22654 this.color = new Color( color ); 22655 this.density = ( density !== undefined ) ? density : 0.00025; 22656 22657 } 22658 22659 FogExp2.prototype.isFogExp2 = true; 22660 22661 FogExp2.prototype.clone = function () { 22662 22663 return new FogExp2( this.color.getHex(), this.density ); 22664 22665 }; 22666 22667 FogExp2.prototype.toJSON = function ( meta ) { 22668 22669 return { 22670 type: 'FogExp2', 22671 color: this.color.getHex(), 22672 density: this.density 22673 }; 22674 22675 }; 22676 22677 /** 22678 * @author mrdoob / http://mrdoob.com/ 22679 * @author alteredq / http://alteredqualia.com/ 22680 */ 22681 22682 function Fog ( color, near, far ) { 22683 22684 this.name = ''; 22685 22686 this.color = new Color( color ); 22687 22688 this.near = ( near !== undefined ) ? near : 1; 22689 this.far = ( far !== undefined ) ? far : 1000; 22690 22691 } 22692 22693 Fog.prototype.isFog = true; 22694 22695 Fog.prototype.clone = function () { 22696 22697 return new Fog( this.color.getHex(), this.near, this.far ); 22698 22699 }; 22700 22701 Fog.prototype.toJSON = function ( meta ) { 22702 22703 return { 22704 type: 'Fog', 22705 color: this.color.getHex(), 22706 near: this.near, 22707 far: this.far 22708 }; 22709 22710 }; 22711 22712 /** 22713 * @author mrdoob / http://mrdoob.com/ 22714 */ 22715 22716 function Scene () { 22717 22718 Object3D.call( this ); 22719 22720 this.type = 'Scene'; 22721 22722 this.background = null; 22723 this.fog = null; 22724 this.overrideMaterial = null; 22725 22726 this.autoUpdate = true; // checked by the renderer 22727 22728 } 22729 22730 Scene.prototype = Object.create( Object3D.prototype ); 22731 22732 Scene.prototype.constructor = Scene; 22733 22734 Scene.prototype.copy = function ( source, recursive ) { 22735 22736 Object3D.prototype.copy.call( this, source, recursive ); 22737 22738 if ( source.background !== null ) this.background = source.background.clone(); 22739 if ( source.fog !== null ) this.fog = source.fog.clone(); 22740 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); 22741 22742 this.autoUpdate = source.autoUpdate; 22743 this.matrixAutoUpdate = source.matrixAutoUpdate; 22744 22745 return this; 22746 22747 }; 22748 22749 Scene.prototype.toJSON = function ( meta ) { 22750 22751 var data = Object3D.prototype.toJSON.call( this, meta ); 22752 22753 if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); 22754 if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); 22755 22756 return data; 22757 22758 }; 22759 22760 /** 22761 * @author mikael emtinger / http://gomo.se/ 22762 * @author alteredq / http://alteredqualia.com/ 22763 */ 22764 22765 function LensFlare( texture, size, distance, blending, color ) { 22766 22767 Object3D.call( this ); 22768 22769 this.lensFlares = []; 22770 22771 this.positionScreen = new Vector3(); 22772 this.customUpdateCallback = undefined; 22773 22774 if ( texture !== undefined ) { 22775 22776 this.add( texture, size, distance, blending, color ); 22777 22778 } 22779 22780 } 22781 22782 LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), { 22783 22784 constructor: LensFlare, 22785 22786 isLensFlare: true, 22787 22788 copy: function ( source ) { 22789 22790 Object3D.prototype.copy.call( this, source ); 22791 22792 this.positionScreen.copy( source.positionScreen ); 22793 this.customUpdateCallback = source.customUpdateCallback; 22794 22795 for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { 22796 22797 this.lensFlares.push( source.lensFlares[ i ] ); 22798 22799 } 22800 22801 return this; 22802 22803 }, 22804 22805 add: function ( texture, size, distance, blending, color, opacity ) { 22806 22807 if ( size === undefined ) size = - 1; 22808 if ( distance === undefined ) distance = 0; 22809 if ( opacity === undefined ) opacity = 1; 22810 if ( color === undefined ) color = new Color( 0xffffff ); 22811 if ( blending === undefined ) blending = NormalBlending; 22812 22813 distance = Math.min( distance, Math.max( 0, distance ) ); 22814 22815 this.lensFlares.push( { 22816 texture: texture, // THREE.Texture 22817 size: size, // size in pixels (-1 = use texture.width) 22818 distance: distance, // distance (0-1) from light source (0=at light source) 22819 x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back 22820 scale: 1, // scale 22821 rotation: 0, // rotation 22822 opacity: opacity, // opacity 22823 color: color, // color 22824 blending: blending // blending 22825 } ); 22826 22827 }, 22828 22829 /* 22830 * Update lens flares update positions on all flares based on the screen position 22831 * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. 22832 */ 22833 22834 updateLensFlares: function () { 22835 22836 var f, fl = this.lensFlares.length; 22837 var flare; 22838 var vecX = - this.positionScreen.x * 2; 22839 var vecY = - this.positionScreen.y * 2; 22840 22841 for ( f = 0; f < fl; f ++ ) { 22842 22843 flare = this.lensFlares[ f ]; 22844 22845 flare.x = this.positionScreen.x + vecX * flare.distance; 22846 flare.y = this.positionScreen.y + vecY * flare.distance; 22847 22848 flare.wantedRotation = flare.x * Math.PI * 0.25; 22849 flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; 22850 22851 } 22852 22853 } 22854 22855 } ); 22856 22857 /** 22858 * @author alteredq / http://alteredqualia.com/ 22859 * 22860 * parameters = { 22861 * color: <hex>, 22862 * opacity: <float>, 22863 * map: new THREE.Texture( <Image> ), 22864 * 22865 * uvOffset: new THREE.Vector2(), 22866 * uvScale: new THREE.Vector2() 22867 * } 22868 */ 22869 22870 function SpriteMaterial( parameters ) { 22871 22872 Material.call( this ); 22873 22874 this.type = 'SpriteMaterial'; 22875 22876 this.color = new Color( 0xffffff ); 22877 this.map = null; 22878 22879 this.rotation = 0; 22880 22881 this.fog = false; 22882 this.lights = false; 22883 22884 this.setValues( parameters ); 22885 22886 } 22887 22888 SpriteMaterial.prototype = Object.create( Material.prototype ); 22889 SpriteMaterial.prototype.constructor = SpriteMaterial; 22890 22891 SpriteMaterial.prototype.copy = function ( source ) { 22892 22893 Material.prototype.copy.call( this, source ); 22894 22895 this.color.copy( source.color ); 22896 this.map = source.map; 22897 22898 this.rotation = source.rotation; 22899 22900 return this; 22901 22902 }; 22903 22904 /** 22905 * @author mikael emtinger / http://gomo.se/ 22906 * @author alteredq / http://alteredqualia.com/ 22907 */ 22908 22909 function Sprite( material ) { 22910 22911 Object3D.call( this ); 22912 22913 this.type = 'Sprite'; 22914 22915 this.material = ( material !== undefined ) ? material : new SpriteMaterial(); 22916 22917 } 22918 22919 Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { 22920 22921 constructor: Sprite, 22922 22923 isSprite: true, 22924 22925 raycast: ( function () { 22926 22927 var matrixPosition = new Vector3(); 22928 22929 return function raycast( raycaster, intersects ) { 22930 22931 matrixPosition.setFromMatrixPosition( this.matrixWorld ); 22932 22933 var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition ); 22934 var guessSizeSq = this.scale.x * this.scale.y / 4; 22935 22936 if ( distanceSq > guessSizeSq ) { 22937 22938 return; 22939 22940 } 22941 22942 intersects.push( { 22943 22944 distance: Math.sqrt( distanceSq ), 22945 point: this.position, 22946 face: null, 22947 object: this 22948 22949 } ); 22950 22951 }; 22952 22953 }() ), 22954 22955 clone: function () { 22956 22957 return new this.constructor( this.material ).copy( this ); 22958 22959 } 22960 22961 } ); 22962 22963 /** 22964 * @author mikael emtinger / http://gomo.se/ 22965 * @author alteredq / http://alteredqualia.com/ 22966 * @author mrdoob / http://mrdoob.com/ 22967 */ 22968 22969 function LOD() { 22970 22971 Object3D.call( this ); 22972 22973 this.type = 'LOD'; 22974 22975 Object.defineProperties( this, { 22976 levels: { 22977 enumerable: true, 22978 value: [] 22979 } 22980 } ); 22981 22982 } 22983 22984 22985 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { 22986 22987 constructor: LOD, 22988 22989 copy: function ( source ) { 22990 22991 Object3D.prototype.copy.call( this, source, false ); 22992 22993 var levels = source.levels; 22994 22995 for ( var i = 0, l = levels.length; i < l; i ++ ) { 22996 22997 var level = levels[ i ]; 22998 22999 this.addLevel( level.object.clone(), level.distance ); 23000 23001 } 23002 23003 return this; 23004 23005 }, 23006 23007 addLevel: function ( object, distance ) { 23008 23009 if ( distance === undefined ) distance = 0; 23010 23011 distance = Math.abs( distance ); 23012 23013 var levels = this.levels; 23014 23015 for ( var l = 0; l < levels.length; l ++ ) { 23016 23017 if ( distance < levels[ l ].distance ) { 23018 23019 break; 23020 23021 } 23022 23023 } 23024 23025 levels.splice( l, 0, { distance: distance, object: object } ); 23026 23027 this.add( object ); 23028 23029 }, 23030 23031 getObjectForDistance: function ( distance ) { 23032 23033 var levels = this.levels; 23034 23035 for ( var i = 1, l = levels.length; i < l; i ++ ) { 23036 23037 if ( distance < levels[ i ].distance ) { 23038 23039 break; 23040 23041 } 23042 23043 } 23044 23045 return levels[ i - 1 ].object; 23046 23047 }, 23048 23049 raycast: ( function () { 23050 23051 var matrixPosition = new Vector3(); 23052 23053 return function raycast( raycaster, intersects ) { 23054 23055 matrixPosition.setFromMatrixPosition( this.matrixWorld ); 23056 23057 var distance = raycaster.ray.origin.distanceTo( matrixPosition ); 23058 23059 this.getObjectForDistance( distance ).raycast( raycaster, intersects ); 23060 23061 }; 23062 23063 }() ), 23064 23065 update: function () { 23066 23067 var v1 = new Vector3(); 23068 var v2 = new Vector3(); 23069 23070 return function update( camera ) { 23071 23072 var levels = this.levels; 23073 23074 if ( levels.length > 1 ) { 23075 23076 v1.setFromMatrixPosition( camera.matrixWorld ); 23077 v2.setFromMatrixPosition( this.matrixWorld ); 23078 23079 var distance = v1.distanceTo( v2 ); 23080 23081 levels[ 0 ].object.visible = true; 23082 23083 for ( var i = 1, l = levels.length; i < l; i ++ ) { 23084 23085 if ( distance >= levels[ i ].distance ) { 23086 23087 levels[ i - 1 ].object.visible = false; 23088 levels[ i ].object.visible = true; 23089 23090 } else { 23091 23092 break; 23093 23094 } 23095 23096 } 23097 23098 for ( ; i < l; i ++ ) { 23099 23100 levels[ i ].object.visible = false; 23101 23102 } 23103 23104 } 23105 23106 }; 23107 23108 }(), 23109 23110 toJSON: function ( meta ) { 23111 23112 var data = Object3D.prototype.toJSON.call( this, meta ); 23113 23114 data.object.levels = []; 23115 23116 var levels = this.levels; 23117 23118 for ( var i = 0, l = levels.length; i < l; i ++ ) { 23119 23120 var level = levels[ i ]; 23121 23122 data.object.levels.push( { 23123 object: level.object.uuid, 23124 distance: level.distance 23125 } ); 23126 23127 } 23128 23129 return data; 23130 23131 } 23132 23133 } ); 23134 23135 /** 23136 * @author mikael emtinger / http://gomo.se/ 23137 * @author alteredq / http://alteredqualia.com/ 23138 * @author michael guerrero / http://realitymeltdown.com 23139 * @author ikerr / http://verold.com 23140 */ 23141 23142 function Skeleton( bones, boneInverses, useVertexTexture ) { 23143 23144 this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; 23145 23146 this.identityMatrix = new Matrix4(); 23147 23148 // copy the bone array 23149 23150 bones = bones || []; 23151 23152 this.bones = bones.slice( 0 ); 23153 23154 // create a bone texture or an array of floats 23155 23156 if ( this.useVertexTexture ) { 23157 23158 // layout (1 matrix = 4 pixels) 23159 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 23160 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) 23161 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) 23162 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) 23163 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) 23164 23165 23166 var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix 23167 size = _Math.nextPowerOfTwo( Math.ceil( size ) ); 23168 size = Math.max( size, 4 ); 23169 23170 this.boneTextureWidth = size; 23171 this.boneTextureHeight = size; 23172 23173 this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel 23174 this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType ); 23175 23176 } else { 23177 23178 this.boneMatrices = new Float32Array( 16 * this.bones.length ); 23179 23180 } 23181 23182 // use the supplied bone inverses or calculate the inverses 23183 23184 if ( boneInverses === undefined ) { 23185 23186 this.calculateInverses(); 23187 23188 } else { 23189 23190 if ( this.bones.length === boneInverses.length ) { 23191 23192 this.boneInverses = boneInverses.slice( 0 ); 23193 23194 } else { 23195 23196 console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); 23197 23198 this.boneInverses = []; 23199 23200 for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { 23201 23202 this.boneInverses.push( new Matrix4() ); 23203 23204 } 23205 23206 } 23207 23208 } 23209 23210 } 23211 23212 Object.assign( Skeleton.prototype, { 23213 23214 calculateInverses: function () { 23215 23216 this.boneInverses = []; 23217 23218 for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { 23219 23220 var inverse = new Matrix4(); 23221 23222 if ( this.bones[ b ] ) { 23223 23224 inverse.getInverse( this.bones[ b ].matrixWorld ); 23225 23226 } 23227 23228 this.boneInverses.push( inverse ); 23229 23230 } 23231 23232 }, 23233 23234 pose: function () { 23235 23236 var bone; 23237 23238 // recover the bind-time world matrices 23239 23240 for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { 23241 23242 bone = this.bones[ b ]; 23243 23244 if ( bone ) { 23245 23246 bone.matrixWorld.getInverse( this.boneInverses[ b ] ); 23247 23248 } 23249 23250 } 23251 23252 // compute the local matrices, positions, rotations and scales 23253 23254 for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { 23255 23256 bone = this.bones[ b ]; 23257 23258 if ( bone ) { 23259 23260 if ( bone.parent && bone.parent.isBone ) { 23261 23262 bone.matrix.getInverse( bone.parent.matrixWorld ); 23263 bone.matrix.multiply( bone.matrixWorld ); 23264 23265 } else { 23266 23267 bone.matrix.copy( bone.matrixWorld ); 23268 23269 } 23270 23271 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); 23272 23273 } 23274 23275 } 23276 23277 }, 23278 23279 update: ( function () { 23280 23281 var offsetMatrix = new Matrix4(); 23282 23283 return function update() { 23284 23285 // flatten bone matrices to array 23286 23287 for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { 23288 23289 // compute the offset between the current and the original transform 23290 23291 var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; 23292 23293 offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); 23294 offsetMatrix.toArray( this.boneMatrices, b * 16 ); 23295 23296 } 23297 23298 if ( this.useVertexTexture ) { 23299 23300 this.boneTexture.needsUpdate = true; 23301 23302 } 23303 23304 }; 23305 23306 } )(), 23307 23308 clone: function () { 23309 23310 return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture ); 23311 23312 } 23313 23314 } ); 23315 23316 /** 23317 * @author mikael emtinger / http://gomo.se/ 23318 * @author alteredq / http://alteredqualia.com/ 23319 * @author ikerr / http://verold.com 23320 */ 23321 23322 function Bone() { 23323 23324 Object3D.call( this ); 23325 23326 this.type = 'Bone'; 23327 23328 } 23329 23330 Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { 23331 23332 constructor: Bone, 23333 23334 isBone: true 23335 23336 } ); 23337 23338 /** 23339 * @author mikael emtinger / http://gomo.se/ 23340 * @author alteredq / http://alteredqualia.com/ 23341 * @author ikerr / http://verold.com 23342 */ 23343 23344 function SkinnedMesh( geometry, material, useVertexTexture ) { 23345 23346 Mesh.call( this, geometry, material ); 23347 23348 this.type = 'SkinnedMesh'; 23349 23350 this.bindMode = "attached"; 23351 this.bindMatrix = new Matrix4(); 23352 this.bindMatrixInverse = new Matrix4(); 23353 23354 // init bones 23355 23356 // TODO: remove bone creation as there is no reason (other than 23357 // convenience) for THREE.SkinnedMesh to do this. 23358 23359 var bones = []; 23360 23361 if ( this.geometry && this.geometry.bones !== undefined ) { 23362 23363 var bone, gbone; 23364 23365 for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { 23366 23367 gbone = this.geometry.bones[ b ]; 23368 23369 bone = new Bone(); 23370 bones.push( bone ); 23371 23372 bone.name = gbone.name; 23373 bone.position.fromArray( gbone.pos ); 23374 bone.quaternion.fromArray( gbone.rotq ); 23375 if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); 23376 23377 } 23378 23379 for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { 23380 23381 gbone = this.geometry.bones[ b ]; 23382 23383 if ( gbone.parent !== - 1 && gbone.parent !== null && 23384 bones[ gbone.parent ] !== undefined ) { 23385 23386 bones[ gbone.parent ].add( bones[ b ] ); 23387 23388 } else { 23389 23390 this.add( bones[ b ] ); 23391 23392 } 23393 23394 } 23395 23396 } 23397 23398 this.normalizeSkinWeights(); 23399 23400 this.updateMatrixWorld( true ); 23401 this.bind( new Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld ); 23402 23403 } 23404 23405 23406 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { 23407 23408 constructor: SkinnedMesh, 23409 23410 isSkinnedMesh: true, 23411 23412 bind: function( skeleton, bindMatrix ) { 23413 23414 this.skeleton = skeleton; 23415 23416 if ( bindMatrix === undefined ) { 23417 23418 this.updateMatrixWorld( true ); 23419 23420 this.skeleton.calculateInverses(); 23421 23422 bindMatrix = this.matrixWorld; 23423 23424 } 23425 23426 this.bindMatrix.copy( bindMatrix ); 23427 this.bindMatrixInverse.getInverse( bindMatrix ); 23428 23429 }, 23430 23431 pose: function () { 23432 23433 this.skeleton.pose(); 23434 23435 }, 23436 23437 normalizeSkinWeights: function () { 23438 23439 if ( this.geometry && this.geometry.isGeometry ) { 23440 23441 for ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) { 23442 23443 var sw = this.geometry.skinWeights[ i ]; 23444 23445 var scale = 1.0 / sw.lengthManhattan(); 23446 23447 if ( scale !== Infinity ) { 23448 23449 sw.multiplyScalar( scale ); 23450 23451 } else { 23452 23453 sw.set( 1, 0, 0, 0 ); // do something reasonable 23454 23455 } 23456 23457 } 23458 23459 } else if ( this.geometry && this.geometry.isBufferGeometry ) { 23460 23461 var vec = new Vector4(); 23462 23463 var skinWeight = this.geometry.attributes.skinWeight; 23464 23465 for ( var i = 0; i < skinWeight.count; i ++ ) { 23466 23467 vec.x = skinWeight.getX( i ); 23468 vec.y = skinWeight.getY( i ); 23469 vec.z = skinWeight.getZ( i ); 23470 vec.w = skinWeight.getW( i ); 23471 23472 var scale = 1.0 / vec.lengthManhattan(); 23473 23474 if ( scale !== Infinity ) { 23475 23476 vec.multiplyScalar( scale ); 23477 23478 } else { 23479 23480 vec.set( 1, 0, 0, 0 ); // do something reasonable 23481 23482 } 23483 23484 skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w ); 23485 23486 } 23487 23488 } 23489 23490 }, 23491 23492 updateMatrixWorld: function( force ) { 23493 23494 Mesh.prototype.updateMatrixWorld.call( this, true ); 23495 23496 if ( this.bindMode === "attached" ) { 23497 23498 this.bindMatrixInverse.getInverse( this.matrixWorld ); 23499 23500 } else if ( this.bindMode === "detached" ) { 23501 23502 this.bindMatrixInverse.getInverse( this.bindMatrix ); 23503 23504 } else { 23505 23506 console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode ); 23507 23508 } 23509 23510 }, 23511 23512 clone: function() { 23513 23514 return new this.constructor( this.geometry, this.material, this.skeleton.useVertexTexture ).copy( this ); 23515 23516 } 23517 23518 } ); 23519 23520 /** 23521 * @author mrdoob / http://mrdoob.com/ 23522 * @author alteredq / http://alteredqualia.com/ 23523 * 23524 * parameters = { 23525 * color: <hex>, 23526 * opacity: <float>, 23527 * 23528 * linewidth: <float>, 23529 * linecap: "round", 23530 * linejoin: "round" 23531 * } 23532 */ 23533 23534 function LineBasicMaterial( parameters ) { 23535 23536 Material.call( this ); 23537 23538 this.type = 'LineBasicMaterial'; 23539 23540 this.color = new Color( 0xffffff ); 23541 23542 this.linewidth = 1; 23543 this.linecap = 'round'; 23544 this.linejoin = 'round'; 23545 23546 this.lights = false; 23547 23548 this.setValues( parameters ); 23549 23550 } 23551 23552 LineBasicMaterial.prototype = Object.create( Material.prototype ); 23553 LineBasicMaterial.prototype.constructor = LineBasicMaterial; 23554 23555 LineBasicMaterial.prototype.isLineBasicMaterial = true; 23556 23557 LineBasicMaterial.prototype.copy = function ( source ) { 23558 23559 Material.prototype.copy.call( this, source ); 23560 23561 this.color.copy( source.color ); 23562 23563 this.linewidth = source.linewidth; 23564 this.linecap = source.linecap; 23565 this.linejoin = source.linejoin; 23566 23567 return this; 23568 23569 }; 23570 23571 /** 23572 * @author mrdoob / http://mrdoob.com/ 23573 */ 23574 23575 function Line( geometry, material, mode ) { 23576 23577 if ( mode === 1 ) { 23578 23579 console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); 23580 return new LineSegments( geometry, material ); 23581 23582 } 23583 23584 Object3D.call( this ); 23585 23586 this.type = 'Line'; 23587 23588 this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); 23589 this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); 23590 23591 } 23592 23593 Line.prototype = Object.assign( Object.create( Object3D.prototype ), { 23594 23595 constructor: Line, 23596 23597 isLine: true, 23598 23599 raycast: ( function () { 23600 23601 var inverseMatrix = new Matrix4(); 23602 var ray = new Ray(); 23603 var sphere = new Sphere(); 23604 23605 return function raycast( raycaster, intersects ) { 23606 23607 var precision = raycaster.linePrecision; 23608 var precisionSq = precision * precision; 23609 23610 var geometry = this.geometry; 23611 var matrixWorld = this.matrixWorld; 23612 23613 // Checking boundingSphere distance to ray 23614 23615 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 23616 23617 sphere.copy( geometry.boundingSphere ); 23618 sphere.applyMatrix4( matrixWorld ); 23619 23620 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; 23621 23622 // 23623 23624 inverseMatrix.getInverse( matrixWorld ); 23625 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); 23626 23627 var vStart = new Vector3(); 23628 var vEnd = new Vector3(); 23629 var interSegment = new Vector3(); 23630 var interRay = new Vector3(); 23631 var step = (this && this.isLineSegments) ? 2 : 1; 23632 23633 if ( geometry.isBufferGeometry ) { 23634 23635 var index = geometry.index; 23636 var attributes = geometry.attributes; 23637 var positions = attributes.position.array; 23638 23639 if ( index !== null ) { 23640 23641 var indices = index.array; 23642 23643 for ( var i = 0, l = indices.length - 1; i < l; i += step ) { 23644 23645 var a = indices[ i ]; 23646 var b = indices[ i + 1 ]; 23647 23648 vStart.fromArray( positions, a * 3 ); 23649 vEnd.fromArray( positions, b * 3 ); 23650 23651 var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); 23652 23653 if ( distSq > precisionSq ) continue; 23654 23655 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation 23656 23657 var distance = raycaster.ray.origin.distanceTo( interRay ); 23658 23659 if ( distance < raycaster.near || distance > raycaster.far ) continue; 23660 23661 intersects.push( { 23662 23663 distance: distance, 23664 // What do we want? intersection point on the ray or on the segment?? 23665 // point: raycaster.ray.at( distance ), 23666 point: interSegment.clone().applyMatrix4( this.matrixWorld ), 23667 index: i, 23668 face: null, 23669 faceIndex: null, 23670 object: this 23671 23672 } ); 23673 23674 } 23675 23676 } else { 23677 23678 for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { 23679 23680 vStart.fromArray( positions, 3 * i ); 23681 vEnd.fromArray( positions, 3 * i + 3 ); 23682 23683 var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); 23684 23685 if ( distSq > precisionSq ) continue; 23686 23687 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation 23688 23689 var distance = raycaster.ray.origin.distanceTo( interRay ); 23690 23691 if ( distance < raycaster.near || distance > raycaster.far ) continue; 23692 23693 intersects.push( { 23694 23695 distance: distance, 23696 // What do we want? intersection point on the ray or on the segment?? 23697 // point: raycaster.ray.at( distance ), 23698 point: interSegment.clone().applyMatrix4( this.matrixWorld ), 23699 index: i, 23700 face: null, 23701 faceIndex: null, 23702 object: this 23703 23704 } ); 23705 23706 } 23707 23708 } 23709 23710 } else if ( geometry.isGeometry ) { 23711 23712 var vertices = geometry.vertices; 23713 var nbVertices = vertices.length; 23714 23715 for ( var i = 0; i < nbVertices - 1; i += step ) { 23716 23717 var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); 23718 23719 if ( distSq > precisionSq ) continue; 23720 23721 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation 23722 23723 var distance = raycaster.ray.origin.distanceTo( interRay ); 23724 23725 if ( distance < raycaster.near || distance > raycaster.far ) continue; 23726 23727 intersects.push( { 23728 23729 distance: distance, 23730 // What do we want? intersection point on the ray or on the segment?? 23731 // point: raycaster.ray.at( distance ), 23732 point: interSegment.clone().applyMatrix4( this.matrixWorld ), 23733 index: i, 23734 face: null, 23735 faceIndex: null, 23736 object: this 23737 23738 } ); 23739 23740 } 23741 23742 } 23743 23744 }; 23745 23746 }() ), 23747 23748 clone: function () { 23749 23750 return new this.constructor( this.geometry, this.material ).copy( this ); 23751 23752 } 23753 23754 } ); 23755 23756 /** 23757 * @author mrdoob / http://mrdoob.com/ 23758 */ 23759 23760 function LineSegments( geometry, material ) { 23761 23762 Line.call( this, geometry, material ); 23763 23764 this.type = 'LineSegments'; 23765 23766 } 23767 23768 LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { 23769 23770 constructor: LineSegments, 23771 23772 isLineSegments: true 23773 23774 } ); 23775 23776 /** 23777 * @author mrdoob / http://mrdoob.com/ 23778 * @author alteredq / http://alteredqualia.com/ 23779 * 23780 * parameters = { 23781 * color: <hex>, 23782 * opacity: <float>, 23783 * map: new THREE.Texture( <Image> ), 23784 * 23785 * size: <float>, 23786 * sizeAttenuation: <bool> 23787 * } 23788 */ 23789 23790 function PointsMaterial( parameters ) { 23791 23792 Material.call( this ); 23793 23794 this.type = 'PointsMaterial'; 23795 23796 this.color = new Color( 0xffffff ); 23797 23798 this.map = null; 23799 23800 this.size = 1; 23801 this.sizeAttenuation = true; 23802 23803 this.lights = false; 23804 23805 this.setValues( parameters ); 23806 23807 } 23808 23809 PointsMaterial.prototype = Object.create( Material.prototype ); 23810 PointsMaterial.prototype.constructor = PointsMaterial; 23811 23812 PointsMaterial.prototype.isPointsMaterial = true; 23813 23814 PointsMaterial.prototype.copy = function ( source ) { 23815 23816 Material.prototype.copy.call( this, source ); 23817 23818 this.color.copy( source.color ); 23819 23820 this.map = source.map; 23821 23822 this.size = source.size; 23823 this.sizeAttenuation = source.sizeAttenuation; 23824 23825 return this; 23826 23827 }; 23828 23829 /** 23830 * @author alteredq / http://alteredqualia.com/ 23831 */ 23832 23833 function Points( geometry, material ) { 23834 23835 Object3D.call( this ); 23836 23837 this.type = 'Points'; 23838 23839 this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); 23840 this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); 23841 23842 } 23843 23844 Points.prototype = Object.assign( Object.create( Object3D.prototype ), { 23845 23846 constructor: Points, 23847 23848 isPoints: true, 23849 23850 raycast: ( function () { 23851 23852 var inverseMatrix = new Matrix4(); 23853 var ray = new Ray(); 23854 var sphere = new Sphere(); 23855 23856 return function raycast( raycaster, intersects ) { 23857 23858 var object = this; 23859 var geometry = this.geometry; 23860 var matrixWorld = this.matrixWorld; 23861 var threshold = raycaster.params.Points.threshold; 23862 23863 // Checking boundingSphere distance to ray 23864 23865 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 23866 23867 sphere.copy( geometry.boundingSphere ); 23868 sphere.applyMatrix4( matrixWorld ); 23869 23870 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; 23871 23872 // 23873 23874 inverseMatrix.getInverse( matrixWorld ); 23875 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); 23876 23877 var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 23878 var localThresholdSq = localThreshold * localThreshold; 23879 var position = new Vector3(); 23880 23881 function testPoint( point, index ) { 23882 23883 var rayPointDistanceSq = ray.distanceSqToPoint( point ); 23884 23885 if ( rayPointDistanceSq < localThresholdSq ) { 23886 23887 var intersectPoint = ray.closestPointToPoint( point ); 23888 intersectPoint.applyMatrix4( matrixWorld ); 23889 23890 var distance = raycaster.ray.origin.distanceTo( intersectPoint ); 23891 23892 if ( distance < raycaster.near || distance > raycaster.far ) return; 23893 23894 intersects.push( { 23895 23896 distance: distance, 23897 distanceToRay: Math.sqrt( rayPointDistanceSq ), 23898 point: intersectPoint.clone(), 23899 index: index, 23900 face: null, 23901 object: object 23902 23903 } ); 23904 23905 } 23906 23907 } 23908 23909 if ( geometry.isBufferGeometry ) { 23910 23911 var index = geometry.index; 23912 var attributes = geometry.attributes; 23913 var positions = attributes.position.array; 23914 23915 if ( index !== null ) { 23916 23917 var indices = index.array; 23918 23919 for ( var i = 0, il = indices.length; i < il; i ++ ) { 23920 23921 var a = indices[ i ]; 23922 23923 position.fromArray( positions, a * 3 ); 23924 23925 testPoint( position, a ); 23926 23927 } 23928 23929 } else { 23930 23931 for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { 23932 23933 position.fromArray( positions, i * 3 ); 23934 23935 testPoint( position, i ); 23936 23937 } 23938 23939 } 23940 23941 } else { 23942 23943 var vertices = geometry.vertices; 23944 23945 for ( var i = 0, l = vertices.length; i < l; i ++ ) { 23946 23947 testPoint( vertices[ i ], i ); 23948 23949 } 23950 23951 } 23952 23953 }; 23954 23955 }() ), 23956 23957 clone: function () { 23958 23959 return new this.constructor( this.geometry, this.material ).copy( this ); 23960 23961 } 23962 23963 } ); 23964 23965 /** 23966 * @author mrdoob / http://mrdoob.com/ 23967 */ 23968 23969 function Group() { 23970 23971 Object3D.call( this ); 23972 23973 this.type = 'Group'; 23974 23975 } 23976 23977 Group.prototype = Object.assign( Object.create( Object3D.prototype ), { 23978 23979 constructor: Group 23980 23981 } ); 23982 23983 /** 23984 * @author mrdoob / http://mrdoob.com/ 23985 */ 23986 23987 function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 23988 23989 Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 23990 23991 this.generateMipmaps = false; 23992 23993 var scope = this; 23994 23995 function update() { 23996 23997 requestAnimationFrame( update ); 23998 23999 if ( video.readyState >= video.HAVE_CURRENT_DATA ) { 24000 24001 scope.needsUpdate = true; 24002 24003 } 24004 24005 } 24006 24007 update(); 24008 24009 } 24010 24011 VideoTexture.prototype = Object.create( Texture.prototype ); 24012 VideoTexture.prototype.constructor = VideoTexture; 24013 24014 /** 24015 * @author alteredq / http://alteredqualia.com/ 24016 */ 24017 24018 function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { 24019 24020 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); 24021 24022 this.image = { width: width, height: height }; 24023 this.mipmaps = mipmaps; 24024 24025 // no flipping for cube textures 24026 // (also flipping doesn't work for compressed textures ) 24027 24028 this.flipY = false; 24029 24030 // can't generate mipmaps for compressed textures 24031 // mips must be embedded in DDS files 24032 24033 this.generateMipmaps = false; 24034 24035 } 24036 24037 CompressedTexture.prototype = Object.create( Texture.prototype ); 24038 CompressedTexture.prototype.constructor = CompressedTexture; 24039 24040 CompressedTexture.prototype.isCompressedTexture = true; 24041 24042 /** 24043 * @author mrdoob / http://mrdoob.com/ 24044 */ 24045 24046 function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 24047 24048 Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 24049 24050 this.needsUpdate = true; 24051 24052 } 24053 24054 CanvasTexture.prototype = Object.create( Texture.prototype ); 24055 CanvasTexture.prototype.constructor = CanvasTexture; 24056 24057 /** 24058 * @author Matt DesLauriers / @mattdesl 24059 * @author atix / arthursilber.de 24060 */ 24061 24062 function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { 24063 24064 format = format !== undefined ? format : DepthFormat; 24065 24066 if ( format !== DepthFormat && format !== DepthStencilFormat ) { 24067 24068 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ) 24069 24070 } 24071 24072 if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; 24073 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; 24074 24075 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 24076 24077 this.image = { width: width, height: height }; 24078 24079 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; 24080 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; 24081 24082 this.flipY = false; 24083 this.generateMipmaps = false; 24084 24085 } 24086 24087 DepthTexture.prototype = Object.create( Texture.prototype ); 24088 DepthTexture.prototype.constructor = DepthTexture; 24089 DepthTexture.prototype.isDepthTexture = true; 24090 24091 /** 24092 * @author mrdoob / http://mrdoob.com/ 24093 * @author Mugen87 / https://github.com/Mugen87 24094 */ 24095 24096 function WireframeGeometry( geometry ) { 24097 24098 BufferGeometry.call( this ); 24099 24100 this.type = 'WireframeGeometry'; 24101 24102 // buffer 24103 24104 var vertices = []; 24105 24106 // helper variables 24107 24108 var i, j, l, o, ol; 24109 var edge = [ 0, 0 ], edges = {}, e; 24110 var key, keys = [ 'a', 'b', 'c' ]; 24111 var vertex; 24112 24113 // different logic for Geometry and BufferGeometry 24114 24115 if ( geometry && geometry.isGeometry ) { 24116 24117 // create a data structure that contains all edges without duplicates 24118 24119 var faces = geometry.faces; 24120 24121 for ( i = 0, l = faces.length; i < l; i ++ ) { 24122 24123 var face = faces[ i ]; 24124 24125 for ( j = 0; j < 3; j ++ ) { 24126 24127 edge[ 0 ] = face[ keys[ j ] ]; 24128 edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; 24129 edge.sort( sortFunction ); // sorting prevents duplicates 24130 24131 key = edge.toString(); 24132 24133 if ( edges[ key ] === undefined ) { 24134 24135 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; 24136 24137 } 24138 24139 } 24140 24141 } 24142 24143 // generate vertices 24144 24145 for ( key in edges ) { 24146 24147 e = edges[ key ]; 24148 24149 vertex = geometry.vertices[ e.index1 ]; 24150 vertices.push( vertex.x, vertex.y, vertex.z ); 24151 24152 vertex = geometry.vertices[ e.index2 ]; 24153 vertices.push( vertex.x, vertex.y, vertex.z ); 24154 24155 } 24156 24157 } else if ( geometry && geometry.isBufferGeometry ) { 24158 24159 var position, indices, groups; 24160 var group, start, count; 24161 var index1, index2; 24162 24163 vertex = new Vector3(); 24164 24165 if ( geometry.index !== null ) { 24166 24167 // indexed BufferGeometry 24168 24169 position = geometry.attributes.position; 24170 indices = geometry.index; 24171 groups = geometry.groups; 24172 24173 if ( groups.length === 0 ) { 24174 24175 geometry.addGroup( 0, indices.count ); 24176 24177 } 24178 24179 // create a data structure that contains all eges without duplicates 24180 24181 for ( o = 0, ol = groups.length; o < ol; ++ o ) { 24182 24183 group = groups[ o ]; 24184 24185 start = group.start; 24186 count = group.count; 24187 24188 for ( i = start, l = ( start + count ); i < l; i += 3 ) { 24189 24190 for ( j = 0; j < 3; j ++ ) { 24191 24192 edge[ 0 ] = indices.getX( i + j ); 24193 edge[ 1 ] = indices.getX( i + ( j + 1 ) % 3 ); 24194 edge.sort( sortFunction ); // sorting prevents duplicates 24195 24196 key = edge.toString(); 24197 24198 if ( edges[ key ] === undefined ) { 24199 24200 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; 24201 24202 } 24203 24204 } 24205 24206 } 24207 24208 } 24209 24210 // generate vertices 24211 24212 for ( key in edges ) { 24213 24214 e = edges[ key ]; 24215 24216 vertex.fromBufferAttribute( position, e.index1 ); 24217 vertices.push( vertex.x, vertex.y, vertex.z ); 24218 24219 vertex.fromBufferAttribute( position, e.index2 ); 24220 vertices.push( vertex.x, vertex.y, vertex.z ); 24221 24222 } 24223 24224 } else { 24225 24226 // non-indexed BufferGeometry 24227 24228 position = geometry.attributes.position; 24229 24230 for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { 24231 24232 for ( j = 0; j < 3; j ++ ) { 24233 24234 // three edges per triangle, an edge is represented as (index1, index2) 24235 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) 24236 24237 index1 = 3 * i + j; 24238 vertex.fromBufferAttribute( position, index1 ); 24239 vertices.push( vertex.x, vertex.y, vertex.z ); 24240 24241 index2 = 3 * i + ( ( j + 1 ) % 3 ); 24242 vertex.fromBufferAttribute( position, index2 ); 24243 vertices.push( vertex.x, vertex.y, vertex.z ); 24244 24245 } 24246 24247 } 24248 24249 } 24250 24251 } 24252 24253 // build geometry 24254 24255 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 24256 24257 // custom array sort function 24258 24259 function sortFunction( a, b ) { 24260 24261 return a - b; 24262 24263 } 24264 24265 } 24266 24267 WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); 24268 WireframeGeometry.prototype.constructor = WireframeGeometry; 24269 24270 /** 24271 * @author zz85 / https://github.com/zz85 24272 * 24273 * Parametric Surfaces Geometry 24274 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 24275 */ 24276 24277 function ParametricGeometry( func, slices, stacks ) { 24278 24279 Geometry.call( this ); 24280 24281 this.type = 'ParametricGeometry'; 24282 24283 this.parameters = { 24284 func: func, 24285 slices: slices, 24286 stacks: stacks 24287 }; 24288 24289 this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); 24290 this.mergeVertices(); 24291 24292 } 24293 24294 ParametricGeometry.prototype = Object.create( Geometry.prototype ); 24295 ParametricGeometry.prototype.constructor = ParametricGeometry; 24296 24297 /** 24298 * @author Mugen87 / https://github.com/Mugen87 24299 * 24300 * Parametric Surfaces Geometry 24301 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 24302 */ 24303 24304 function ParametricBufferGeometry( func, slices, stacks ) { 24305 24306 BufferGeometry.call( this ); 24307 24308 this.type = 'ParametricBufferGeometry'; 24309 24310 this.parameters = { 24311 func: func, 24312 slices: slices, 24313 stacks: stacks 24314 }; 24315 24316 // buffers 24317 24318 var indices = []; 24319 var vertices = []; 24320 var uvs = []; 24321 24322 var i, j; 24323 24324 // generate vertices and uvs 24325 24326 var sliceCount = slices + 1; 24327 24328 for ( i = 0; i <= stacks; i ++ ) { 24329 24330 var v = i / stacks; 24331 24332 for ( j = 0; j <= slices; j ++ ) { 24333 24334 var u = j / slices; 24335 24336 var p = func( u, v ); 24337 vertices.push( p.x, p.y, p.z ); 24338 24339 uvs.push( u, v ); 24340 24341 } 24342 24343 } 24344 24345 // generate indices 24346 24347 for ( i = 0; i < stacks; i ++ ) { 24348 24349 for ( j = 0; j < slices; j ++ ) { 24350 24351 var a = i * sliceCount + j; 24352 var b = i * sliceCount + j + 1; 24353 var c = ( i + 1 ) * sliceCount + j + 1; 24354 var d = ( i + 1 ) * sliceCount + j; 24355 24356 // faces one and two 24357 24358 indices.push( a, b, d ); 24359 indices.push( b, c, d ); 24360 24361 } 24362 24363 } 24364 24365 // build geometry 24366 24367 this.setIndex( indices ); 24368 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 24369 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 24370 24371 // generate normals 24372 24373 this.computeVertexNormals(); 24374 24375 } 24376 24377 ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 24378 ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; 24379 24380 /** 24381 * @author clockworkgeek / https://github.com/clockworkgeek 24382 * @author timothypratley / https://github.com/timothypratley 24383 * @author WestLangley / http://github.com/WestLangley 24384 */ 24385 24386 function PolyhedronGeometry( vertices, indices, radius, detail ) { 24387 24388 Geometry.call( this ); 24389 24390 this.type = 'PolyhedronGeometry'; 24391 24392 this.parameters = { 24393 vertices: vertices, 24394 indices: indices, 24395 radius: radius, 24396 detail: detail 24397 }; 24398 24399 this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); 24400 this.mergeVertices(); 24401 24402 } 24403 24404 PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); 24405 PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; 24406 24407 /** 24408 * @author Mugen87 / https://github.com/Mugen87 24409 */ 24410 24411 function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { 24412 24413 BufferGeometry.call( this ); 24414 24415 this.type = 'PolyhedronBufferGeometry'; 24416 24417 this.parameters = { 24418 vertices: vertices, 24419 indices: indices, 24420 radius: radius, 24421 detail: detail 24422 }; 24423 24424 radius = radius || 1; 24425 detail = detail || 0; 24426 24427 // default buffer data 24428 24429 var vertexBuffer = []; 24430 var uvBuffer = []; 24431 24432 // the subdivision creates the vertex buffer data 24433 24434 subdivide( detail ); 24435 24436 // all vertices should lie on a conceptual sphere with a given radius 24437 24438 appplyRadius( radius ); 24439 24440 // finally, create the uv data 24441 24442 generateUVs(); 24443 24444 // build non-indexed geometry 24445 24446 this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); 24447 this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); 24448 this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); 24449 this.normalizeNormals(); 24450 24451 // helper functions 24452 24453 function subdivide( detail ) { 24454 24455 var a = new Vector3(); 24456 var b = new Vector3(); 24457 var c = new Vector3(); 24458 24459 // iterate over all faces and apply a subdivison with the given detail value 24460 24461 for ( var i = 0; i < indices.length; i += 3 ) { 24462 24463 // get the vertices of the face 24464 24465 getVertexByIndex( indices[ i + 0 ], a ); 24466 getVertexByIndex( indices[ i + 1 ], b ); 24467 getVertexByIndex( indices[ i + 2 ], c ); 24468 24469 // perform subdivision 24470 24471 subdivideFace( a, b, c, detail ); 24472 24473 } 24474 24475 } 24476 24477 function subdivideFace( a, b, c, detail ) { 24478 24479 var cols = Math.pow( 2, detail ); 24480 24481 // we use this multidimensional array as a data structure for creating the subdivision 24482 24483 var v = []; 24484 24485 var i, j; 24486 24487 // construct all of the vertices for this subdivision 24488 24489 for ( i = 0; i <= cols; i ++ ) { 24490 24491 v[ i ] = []; 24492 24493 var aj = a.clone().lerp( c, i / cols ); 24494 var bj = b.clone().lerp( c, i / cols ); 24495 24496 var rows = cols - i; 24497 24498 for ( j = 0; j <= rows; j ++ ) { 24499 24500 if ( j === 0 && i === cols ) { 24501 24502 v[ i ][ j ] = aj; 24503 24504 } else { 24505 24506 v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); 24507 24508 } 24509 24510 } 24511 24512 } 24513 24514 // construct all of the faces 24515 24516 for ( i = 0; i < cols; i ++ ) { 24517 24518 for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { 24519 24520 var k = Math.floor( j / 2 ); 24521 24522 if ( j % 2 === 0 ) { 24523 24524 pushVertex( v[ i ][ k + 1 ] ); 24525 pushVertex( v[ i + 1 ][ k ] ); 24526 pushVertex( v[ i ][ k ] ); 24527 24528 } else { 24529 24530 pushVertex( v[ i ][ k + 1 ] ); 24531 pushVertex( v[ i + 1 ][ k + 1 ] ); 24532 pushVertex( v[ i + 1 ][ k ] ); 24533 24534 } 24535 24536 } 24537 24538 } 24539 24540 } 24541 24542 function appplyRadius( radius ) { 24543 24544 var vertex = new Vector3(); 24545 24546 // iterate over the entire buffer and apply the radius to each vertex 24547 24548 for ( var i = 0; i < vertexBuffer.length; i += 3 ) { 24549 24550 vertex.x = vertexBuffer[ i + 0 ]; 24551 vertex.y = vertexBuffer[ i + 1 ]; 24552 vertex.z = vertexBuffer[ i + 2 ]; 24553 24554 vertex.normalize().multiplyScalar( radius ); 24555 24556 vertexBuffer[ i + 0 ] = vertex.x; 24557 vertexBuffer[ i + 1 ] = vertex.y; 24558 vertexBuffer[ i + 2 ] = vertex.z; 24559 24560 } 24561 24562 } 24563 24564 function generateUVs() { 24565 24566 var vertex = new Vector3(); 24567 24568 for ( var i = 0; i < vertexBuffer.length; i += 3 ) { 24569 24570 vertex.x = vertexBuffer[ i + 0 ]; 24571 vertex.y = vertexBuffer[ i + 1 ]; 24572 vertex.z = vertexBuffer[ i + 2 ]; 24573 24574 var u = azimuth( vertex ) / 2 / Math.PI + 0.5; 24575 var v = inclination( vertex ) / Math.PI + 0.5; 24576 uvBuffer.push( u, 1 - v ); 24577 24578 } 24579 24580 correctUVs(); 24581 24582 correctSeam(); 24583 24584 } 24585 24586 function correctSeam() { 24587 24588 // handle case when face straddles the seam, see #3269 24589 24590 for ( var i = 0; i < uvBuffer.length; i += 6 ) { 24591 24592 // uv data of a single face 24593 24594 var x0 = uvBuffer[ i + 0 ]; 24595 var x1 = uvBuffer[ i + 2 ]; 24596 var x2 = uvBuffer[ i + 4 ]; 24597 24598 var max = Math.max( x0, x1, x2 ); 24599 var min = Math.min( x0, x1, x2 ); 24600 24601 // 0.9 is somewhat arbitrary 24602 24603 if ( max > 0.9 && min < 0.1 ) { 24604 24605 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; 24606 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; 24607 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; 24608 24609 } 24610 24611 } 24612 24613 } 24614 24615 function pushVertex( vertex ) { 24616 24617 vertexBuffer.push( vertex.x, vertex.y, vertex.z ); 24618 24619 } 24620 24621 function getVertexByIndex( index, vertex ) { 24622 24623 var stride = index * 3; 24624 24625 vertex.x = vertices[ stride + 0 ]; 24626 vertex.y = vertices[ stride + 1 ]; 24627 vertex.z = vertices[ stride + 2 ]; 24628 24629 } 24630 24631 function correctUVs() { 24632 24633 var a = new Vector3(); 24634 var b = new Vector3(); 24635 var c = new Vector3(); 24636 24637 var centroid = new Vector3(); 24638 24639 var uvA = new Vector2(); 24640 var uvB = new Vector2(); 24641 var uvC = new Vector2(); 24642 24643 for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { 24644 24645 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); 24646 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); 24647 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); 24648 24649 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); 24650 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); 24651 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); 24652 24653 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); 24654 24655 var azi = azimuth( centroid ); 24656 24657 correctUV( uvA, j + 0, a, azi ); 24658 correctUV( uvB, j + 2, b, azi ); 24659 correctUV( uvC, j + 4, c, azi ); 24660 24661 } 24662 24663 } 24664 24665 function correctUV( uv, stride, vector, azimuth ) { 24666 24667 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { 24668 24669 uvBuffer[ stride ] = uv.x - 1; 24670 24671 } 24672 24673 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { 24674 24675 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; 24676 24677 } 24678 24679 } 24680 24681 // Angle around the Y axis, counter-clockwise when looking from above. 24682 24683 function azimuth( vector ) { 24684 24685 return Math.atan2( vector.z, - vector.x ); 24686 24687 } 24688 24689 24690 // Angle above the XZ plane. 24691 24692 function inclination( vector ) { 24693 24694 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); 24695 24696 } 24697 24698 } 24699 24700 PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 24701 PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; 24702 24703 /** 24704 * @author timothypratley / https://github.com/timothypratley 24705 */ 24706 24707 function TetrahedronGeometry( radius, detail ) { 24708 24709 Geometry.call( this ); 24710 24711 this.type = 'TetrahedronGeometry'; 24712 24713 this.parameters = { 24714 radius: radius, 24715 detail: detail 24716 }; 24717 24718 this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); 24719 this.mergeVertices(); 24720 24721 } 24722 24723 TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); 24724 TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; 24725 24726 /** 24727 * @author Mugen87 / https://github.com/Mugen87 24728 */ 24729 24730 function TetrahedronBufferGeometry( radius, detail ) { 24731 24732 var vertices = [ 24733 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 24734 ]; 24735 24736 var indices = [ 24737 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 24738 ]; 24739 24740 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); 24741 24742 this.type = 'TetrahedronBufferGeometry'; 24743 24744 this.parameters = { 24745 radius: radius, 24746 detail: detail 24747 }; 24748 24749 } 24750 24751 TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); 24752 TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; 24753 24754 /** 24755 * @author timothypratley / https://github.com/timothypratley 24756 */ 24757 24758 function OctahedronGeometry( radius, detail ) { 24759 24760 Geometry.call( this ); 24761 24762 this.type = 'OctahedronGeometry'; 24763 24764 this.parameters = { 24765 radius: radius, 24766 detail: detail 24767 }; 24768 24769 this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); 24770 this.mergeVertices(); 24771 24772 } 24773 24774 OctahedronGeometry.prototype = Object.create( Geometry.prototype ); 24775 OctahedronGeometry.prototype.constructor = OctahedronGeometry; 24776 24777 /** 24778 * @author Mugen87 / https://github.com/Mugen87 24779 */ 24780 24781 function OctahedronBufferGeometry( radius, detail ) { 24782 24783 var vertices = [ 24784 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1 24785 ]; 24786 24787 var indices = [ 24788 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2 24789 ]; 24790 24791 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); 24792 24793 this.type = 'OctahedronBufferGeometry'; 24794 24795 this.parameters = { 24796 radius: radius, 24797 detail: detail 24798 }; 24799 24800 } 24801 24802 OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); 24803 OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; 24804 24805 /** 24806 * @author timothypratley / https://github.com/timothypratley 24807 */ 24808 24809 function IcosahedronGeometry( radius, detail ) { 24810 24811 Geometry.call( this ); 24812 24813 this.type = 'IcosahedronGeometry'; 24814 24815 this.parameters = { 24816 radius: radius, 24817 detail: detail 24818 }; 24819 24820 this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); 24821 this.mergeVertices(); 24822 24823 } 24824 24825 IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); 24826 IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; 24827 24828 /** 24829 * @author Mugen87 / https://github.com/Mugen87 24830 */ 24831 24832 function IcosahedronBufferGeometry( radius, detail ) { 24833 24834 var t = ( 1 + Math.sqrt( 5 ) ) / 2; 24835 24836 var vertices = [ 24837 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, 24838 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 24839 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 24840 ]; 24841 24842 var indices = [ 24843 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 24844 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 24845 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 24846 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 24847 ]; 24848 24849 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); 24850 24851 this.type = 'IcosahedronBufferGeometry'; 24852 24853 this.parameters = { 24854 radius: radius, 24855 detail: detail 24856 }; 24857 24858 } 24859 24860 IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); 24861 IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; 24862 24863 /** 24864 * @author Abe Pazos / https://hamoid.com 24865 */ 24866 24867 function DodecahedronGeometry( radius, detail ) { 24868 24869 Geometry.call( this ); 24870 24871 this.type = 'DodecahedronGeometry'; 24872 24873 this.parameters = { 24874 radius: radius, 24875 detail: detail 24876 }; 24877 24878 this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); 24879 this.mergeVertices(); 24880 24881 } 24882 24883 DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); 24884 DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; 24885 24886 /** 24887 * @author Mugen87 / https://github.com/Mugen87 24888 */ 24889 24890 function DodecahedronBufferGeometry( radius, detail ) { 24891 24892 var t = ( 1 + Math.sqrt( 5 ) ) / 2; 24893 var r = 1 / t; 24894 24895 var vertices = [ 24896 24897 // (±1, ±1, ±1) 24898 - 1, - 1, - 1, - 1, - 1, 1, 24899 - 1, 1, - 1, - 1, 1, 1, 24900 1, - 1, - 1, 1, - 1, 1, 24901 1, 1, - 1, 1, 1, 1, 24902 24903 // (0, ±1/φ, ±φ) 24904 0, - r, - t, 0, - r, t, 24905 0, r, - t, 0, r, t, 24906 24907 // (±1/φ, ±φ, 0) 24908 - r, - t, 0, - r, t, 0, 24909 r, - t, 0, r, t, 0, 24910 24911 // (±φ, 0, ±1/φ) 24912 - t, 0, - r, t, 0, - r, 24913 - t, 0, r, t, 0, r 24914 ]; 24915 24916 var indices = [ 24917 3, 11, 7, 3, 7, 15, 3, 15, 13, 24918 7, 19, 17, 7, 17, 6, 7, 6, 15, 24919 17, 4, 8, 17, 8, 10, 17, 10, 6, 24920 8, 0, 16, 8, 16, 2, 8, 2, 10, 24921 0, 12, 1, 0, 1, 18, 0, 18, 16, 24922 6, 10, 2, 6, 2, 13, 6, 13, 15, 24923 2, 16, 18, 2, 18, 3, 2, 3, 13, 24924 18, 1, 9, 18, 9, 11, 18, 11, 3, 24925 4, 14, 12, 4, 12, 0, 4, 0, 8, 24926 11, 9, 5, 11, 5, 19, 11, 19, 7, 24927 19, 5, 14, 19, 14, 4, 19, 4, 17, 24928 1, 12, 14, 1, 14, 5, 1, 5, 9 24929 ]; 24930 24931 PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); 24932 24933 this.type = 'DodecahedronBufferGeometry'; 24934 24935 this.parameters = { 24936 radius: radius, 24937 detail: detail 24938 }; 24939 24940 } 24941 24942 DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); 24943 DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; 24944 24945 /** 24946 * @author oosmoxiecode / https://github.com/oosmoxiecode 24947 * @author WestLangley / https://github.com/WestLangley 24948 * @author zz85 / https://github.com/zz85 24949 * @author miningold / https://github.com/miningold 24950 * @author jonobr1 / https://github.com/jonobr1 24951 * 24952 * Creates a tube which extrudes along a 3d spline. 24953 */ 24954 24955 function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { 24956 24957 Geometry.call( this ); 24958 24959 this.type = 'TubeGeometry'; 24960 24961 this.parameters = { 24962 path: path, 24963 tubularSegments: tubularSegments, 24964 radius: radius, 24965 radialSegments: radialSegments, 24966 closed: closed 24967 }; 24968 24969 if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); 24970 24971 var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); 24972 24973 // expose internals 24974 24975 this.tangents = bufferGeometry.tangents; 24976 this.normals = bufferGeometry.normals; 24977 this.binormals = bufferGeometry.binormals; 24978 24979 // create geometry 24980 24981 this.fromBufferGeometry( bufferGeometry ); 24982 this.mergeVertices(); 24983 24984 } 24985 24986 TubeGeometry.prototype = Object.create( Geometry.prototype ); 24987 TubeGeometry.prototype.constructor = TubeGeometry; 24988 24989 /** 24990 * @author Mugen87 / https://github.com/Mugen87 24991 */ 24992 24993 function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { 24994 24995 BufferGeometry.call( this ); 24996 24997 this.type = 'TubeBufferGeometry'; 24998 24999 this.parameters = { 25000 path: path, 25001 tubularSegments: tubularSegments, 25002 radius: radius, 25003 radialSegments: radialSegments, 25004 closed: closed 25005 }; 25006 25007 tubularSegments = tubularSegments || 64; 25008 radius = radius || 1; 25009 radialSegments = radialSegments || 8; 25010 closed = closed || false; 25011 25012 var frames = path.computeFrenetFrames( tubularSegments, closed ); 25013 25014 // expose internals 25015 25016 this.tangents = frames.tangents; 25017 this.normals = frames.normals; 25018 this.binormals = frames.binormals; 25019 25020 // helper variables 25021 25022 var vertex = new Vector3(); 25023 var normal = new Vector3(); 25024 var uv = new Vector2(); 25025 25026 var i, j; 25027 25028 // buffer 25029 25030 var vertices = []; 25031 var normals = []; 25032 var uvs = []; 25033 var indices = []; 25034 25035 // create buffer data 25036 25037 generateBufferData(); 25038 25039 // build geometry 25040 25041 this.setIndex( indices ); 25042 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 25043 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 25044 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 25045 25046 // functions 25047 25048 function generateBufferData() { 25049 25050 for ( i = 0; i < tubularSegments; i ++ ) { 25051 25052 generateSegment( i ); 25053 25054 } 25055 25056 // if the geometry is not closed, generate the last row of vertices and normals 25057 // at the regular position on the given path 25058 // 25059 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) 25060 25061 generateSegment( ( closed === false ) ? tubularSegments : 0 ); 25062 25063 // uvs are generated in a separate function. 25064 // this makes it easy compute correct values for closed geometries 25065 25066 generateUVs(); 25067 25068 // finally create faces 25069 25070 generateIndices(); 25071 25072 } 25073 25074 function generateSegment( i ) { 25075 25076 // we use getPointAt to sample evenly distributed points from the given path 25077 25078 var P = path.getPointAt( i / tubularSegments ); 25079 25080 // retrieve corresponding normal and binormal 25081 25082 var N = frames.normals[ i ]; 25083 var B = frames.binormals[ i ]; 25084 25085 // generate normals and vertices for the current segment 25086 25087 for ( j = 0; j <= radialSegments; j ++ ) { 25088 25089 var v = j / radialSegments * Math.PI * 2; 25090 25091 var sin = Math.sin( v ); 25092 var cos = - Math.cos( v ); 25093 25094 // normal 25095 25096 normal.x = ( cos * N.x + sin * B.x ); 25097 normal.y = ( cos * N.y + sin * B.y ); 25098 normal.z = ( cos * N.z + sin * B.z ); 25099 normal.normalize(); 25100 25101 normals.push( normal.x, normal.y, normal.z ); 25102 25103 // vertex 25104 25105 vertex.x = P.x + radius * normal.x; 25106 vertex.y = P.y + radius * normal.y; 25107 vertex.z = P.z + radius * normal.z; 25108 25109 vertices.push( vertex.x, vertex.y, vertex.z ); 25110 25111 } 25112 25113 } 25114 25115 function generateIndices() { 25116 25117 for ( j = 1; j <= tubularSegments; j ++ ) { 25118 25119 for ( i = 1; i <= radialSegments; i ++ ) { 25120 25121 var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 25122 var b = ( radialSegments + 1 ) * j + ( i - 1 ); 25123 var c = ( radialSegments + 1 ) * j + i; 25124 var d = ( radialSegments + 1 ) * ( j - 1 ) + i; 25125 25126 // faces 25127 25128 indices.push( a, b, d ); 25129 indices.push( b, c, d ); 25130 25131 } 25132 25133 } 25134 25135 } 25136 25137 function generateUVs() { 25138 25139 for ( i = 0; i <= tubularSegments; i ++ ) { 25140 25141 for ( j = 0; j <= radialSegments; j ++ ) { 25142 25143 uv.x = i / tubularSegments; 25144 uv.y = j / radialSegments; 25145 25146 uvs.push( uv.x, uv.y ); 25147 25148 } 25149 25150 } 25151 25152 } 25153 25154 } 25155 25156 TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 25157 TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; 25158 25159 /** 25160 * @author oosmoxiecode 25161 */ 25162 25163 function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { 25164 25165 Geometry.call( this ); 25166 25167 this.type = 'TorusKnotGeometry'; 25168 25169 this.parameters = { 25170 radius: radius, 25171 tube: tube, 25172 tubularSegments: tubularSegments, 25173 radialSegments: radialSegments, 25174 p: p, 25175 q: q 25176 }; 25177 25178 if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); 25179 25180 this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); 25181 this.mergeVertices(); 25182 25183 } 25184 25185 TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); 25186 TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; 25187 25188 /** 25189 * @author Mugen87 / https://github.com/Mugen87 25190 * see: http://www.blackpawn.com/texts/pqtorus/ 25191 */ 25192 25193 function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { 25194 25195 BufferGeometry.call( this ); 25196 25197 this.type = 'TorusKnotBufferGeometry'; 25198 25199 this.parameters = { 25200 radius: radius, 25201 tube: tube, 25202 tubularSegments: tubularSegments, 25203 radialSegments: radialSegments, 25204 p: p, 25205 q: q 25206 }; 25207 25208 radius = radius || 100; 25209 tube = tube || 40; 25210 tubularSegments = Math.floor( tubularSegments ) || 64; 25211 radialSegments = Math.floor( radialSegments ) || 8; 25212 p = p || 2; 25213 q = q || 3; 25214 25215 // buffers 25216 25217 var indices = []; 25218 var vertices = []; 25219 var normals = []; 25220 var uvs = []; 25221 25222 // helper variables 25223 25224 var i, j; 25225 25226 var vertex = new Vector3(); 25227 var normal = new Vector3(); 25228 var uv = new Vector2(); 25229 25230 var P1 = new Vector3(); 25231 var P2 = new Vector3(); 25232 25233 var B = new Vector3(); 25234 var T = new Vector3(); 25235 var N = new Vector3(); 25236 25237 // generate vertices, normals and uvs 25238 25239 for ( i = 0; i <= tubularSegments; ++ i ) { 25240 25241 // the radian "u" is used to calculate the position on the torus curve of the current tubular segement 25242 25243 var u = i / tubularSegments * p * Math.PI * 2; 25244 25245 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. 25246 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions 25247 25248 calculatePositionOnCurve( u, p, q, radius, P1 ); 25249 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); 25250 25251 // calculate orthonormal basis 25252 25253 T.subVectors( P2, P1 ); 25254 N.addVectors( P2, P1 ); 25255 B.crossVectors( T, N ); 25256 N.crossVectors( B, T ); 25257 25258 // normalize B, N. T can be ignored, we don't use it 25259 25260 B.normalize(); 25261 N.normalize(); 25262 25263 for ( j = 0; j <= radialSegments; ++ j ) { 25264 25265 // now calculate the vertices. they are nothing more than an extrusion of the torus curve. 25266 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. 25267 25268 var v = j / radialSegments * Math.PI * 2; 25269 var cx = - tube * Math.cos( v ); 25270 var cy = tube * Math.sin( v ); 25271 25272 // now calculate the final vertex position. 25273 // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve 25274 25275 vertex.x = P1.x + ( cx * N.x + cy * B.x ); 25276 vertex.y = P1.y + ( cx * N.y + cy * B.y ); 25277 vertex.z = P1.z + ( cx * N.z + cy * B.z ); 25278 25279 vertices.push( vertex.x, vertex.y, vertex.z ); 25280 25281 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) 25282 25283 normal.subVectors( vertex, P1 ).normalize(); 25284 25285 normals.push( normal.x, normal.y, normal.z ); 25286 25287 // uv 25288 25289 uvs.push( i / tubularSegments ); 25290 uvs.push( j / radialSegments ); 25291 25292 } 25293 25294 } 25295 25296 // generate indices 25297 25298 for ( j = 1; j <= tubularSegments; j ++ ) { 25299 25300 for ( i = 1; i <= radialSegments; i ++ ) { 25301 25302 // indices 25303 25304 var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 25305 var b = ( radialSegments + 1 ) * j + ( i - 1 ); 25306 var c = ( radialSegments + 1 ) * j + i; 25307 var d = ( radialSegments + 1 ) * ( j - 1 ) + i; 25308 25309 // faces 25310 25311 indices.push( a, b, d ); 25312 indices.push( b, c, d ); 25313 25314 } 25315 25316 } 25317 25318 // build geometry 25319 25320 this.setIndex( indices ); 25321 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 25322 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 25323 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 25324 25325 // this function calculates the current position on the torus curve 25326 25327 function calculatePositionOnCurve( u, p, q, radius, position ) { 25328 25329 var cu = Math.cos( u ); 25330 var su = Math.sin( u ); 25331 var quOverP = q / p * u; 25332 var cs = Math.cos( quOverP ); 25333 25334 position.x = radius * ( 2 + cs ) * 0.5 * cu; 25335 position.y = radius * ( 2 + cs ) * su * 0.5; 25336 position.z = radius * Math.sin( quOverP ) * 0.5; 25337 25338 } 25339 25340 } 25341 25342 TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 25343 TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; 25344 25345 /** 25346 * @author oosmoxiecode 25347 * @author mrdoob / http://mrdoob.com/ 25348 * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 25349 */ 25350 25351 function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { 25352 25353 Geometry.call( this ); 25354 25355 this.type = 'TorusGeometry'; 25356 25357 this.parameters = { 25358 radius: radius, 25359 tube: tube, 25360 radialSegments: radialSegments, 25361 tubularSegments: tubularSegments, 25362 arc: arc 25363 }; 25364 25365 this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); 25366 25367 } 25368 25369 TorusGeometry.prototype = Object.create( Geometry.prototype ); 25370 TorusGeometry.prototype.constructor = TorusGeometry; 25371 25372 /** 25373 * @author Mugen87 / https://github.com/Mugen87 25374 */ 25375 25376 function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { 25377 25378 BufferGeometry.call( this ); 25379 25380 this.type = 'TorusBufferGeometry'; 25381 25382 this.parameters = { 25383 radius: radius, 25384 tube: tube, 25385 radialSegments: radialSegments, 25386 tubularSegments: tubularSegments, 25387 arc: arc 25388 }; 25389 25390 radius = radius || 100; 25391 tube = tube || 40; 25392 radialSegments = Math.floor( radialSegments ) || 8; 25393 tubularSegments = Math.floor( tubularSegments ) || 6; 25394 arc = arc || Math.PI * 2; 25395 25396 // buffers 25397 25398 var indices = []; 25399 var vertices = []; 25400 var normals = []; 25401 var uvs = []; 25402 25403 // helper variables 25404 25405 var center = new Vector3(); 25406 var vertex = new Vector3(); 25407 var normal = new Vector3(); 25408 25409 var j, i; 25410 25411 // generate vertices, normals and uvs 25412 25413 for ( j = 0; j <= radialSegments; j ++ ) { 25414 25415 for ( i = 0; i <= tubularSegments; i ++ ) { 25416 25417 var u = i / tubularSegments * arc; 25418 var v = j / radialSegments * Math.PI * 2; 25419 25420 // vertex 25421 25422 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); 25423 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); 25424 vertex.z = tube * Math.sin( v ); 25425 25426 vertices.push( vertex.x, vertex.y, vertex.z ); 25427 25428 // normal 25429 25430 center.x = radius * Math.cos( u ); 25431 center.y = radius * Math.sin( u ); 25432 normal.subVectors( vertex, center ).normalize(); 25433 25434 normals.push( normal.x, normal.y, normal.z ); 25435 25436 // uv 25437 25438 uvs.push( i / tubularSegments ); 25439 uvs.push( j / radialSegments ); 25440 25441 } 25442 25443 } 25444 25445 // generate indices 25446 25447 for ( j = 1; j <= radialSegments; j ++ ) { 25448 25449 for ( i = 1; i <= tubularSegments; i ++ ) { 25450 25451 // indices 25452 25453 var a = ( tubularSegments + 1 ) * j + i - 1; 25454 var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; 25455 var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; 25456 var d = ( tubularSegments + 1 ) * j + i; 25457 25458 // faces 25459 25460 indices.push( a, b, d ); 25461 indices.push( b, c, d ); 25462 25463 } 25464 25465 } 25466 25467 // build geometry 25468 25469 this.setIndex( indices ); 25470 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 25471 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 25472 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 25473 25474 } 25475 25476 TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 25477 TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; 25478 25479 /** 25480 * @author zz85 / http://www.lab4games.net/zz85/blog 25481 */ 25482 25483 var ShapeUtils = { 25484 25485 // calculate area of the contour polygon 25486 25487 area: function ( contour ) { 25488 25489 var n = contour.length; 25490 var a = 0.0; 25491 25492 for ( var p = n - 1, q = 0; q < n; p = q ++ ) { 25493 25494 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; 25495 25496 } 25497 25498 return a * 0.5; 25499 25500 }, 25501 25502 triangulate: ( function () { 25503 25504 /** 25505 * This code is a quick port of code written in C++ which was submitted to 25506 * flipcode.com by John W. Ratcliff // July 22, 2000 25507 * See original code and more information here: 25508 * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml 25509 * 25510 * ported to actionscript by Zevan Rosser 25511 * www.actionsnippet.com 25512 * 25513 * ported to javascript by Joshua Koo 25514 * http://www.lab4games.net/zz85/blog 25515 * 25516 */ 25517 25518 function snip( contour, u, v, w, n, verts ) { 25519 25520 var p; 25521 var ax, ay, bx, by; 25522 var cx, cy, px, py; 25523 25524 ax = contour[ verts[ u ] ].x; 25525 ay = contour[ verts[ u ] ].y; 25526 25527 bx = contour[ verts[ v ] ].x; 25528 by = contour[ verts[ v ] ].y; 25529 25530 cx = contour[ verts[ w ] ].x; 25531 cy = contour[ verts[ w ] ].y; 25532 25533 if ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false; 25534 25535 var aX, aY, bX, bY, cX, cY; 25536 var apx, apy, bpx, bpy, cpx, cpy; 25537 var cCROSSap, bCROSScp, aCROSSbp; 25538 25539 aX = cx - bx; aY = cy - by; 25540 bX = ax - cx; bY = ay - cy; 25541 cX = bx - ax; cY = by - ay; 25542 25543 for ( p = 0; p < n; p ++ ) { 25544 25545 px = contour[ verts[ p ] ].x; 25546 py = contour[ verts[ p ] ].y; 25547 25548 if ( ( ( px === ax ) && ( py === ay ) ) || 25549 ( ( px === bx ) && ( py === by ) ) || 25550 ( ( px === cx ) && ( py === cy ) ) ) continue; 25551 25552 apx = px - ax; apy = py - ay; 25553 bpx = px - bx; bpy = py - by; 25554 cpx = px - cx; cpy = py - cy; 25555 25556 // see if p is inside triangle abc 25557 25558 aCROSSbp = aX * bpy - aY * bpx; 25559 cCROSSap = cX * apy - cY * apx; 25560 bCROSScp = bX * cpy - bY * cpx; 25561 25562 if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false; 25563 25564 } 25565 25566 return true; 25567 25568 } 25569 25570 // takes in an contour array and returns 25571 25572 return function triangulate( contour, indices ) { 25573 25574 var n = contour.length; 25575 25576 if ( n < 3 ) return null; 25577 25578 var result = [], 25579 verts = [], 25580 vertIndices = []; 25581 25582 /* we want a counter-clockwise polygon in verts */ 25583 25584 var u, v, w; 25585 25586 if ( ShapeUtils.area( contour ) > 0.0 ) { 25587 25588 for ( v = 0; v < n; v ++ ) verts[ v ] = v; 25589 25590 } else { 25591 25592 for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; 25593 25594 } 25595 25596 var nv = n; 25597 25598 /* remove nv - 2 vertices, creating 1 triangle every time */ 25599 25600 var count = 2 * nv; /* error detection */ 25601 25602 for ( v = nv - 1; nv > 2; ) { 25603 25604 /* if we loop, it is probably a non-simple polygon */ 25605 25606 if ( ( count -- ) <= 0 ) { 25607 25608 //** Triangulate: ERROR - probable bad polygon! 25609 25610 //throw ( "Warning, unable to triangulate polygon!" ); 25611 //return null; 25612 // Sometimes warning is fine, especially polygons are triangulated in reverse. 25613 console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' ); 25614 25615 if ( indices ) return vertIndices; 25616 return result; 25617 25618 } 25619 25620 /* three consecutive vertices in current polygon, <u,v,w> */ 25621 25622 u = v; if ( nv <= u ) u = 0; /* previous */ 25623 v = u + 1; if ( nv <= v ) v = 0; /* new v */ 25624 w = v + 1; if ( nv <= w ) w = 0; /* next */ 25625 25626 if ( snip( contour, u, v, w, nv, verts ) ) { 25627 25628 var a, b, c, s, t; 25629 25630 /* true names of the vertices */ 25631 25632 a = verts[ u ]; 25633 b = verts[ v ]; 25634 c = verts[ w ]; 25635 25636 /* output Triangle */ 25637 25638 result.push( [ contour[ a ], 25639 contour[ b ], 25640 contour[ c ] ] ); 25641 25642 25643 vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); 25644 25645 /* remove v from the remaining polygon */ 25646 25647 for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { 25648 25649 verts[ s ] = verts[ t ]; 25650 25651 } 25652 25653 nv --; 25654 25655 /* reset error detection counter */ 25656 25657 count = 2 * nv; 25658 25659 } 25660 25661 } 25662 25663 if ( indices ) return vertIndices; 25664 return result; 25665 25666 } 25667 25668 } )(), 25669 25670 triangulateShape: function ( contour, holes ) { 25671 25672 function removeDupEndPts(points) { 25673 25674 var l = points.length; 25675 25676 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { 25677 25678 points.pop(); 25679 25680 } 25681 25682 } 25683 25684 removeDupEndPts( contour ); 25685 holes.forEach( removeDupEndPts ); 25686 25687 function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { 25688 25689 // inOtherPt needs to be collinear to the inSegment 25690 if ( inSegPt1.x !== inSegPt2.x ) { 25691 25692 if ( inSegPt1.x < inSegPt2.x ) { 25693 25694 return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); 25695 25696 } else { 25697 25698 return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); 25699 25700 } 25701 25702 } else { 25703 25704 if ( inSegPt1.y < inSegPt2.y ) { 25705 25706 return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); 25707 25708 } else { 25709 25710 return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); 25711 25712 } 25713 25714 } 25715 25716 } 25717 25718 function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { 25719 25720 var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; 25721 var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; 25722 25723 var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; 25724 var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; 25725 25726 var limit = seg1dy * seg2dx - seg1dx * seg2dy; 25727 var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; 25728 25729 if ( Math.abs( limit ) > Number.EPSILON ) { 25730 25731 // not parallel 25732 25733 var perpSeg2; 25734 if ( limit > 0 ) { 25735 25736 if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; 25737 perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; 25738 if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; 25739 25740 } else { 25741 25742 if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; 25743 perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; 25744 if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; 25745 25746 } 25747 25748 // i.e. to reduce rounding errors 25749 // intersection at endpoint of segment#1? 25750 if ( perpSeg2 === 0 ) { 25751 25752 if ( ( inExcludeAdjacentSegs ) && 25753 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; 25754 return [ inSeg1Pt1 ]; 25755 25756 } 25757 if ( perpSeg2 === limit ) { 25758 25759 if ( ( inExcludeAdjacentSegs ) && 25760 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; 25761 return [ inSeg1Pt2 ]; 25762 25763 } 25764 // intersection at endpoint of segment#2? 25765 if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ]; 25766 if ( perpSeg1 === limit ) return [ inSeg2Pt2 ]; 25767 25768 // return real intersection point 25769 var factorSeg1 = perpSeg2 / limit; 25770 return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, 25771 y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; 25772 25773 } else { 25774 25775 // parallel or collinear 25776 if ( ( perpSeg1 !== 0 ) || 25777 ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return []; 25778 25779 // they are collinear or degenerate 25780 var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point? 25781 var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point? 25782 // both segments are points 25783 if ( seg1Pt && seg2Pt ) { 25784 25785 if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) || 25786 ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points 25787 return [ inSeg1Pt1 ]; // they are the same point 25788 25789 } 25790 // segment#1 is a single point 25791 if ( seg1Pt ) { 25792 25793 if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 25794 return [ inSeg1Pt1 ]; 25795 25796 } 25797 // segment#2 is a single point 25798 if ( seg2Pt ) { 25799 25800 if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 25801 return [ inSeg2Pt1 ]; 25802 25803 } 25804 25805 // they are collinear segments, which might overlap 25806 var seg1min, seg1max, seg1minVal, seg1maxVal; 25807 var seg2min, seg2max, seg2minVal, seg2maxVal; 25808 if ( seg1dx !== 0 ) { 25809 25810 // the segments are NOT on a vertical line 25811 if ( inSeg1Pt1.x < inSeg1Pt2.x ) { 25812 25813 seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; 25814 seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; 25815 25816 } else { 25817 25818 seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; 25819 seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; 25820 25821 } 25822 if ( inSeg2Pt1.x < inSeg2Pt2.x ) { 25823 25824 seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; 25825 seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; 25826 25827 } else { 25828 25829 seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; 25830 seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; 25831 25832 } 25833 25834 } else { 25835 25836 // the segments are on a vertical line 25837 if ( inSeg1Pt1.y < inSeg1Pt2.y ) { 25838 25839 seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; 25840 seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; 25841 25842 } else { 25843 25844 seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; 25845 seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; 25846 25847 } 25848 if ( inSeg2Pt1.y < inSeg2Pt2.y ) { 25849 25850 seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; 25851 seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; 25852 25853 } else { 25854 25855 seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; 25856 seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; 25857 25858 } 25859 25860 } 25861 if ( seg1minVal <= seg2minVal ) { 25862 25863 if ( seg1maxVal < seg2minVal ) return []; 25864 if ( seg1maxVal === seg2minVal ) { 25865 25866 if ( inExcludeAdjacentSegs ) return []; 25867 return [ seg2min ]; 25868 25869 } 25870 if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; 25871 return [ seg2min, seg2max ]; 25872 25873 } else { 25874 25875 if ( seg1minVal > seg2maxVal ) return []; 25876 if ( seg1minVal === seg2maxVal ) { 25877 25878 if ( inExcludeAdjacentSegs ) return []; 25879 return [ seg1min ]; 25880 25881 } 25882 if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; 25883 return [ seg1min, seg2max ]; 25884 25885 } 25886 25887 } 25888 25889 } 25890 25891 function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { 25892 25893 // The order of legs is important 25894 25895 // translation of all points, so that Vertex is at (0,0) 25896 var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; 25897 var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; 25898 var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; 25899 25900 // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. 25901 var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; 25902 var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; 25903 25904 if ( Math.abs( from2toAngle ) > Number.EPSILON ) { 25905 25906 // angle != 180 deg. 25907 25908 var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; 25909 // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); 25910 25911 if ( from2toAngle > 0 ) { 25912 25913 // main angle < 180 deg. 25914 return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); 25915 25916 } else { 25917 25918 // main angle > 180 deg. 25919 return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); 25920 25921 } 25922 25923 } else { 25924 25925 // angle == 180 deg. 25926 // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); 25927 return ( from2otherAngle > 0 ); 25928 25929 } 25930 25931 } 25932 25933 25934 function removeHoles( contour, holes ) { 25935 25936 var shape = contour.concat(); // work on this shape 25937 var hole; 25938 25939 function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { 25940 25941 // Check if hole point lies within angle around shape point 25942 var lastShapeIdx = shape.length - 1; 25943 25944 var prevShapeIdx = inShapeIdx - 1; 25945 if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; 25946 25947 var nextShapeIdx = inShapeIdx + 1; 25948 if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; 25949 25950 var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] ); 25951 if ( ! insideAngle ) { 25952 25953 // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); 25954 return false; 25955 25956 } 25957 25958 // Check if shape point lies within angle around hole point 25959 var lastHoleIdx = hole.length - 1; 25960 25961 var prevHoleIdx = inHoleIdx - 1; 25962 if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; 25963 25964 var nextHoleIdx = inHoleIdx + 1; 25965 if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; 25966 25967 insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] ); 25968 if ( ! insideAngle ) { 25969 25970 // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); 25971 return false; 25972 25973 } 25974 25975 return true; 25976 25977 } 25978 25979 function intersectsShapeEdge( inShapePt, inHolePt ) { 25980 25981 // checks for intersections with shape edges 25982 var sIdx, nextIdx, intersection; 25983 for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { 25984 25985 nextIdx = sIdx + 1; nextIdx %= shape.length; 25986 intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true ); 25987 if ( intersection.length > 0 ) return true; 25988 25989 } 25990 25991 return false; 25992 25993 } 25994 25995 var indepHoles = []; 25996 25997 function intersectsHoleEdge( inShapePt, inHolePt ) { 25998 25999 // checks for intersections with hole edges 26000 var ihIdx, chkHole, 26001 hIdx, nextIdx, intersection; 26002 for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { 26003 26004 chkHole = holes[ indepHoles[ ihIdx ]]; 26005 for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { 26006 26007 nextIdx = hIdx + 1; nextIdx %= chkHole.length; 26008 intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true ); 26009 if ( intersection.length > 0 ) return true; 26010 26011 } 26012 26013 } 26014 return false; 26015 26016 } 26017 26018 var holeIndex, shapeIndex, 26019 shapePt, holePt, 26020 holeIdx, cutKey, failedCuts = [], 26021 tmpShape1, tmpShape2, 26022 tmpHole1, tmpHole2; 26023 26024 for ( var h = 0, hl = holes.length; h < hl; h ++ ) { 26025 26026 indepHoles.push( h ); 26027 26028 } 26029 26030 var minShapeIndex = 0; 26031 var counter = indepHoles.length * 2; 26032 while ( indepHoles.length > 0 ) { 26033 26034 counter --; 26035 if ( counter < 0 ) { 26036 26037 console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); 26038 break; 26039 26040 } 26041 26042 // search for shape-vertex and hole-vertex, 26043 // which can be connected without intersections 26044 for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { 26045 26046 shapePt = shape[ shapeIndex ]; 26047 holeIndex = - 1; 26048 26049 // search for hole which can be reached without intersections 26050 for ( var h = 0; h < indepHoles.length; h ++ ) { 26051 26052 holeIdx = indepHoles[ h ]; 26053 26054 // prevent multiple checks 26055 cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; 26056 if ( failedCuts[ cutKey ] !== undefined ) continue; 26057 26058 hole = holes[ holeIdx ]; 26059 for ( var h2 = 0; h2 < hole.length; h2 ++ ) { 26060 26061 holePt = hole[ h2 ]; 26062 if ( ! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; 26063 if ( intersectsShapeEdge( shapePt, holePt ) ) continue; 26064 if ( intersectsHoleEdge( shapePt, holePt ) ) continue; 26065 26066 holeIndex = h2; 26067 indepHoles.splice( h, 1 ); 26068 26069 tmpShape1 = shape.slice( 0, shapeIndex + 1 ); 26070 tmpShape2 = shape.slice( shapeIndex ); 26071 tmpHole1 = hole.slice( holeIndex ); 26072 tmpHole2 = hole.slice( 0, holeIndex + 1 ); 26073 26074 shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); 26075 26076 minShapeIndex = shapeIndex; 26077 26078 // Debug only, to show the selected cuts 26079 // glob_CutLines.push( [ shapePt, holePt ] ); 26080 26081 break; 26082 26083 } 26084 if ( holeIndex >= 0 ) break; // hole-vertex found 26085 26086 failedCuts[ cutKey ] = true; // remember failure 26087 26088 } 26089 if ( holeIndex >= 0 ) break; // hole-vertex found 26090 26091 } 26092 26093 } 26094 26095 return shape; /* shape with no holes */ 26096 26097 } 26098 26099 26100 var i, il, f, face, 26101 key, index, 26102 allPointsMap = {}; 26103 26104 // 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. 26105 26106 var allpoints = contour.concat(); 26107 26108 for ( var h = 0, hl = holes.length; h < hl; h ++ ) { 26109 26110 Array.prototype.push.apply( allpoints, holes[ h ] ); 26111 26112 } 26113 26114 //console.log( "allpoints",allpoints, allpoints.length ); 26115 26116 // prepare all points map 26117 26118 for ( i = 0, il = allpoints.length; i < il; i ++ ) { 26119 26120 key = allpoints[ i ].x + ":" + allpoints[ i ].y; 26121 26122 if ( allPointsMap[ key ] !== undefined ) { 26123 26124 console.warn( "THREE.ShapeUtils: Duplicate point", key, i ); 26125 26126 } 26127 26128 allPointsMap[ key ] = i; 26129 26130 } 26131 26132 // remove holes by cutting paths to holes and adding them to the shape 26133 var shapeWithoutHoles = removeHoles( contour, holes ); 26134 26135 var triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape 26136 //console.log( "triangles",triangles, triangles.length ); 26137 26138 // check all face vertices against all points map 26139 26140 for ( i = 0, il = triangles.length; i < il; i ++ ) { 26141 26142 face = triangles[ i ]; 26143 26144 for ( f = 0; f < 3; f ++ ) { 26145 26146 key = face[ f ].x + ":" + face[ f ].y; 26147 26148 index = allPointsMap[ key ]; 26149 26150 if ( index !== undefined ) { 26151 26152 face[ f ] = index; 26153 26154 } 26155 26156 } 26157 26158 } 26159 26160 return triangles.concat(); 26161 26162 }, 26163 26164 isClockWise: function ( pts ) { 26165 26166 return ShapeUtils.area( pts ) < 0; 26167 26168 } 26169 26170 }; 26171 26172 /** 26173 * @author zz85 / http://www.lab4games.net/zz85/blog 26174 * 26175 * Creates extruded geometry from a path shape. 26176 * 26177 * parameters = { 26178 * 26179 * curveSegments: <int>, // number of points on the curves 26180 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too 26181 * amount: <int>, // Depth to extrude the shape 26182 * 26183 * bevelEnabled: <bool>, // turn on bevel 26184 * bevelThickness: <float>, // how deep into the original shape bevel goes 26185 * bevelSize: <float>, // how far from shape outline is bevel 26186 * bevelSegments: <int>, // number of bevel layers 26187 * 26188 * extrudePath: <THREE.Curve> // curve to extrude shape along 26189 * frames: <Object> // containing arrays of tangents, normals, binormals 26190 * 26191 * uvGenerator: <Object> // object that provides UV generator functions 26192 * 26193 * } 26194 **/ 26195 26196 function ExtrudeGeometry( shapes, options ) { 26197 26198 if ( typeof( shapes ) === "undefined" ) { 26199 26200 shapes = []; 26201 return; 26202 26203 } 26204 26205 Geometry.call( this ); 26206 26207 this.type = 'ExtrudeGeometry'; 26208 26209 shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; 26210 26211 this.addShapeList( shapes, options ); 26212 26213 this.computeFaceNormals(); 26214 26215 // can't really use automatic vertex normals 26216 // as then front and back sides get smoothed too 26217 // should do separate smoothing just for sides 26218 26219 //this.computeVertexNormals(); 26220 26221 //console.log( "took", ( Date.now() - startTime ) ); 26222 26223 } 26224 26225 ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); 26226 ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; 26227 26228 ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { 26229 26230 var sl = shapes.length; 26231 26232 for ( var s = 0; s < sl; s ++ ) { 26233 26234 var shape = shapes[ s ]; 26235 this.addShape( shape, options ); 26236 26237 } 26238 26239 }; 26240 26241 ExtrudeGeometry.prototype.addShape = function ( shape, options ) { 26242 26243 var amount = options.amount !== undefined ? options.amount : 100; 26244 26245 var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 26246 var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 26247 var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; 26248 26249 var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false 26250 26251 var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; 26252 26253 var steps = options.steps !== undefined ? options.steps : 1; 26254 26255 var extrudePath = options.extrudePath; 26256 var extrudePts, extrudeByPath = false; 26257 26258 // Use default WorldUVGenerator if no UV generators are specified. 26259 var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator; 26260 26261 var splineTube, binormal, normal, position2; 26262 if ( extrudePath ) { 26263 26264 extrudePts = extrudePath.getSpacedPoints( steps ); 26265 26266 extrudeByPath = true; 26267 bevelEnabled = false; // bevels not supported for path extrusion 26268 26269 // SETUP TNB variables 26270 26271 // TODO1 - have a .isClosed in spline? 26272 26273 splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false ); 26274 26275 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); 26276 26277 binormal = new Vector3(); 26278 normal = new Vector3(); 26279 position2 = new Vector3(); 26280 26281 } 26282 26283 // Safeguards if bevels are not enabled 26284 26285 if ( ! bevelEnabled ) { 26286 26287 bevelSegments = 0; 26288 bevelThickness = 0; 26289 bevelSize = 0; 26290 26291 } 26292 26293 // Variables initialization 26294 26295 var ahole, h, hl; // looping of holes 26296 var scope = this; 26297 26298 var shapesOffset = this.vertices.length; 26299 26300 var shapePoints = shape.extractPoints( curveSegments ); 26301 26302 var vertices = shapePoints.shape; 26303 var holes = shapePoints.holes; 26304 26305 var reverse = ! ShapeUtils.isClockWise( vertices ); 26306 26307 if ( reverse ) { 26308 26309 vertices = vertices.reverse(); 26310 26311 // Maybe we should also check if holes are in the opposite direction, just to be safe ... 26312 26313 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26314 26315 ahole = holes[ h ]; 26316 26317 if ( ShapeUtils.isClockWise( ahole ) ) { 26318 26319 holes[ h ] = ahole.reverse(); 26320 26321 } 26322 26323 } 26324 26325 reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! 26326 26327 } 26328 26329 26330 var faces = ShapeUtils.triangulateShape( vertices, holes ); 26331 26332 /* Vertices */ 26333 26334 var contour = vertices; // vertices has all points but contour has only points of circumference 26335 26336 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26337 26338 ahole = holes[ h ]; 26339 26340 vertices = vertices.concat( ahole ); 26341 26342 } 26343 26344 26345 function scalePt2( pt, vec, size ) { 26346 26347 if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); 26348 26349 return vec.clone().multiplyScalar( size ).add( pt ); 26350 26351 } 26352 26353 var b, bs, t, z, 26354 vert, vlen = vertices.length, 26355 face, flen = faces.length; 26356 26357 26358 // Find directions for point movement 26359 26360 26361 function getBevelVec( inPt, inPrev, inNext ) { 26362 26363 // computes for inPt the corresponding point inPt' on a new contour 26364 // shifted by 1 unit (length of normalized vector) to the left 26365 // if we walk along contour clockwise, this new contour is outside the old one 26366 // 26367 // inPt' is the intersection of the two lines parallel to the two 26368 // adjacent edges of inPt at a distance of 1 unit on the left side. 26369 26370 var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt 26371 26372 // good reading for geometry algorithms (here: line-line intersection) 26373 // http://geomalgorithms.com/a05-_intersect-1.html 26374 26375 var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; 26376 var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; 26377 26378 var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); 26379 26380 // check for collinear edges 26381 var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 26382 26383 if ( Math.abs( collinear0 ) > Number.EPSILON ) { 26384 26385 // not collinear 26386 26387 // length of vectors for normalizing 26388 26389 var v_prev_len = Math.sqrt( v_prev_lensq ); 26390 var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); 26391 26392 // shift adjacent points by unit vectors to the left 26393 26394 var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); 26395 var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); 26396 26397 var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); 26398 var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); 26399 26400 // scaling factor for v_prev to intersection point 26401 26402 var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - 26403 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / 26404 ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 26405 26406 // vector from inPt to intersection point 26407 26408 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); 26409 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); 26410 26411 // Don't normalize!, otherwise sharp corners become ugly 26412 // but prevent crazy spikes 26413 var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); 26414 if ( v_trans_lensq <= 2 ) { 26415 26416 return new Vector2( v_trans_x, v_trans_y ); 26417 26418 } else { 26419 26420 shrink_by = Math.sqrt( v_trans_lensq / 2 ); 26421 26422 } 26423 26424 } else { 26425 26426 // handle special case of collinear edges 26427 26428 var direction_eq = false; // assumes: opposite 26429 if ( v_prev_x > Number.EPSILON ) { 26430 26431 if ( v_next_x > Number.EPSILON ) { 26432 26433 direction_eq = true; 26434 26435 } 26436 26437 } else { 26438 26439 if ( v_prev_x < - Number.EPSILON ) { 26440 26441 if ( v_next_x < - Number.EPSILON ) { 26442 26443 direction_eq = true; 26444 26445 } 26446 26447 } else { 26448 26449 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { 26450 26451 direction_eq = true; 26452 26453 } 26454 26455 } 26456 26457 } 26458 26459 if ( direction_eq ) { 26460 26461 // console.log("Warning: lines are a straight sequence"); 26462 v_trans_x = - v_prev_y; 26463 v_trans_y = v_prev_x; 26464 shrink_by = Math.sqrt( v_prev_lensq ); 26465 26466 } else { 26467 26468 // console.log("Warning: lines are a straight spike"); 26469 v_trans_x = v_prev_x; 26470 v_trans_y = v_prev_y; 26471 shrink_by = Math.sqrt( v_prev_lensq / 2 ); 26472 26473 } 26474 26475 } 26476 26477 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); 26478 26479 } 26480 26481 26482 var contourMovements = []; 26483 26484 for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 26485 26486 if ( j === il ) j = 0; 26487 if ( k === il ) k = 0; 26488 26489 // (j)---(i)---(k) 26490 // console.log('i,j,k', i, j , k) 26491 26492 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); 26493 26494 } 26495 26496 var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); 26497 26498 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26499 26500 ahole = holes[ h ]; 26501 26502 oneHoleMovements = []; 26503 26504 for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 26505 26506 if ( j === il ) j = 0; 26507 if ( k === il ) k = 0; 26508 26509 // (j)---(i)---(k) 26510 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); 26511 26512 } 26513 26514 holesMovements.push( oneHoleMovements ); 26515 verticesMovements = verticesMovements.concat( oneHoleMovements ); 26516 26517 } 26518 26519 26520 // Loop bevelSegments, 1 for the front, 1 for the back 26521 26522 for ( b = 0; b < bevelSegments; b ++ ) { 26523 26524 //for ( b = bevelSegments; b > 0; b -- ) { 26525 26526 t = b / bevelSegments; 26527 z = bevelThickness * Math.cos( t * Math.PI / 2 ); 26528 bs = bevelSize * Math.sin( t * Math.PI / 2 ); 26529 26530 // contract shape 26531 26532 for ( i = 0, il = contour.length; i < il; i ++ ) { 26533 26534 vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 26535 26536 v( vert.x, vert.y, - z ); 26537 26538 } 26539 26540 // expand holes 26541 26542 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26543 26544 ahole = holes[ h ]; 26545 oneHoleMovements = holesMovements[ h ]; 26546 26547 for ( i = 0, il = ahole.length; i < il; i ++ ) { 26548 26549 vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 26550 26551 v( vert.x, vert.y, - z ); 26552 26553 } 26554 26555 } 26556 26557 } 26558 26559 bs = bevelSize; 26560 26561 // Back facing vertices 26562 26563 for ( i = 0; i < vlen; i ++ ) { 26564 26565 vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 26566 26567 if ( ! extrudeByPath ) { 26568 26569 v( vert.x, vert.y, 0 ); 26570 26571 } else { 26572 26573 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); 26574 26575 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); 26576 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); 26577 26578 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); 26579 26580 v( position2.x, position2.y, position2.z ); 26581 26582 } 26583 26584 } 26585 26586 // Add stepped vertices... 26587 // Including front facing vertices 26588 26589 var s; 26590 26591 for ( s = 1; s <= steps; s ++ ) { 26592 26593 for ( i = 0; i < vlen; i ++ ) { 26594 26595 vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 26596 26597 if ( ! extrudeByPath ) { 26598 26599 v( vert.x, vert.y, amount / steps * s ); 26600 26601 } else { 26602 26603 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); 26604 26605 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); 26606 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); 26607 26608 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); 26609 26610 v( position2.x, position2.y, position2.z ); 26611 26612 } 26613 26614 } 26615 26616 } 26617 26618 26619 // Add bevel segments planes 26620 26621 //for ( b = 1; b <= bevelSegments; b ++ ) { 26622 for ( b = bevelSegments - 1; b >= 0; b -- ) { 26623 26624 t = b / bevelSegments; 26625 z = bevelThickness * Math.cos ( t * Math.PI / 2 ); 26626 bs = bevelSize * Math.sin( t * Math.PI / 2 ); 26627 26628 // contract shape 26629 26630 for ( i = 0, il = contour.length; i < il; i ++ ) { 26631 26632 vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 26633 v( vert.x, vert.y, amount + z ); 26634 26635 } 26636 26637 // expand holes 26638 26639 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26640 26641 ahole = holes[ h ]; 26642 oneHoleMovements = holesMovements[ h ]; 26643 26644 for ( i = 0, il = ahole.length; i < il; i ++ ) { 26645 26646 vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 26647 26648 if ( ! extrudeByPath ) { 26649 26650 v( vert.x, vert.y, amount + z ); 26651 26652 } else { 26653 26654 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); 26655 26656 } 26657 26658 } 26659 26660 } 26661 26662 } 26663 26664 /* Faces */ 26665 26666 // Top and bottom faces 26667 26668 buildLidFaces(); 26669 26670 // Sides faces 26671 26672 buildSideFaces(); 26673 26674 26675 ///// Internal functions 26676 26677 function buildLidFaces() { 26678 26679 if ( bevelEnabled ) { 26680 26681 var layer = 0; // steps + 1 26682 var offset = vlen * layer; 26683 26684 // Bottom faces 26685 26686 for ( i = 0; i < flen; i ++ ) { 26687 26688 face = faces[ i ]; 26689 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); 26690 26691 } 26692 26693 layer = steps + bevelSegments * 2; 26694 offset = vlen * layer; 26695 26696 // Top faces 26697 26698 for ( i = 0; i < flen; i ++ ) { 26699 26700 face = faces[ i ]; 26701 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); 26702 26703 } 26704 26705 } else { 26706 26707 // Bottom faces 26708 26709 for ( i = 0; i < flen; i ++ ) { 26710 26711 face = faces[ i ]; 26712 f3( face[ 2 ], face[ 1 ], face[ 0 ] ); 26713 26714 } 26715 26716 // Top faces 26717 26718 for ( i = 0; i < flen; i ++ ) { 26719 26720 face = faces[ i ]; 26721 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); 26722 26723 } 26724 26725 } 26726 26727 } 26728 26729 // Create faces for the z-sides of the shape 26730 26731 function buildSideFaces() { 26732 26733 var layeroffset = 0; 26734 sidewalls( contour, layeroffset ); 26735 layeroffset += contour.length; 26736 26737 for ( h = 0, hl = holes.length; h < hl; h ++ ) { 26738 26739 ahole = holes[ h ]; 26740 sidewalls( ahole, layeroffset ); 26741 26742 //, true 26743 layeroffset += ahole.length; 26744 26745 } 26746 26747 } 26748 26749 function sidewalls( contour, layeroffset ) { 26750 26751 var j, k; 26752 i = contour.length; 26753 26754 while ( -- i >= 0 ) { 26755 26756 j = i; 26757 k = i - 1; 26758 if ( k < 0 ) k = contour.length - 1; 26759 26760 //console.log('b', i,j, i-1, k,vertices.length); 26761 26762 var s = 0, sl = steps + bevelSegments * 2; 26763 26764 for ( s = 0; s < sl; s ++ ) { 26765 26766 var slen1 = vlen * s; 26767 var slen2 = vlen * ( s + 1 ); 26768 26769 var a = layeroffset + j + slen1, 26770 b = layeroffset + k + slen1, 26771 c = layeroffset + k + slen2, 26772 d = layeroffset + j + slen2; 26773 26774 f4( a, b, c, d, contour, s, sl, j, k ); 26775 26776 } 26777 26778 } 26779 26780 } 26781 26782 26783 function v( x, y, z ) { 26784 26785 scope.vertices.push( new Vector3( x, y, z ) ); 26786 26787 } 26788 26789 function f3( a, b, c ) { 26790 26791 a += shapesOffset; 26792 b += shapesOffset; 26793 c += shapesOffset; 26794 26795 scope.faces.push( new Face3( a, b, c, null, null, 0 ) ); 26796 26797 var uvs = uvgen.generateTopUV( scope, a, b, c ); 26798 26799 scope.faceVertexUvs[ 0 ].push( uvs ); 26800 26801 } 26802 26803 function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { 26804 26805 a += shapesOffset; 26806 b += shapesOffset; 26807 c += shapesOffset; 26808 d += shapesOffset; 26809 26810 scope.faces.push( new Face3( a, b, d, null, null, 1 ) ); 26811 scope.faces.push( new Face3( b, c, d, null, null, 1 ) ); 26812 26813 var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); 26814 26815 scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); 26816 scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); 26817 26818 } 26819 26820 }; 26821 26822 ExtrudeGeometry.WorldUVGenerator = { 26823 26824 generateTopUV: function ( geometry, indexA, indexB, indexC ) { 26825 26826 var vertices = geometry.vertices; 26827 26828 var a = vertices[ indexA ]; 26829 var b = vertices[ indexB ]; 26830 var c = vertices[ indexC ]; 26831 26832 return [ 26833 new Vector2( a.x, a.y ), 26834 new Vector2( b.x, b.y ), 26835 new Vector2( c.x, c.y ) 26836 ]; 26837 26838 }, 26839 26840 generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { 26841 26842 var vertices = geometry.vertices; 26843 26844 var a = vertices[ indexA ]; 26845 var b = vertices[ indexB ]; 26846 var c = vertices[ indexC ]; 26847 var d = vertices[ indexD ]; 26848 26849 if ( Math.abs( a.y - b.y ) < 0.01 ) { 26850 26851 return [ 26852 new Vector2( a.x, 1 - a.z ), 26853 new Vector2( b.x, 1 - b.z ), 26854 new Vector2( c.x, 1 - c.z ), 26855 new Vector2( d.x, 1 - d.z ) 26856 ]; 26857 26858 } else { 26859 26860 return [ 26861 new Vector2( a.y, 1 - a.z ), 26862 new Vector2( b.y, 1 - b.z ), 26863 new Vector2( c.y, 1 - c.z ), 26864 new Vector2( d.y, 1 - d.z ) 26865 ]; 26866 26867 } 26868 26869 } 26870 }; 26871 26872 /** 26873 * @author zz85 / http://www.lab4games.net/zz85/blog 26874 * @author alteredq / http://alteredqualia.com/ 26875 * 26876 * Text = 3D Text 26877 * 26878 * parameters = { 26879 * font: <THREE.Font>, // font 26880 * 26881 * size: <float>, // size of the text 26882 * height: <float>, // thickness to extrude text 26883 * curveSegments: <int>, // number of points on the curves 26884 * 26885 * bevelEnabled: <bool>, // turn on bevel 26886 * bevelThickness: <float>, // how deep into text bevel goes 26887 * bevelSize: <float> // how far from text outline is bevel 26888 * } 26889 */ 26890 26891 function TextGeometry( text, parameters ) { 26892 26893 parameters = parameters || {}; 26894 26895 var font = parameters.font; 26896 26897 if ( ( font && font.isFont ) === false ) { 26898 26899 console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); 26900 return new Geometry(); 26901 26902 } 26903 26904 var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments ); 26905 26906 // translate parameters to ExtrudeGeometry API 26907 26908 parameters.amount = parameters.height !== undefined ? parameters.height : 50; 26909 26910 // defaults 26911 26912 if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; 26913 if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; 26914 if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; 26915 26916 ExtrudeGeometry.call( this, shapes, parameters ); 26917 26918 this.type = 'TextGeometry'; 26919 26920 } 26921 26922 TextGeometry.prototype = Object.create( ExtrudeGeometry.prototype ); 26923 TextGeometry.prototype.constructor = TextGeometry; 26924 26925 /** 26926 * @author mrdoob / http://mrdoob.com/ 26927 */ 26928 26929 function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { 26930 26931 Geometry.call( this ); 26932 26933 this.type = 'SphereGeometry'; 26934 26935 this.parameters = { 26936 radius: radius, 26937 widthSegments: widthSegments, 26938 heightSegments: heightSegments, 26939 phiStart: phiStart, 26940 phiLength: phiLength, 26941 thetaStart: thetaStart, 26942 thetaLength: thetaLength 26943 }; 26944 26945 this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); 26946 26947 } 26948 26949 SphereGeometry.prototype = Object.create( Geometry.prototype ); 26950 SphereGeometry.prototype.constructor = SphereGeometry; 26951 26952 /** 26953 * @author benaadams / https://twitter.com/ben_a_adams 26954 * @author Mugen87 / https://github.com/Mugen87 26955 */ 26956 26957 function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { 26958 26959 BufferGeometry.call( this ); 26960 26961 this.type = 'SphereBufferGeometry'; 26962 26963 this.parameters = { 26964 radius: radius, 26965 widthSegments: widthSegments, 26966 heightSegments: heightSegments, 26967 phiStart: phiStart, 26968 phiLength: phiLength, 26969 thetaStart: thetaStart, 26970 thetaLength: thetaLength 26971 }; 26972 26973 radius = radius || 50; 26974 26975 widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); 26976 heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); 26977 26978 phiStart = phiStart !== undefined ? phiStart : 0; 26979 phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; 26980 26981 thetaStart = thetaStart !== undefined ? thetaStart : 0; 26982 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; 26983 26984 var thetaEnd = thetaStart + thetaLength; 26985 26986 var ix, iy; 26987 26988 var index = 0; 26989 var grid = []; 26990 26991 var vertex = new Vector3(); 26992 var normal = new Vector3(); 26993 26994 // buffers 26995 26996 var indices = []; 26997 var vertices = []; 26998 var normals = []; 26999 var uvs = []; 27000 27001 // generate vertices, normals and uvs 27002 27003 for ( iy = 0; iy <= heightSegments; iy ++ ) { 27004 27005 var verticesRow = []; 27006 27007 var v = iy / heightSegments; 27008 27009 for ( ix = 0; ix <= widthSegments; ix ++ ) { 27010 27011 var u = ix / widthSegments; 27012 27013 // vertex 27014 27015 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 27016 vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); 27017 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 27018 27019 vertices.push( vertex.x, vertex.y, vertex.z ); 27020 27021 // normal 27022 27023 normal.set( vertex.x, vertex.y, vertex.z ).normalize(); 27024 normals.push( normal.x, normal.y, normal.z ); 27025 27026 // uv 27027 27028 uvs.push( u, 1 - v ); 27029 27030 verticesRow.push( index ++ ); 27031 27032 } 27033 27034 grid.push( verticesRow ); 27035 27036 } 27037 27038 // indices 27039 27040 for ( iy = 0; iy < heightSegments; iy ++ ) { 27041 27042 for ( ix = 0; ix < widthSegments; ix ++ ) { 27043 27044 var a = grid[ iy ][ ix + 1 ]; 27045 var b = grid[ iy ][ ix ]; 27046 var c = grid[ iy + 1 ][ ix ]; 27047 var d = grid[ iy + 1 ][ ix + 1 ]; 27048 27049 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); 27050 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); 27051 27052 } 27053 27054 } 27055 27056 // build geometry 27057 27058 this.setIndex( indices ); 27059 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27060 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 27061 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 27062 27063 } 27064 27065 SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 27066 SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; 27067 27068 /** 27069 * @author Kaleb Murphy 27070 */ 27071 27072 function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { 27073 27074 Geometry.call( this ); 27075 27076 this.type = 'RingGeometry'; 27077 27078 this.parameters = { 27079 innerRadius: innerRadius, 27080 outerRadius: outerRadius, 27081 thetaSegments: thetaSegments, 27082 phiSegments: phiSegments, 27083 thetaStart: thetaStart, 27084 thetaLength: thetaLength 27085 }; 27086 27087 this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); 27088 27089 } 27090 27091 RingGeometry.prototype = Object.create( Geometry.prototype ); 27092 RingGeometry.prototype.constructor = RingGeometry; 27093 27094 /** 27095 * @author Mugen87 / https://github.com/Mugen87 27096 */ 27097 27098 function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { 27099 27100 BufferGeometry.call( this ); 27101 27102 this.type = 'RingBufferGeometry'; 27103 27104 this.parameters = { 27105 innerRadius: innerRadius, 27106 outerRadius: outerRadius, 27107 thetaSegments: thetaSegments, 27108 phiSegments: phiSegments, 27109 thetaStart: thetaStart, 27110 thetaLength: thetaLength 27111 }; 27112 27113 innerRadius = innerRadius || 20; 27114 outerRadius = outerRadius || 50; 27115 27116 thetaStart = thetaStart !== undefined ? thetaStart : 0; 27117 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; 27118 27119 thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; 27120 phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; 27121 27122 // buffers 27123 27124 var indices = []; 27125 var vertices = []; 27126 var normals = []; 27127 var uvs = []; 27128 27129 // some helper variables 27130 27131 var segment; 27132 var radius = innerRadius; 27133 var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); 27134 var vertex = new Vector3(); 27135 var uv = new Vector2(); 27136 var j, i; 27137 27138 // generate vertices, normals and uvs 27139 27140 for ( j = 0; j <= phiSegments; j ++ ) { 27141 27142 for ( i = 0; i <= thetaSegments; i ++ ) { 27143 27144 // values are generate from the inside of the ring to the outside 27145 27146 segment = thetaStart + i / thetaSegments * thetaLength; 27147 27148 // vertex 27149 27150 vertex.x = radius * Math.cos( segment ); 27151 vertex.y = radius * Math.sin( segment ); 27152 27153 vertices.push( vertex.x, vertex.y, vertex.z ); 27154 27155 // normal 27156 27157 normals.push( 0, 0, 1 ); 27158 27159 // uv 27160 27161 uv.x = ( vertex.x / outerRadius + 1 ) / 2; 27162 uv.y = ( vertex.y / outerRadius + 1 ) / 2; 27163 27164 uvs.push( uv.x, uv.y ); 27165 27166 } 27167 27168 // increase the radius for next row of vertices 27169 27170 radius += radiusStep; 27171 27172 } 27173 27174 // indices 27175 27176 for ( j = 0; j < phiSegments; j ++ ) { 27177 27178 var thetaSegmentLevel = j * ( thetaSegments + 1 ); 27179 27180 for ( i = 0; i < thetaSegments; i ++ ) { 27181 27182 segment = i + thetaSegmentLevel; 27183 27184 var a = segment; 27185 var b = segment + thetaSegments + 1; 27186 var c = segment + thetaSegments + 2; 27187 var d = segment + 1; 27188 27189 // faces 27190 27191 indices.push( a, b, d ); 27192 indices.push( b, c, d ); 27193 27194 } 27195 27196 } 27197 27198 // build geometry 27199 27200 this.setIndex( indices ); 27201 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27202 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 27203 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 27204 27205 } 27206 27207 RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 27208 RingBufferGeometry.prototype.constructor = RingBufferGeometry; 27209 27210 /** 27211 * @author astrodud / http://astrodud.isgreat.org/ 27212 * @author zz85 / https://github.com/zz85 27213 * @author bhouston / http://clara.io 27214 */ 27215 27216 // points - to create a closed torus, one must use a set of points 27217 // like so: [ a, b, c, d, a ], see first is the same as last. 27218 // segments - the number of circumference segments to create 27219 // phiStart - the starting radian 27220 // phiLength - the radian (0 to 2PI) range of the lathed section 27221 // 2PI is a closed lathe, less than 2PI is a portion. 27222 27223 function LatheGeometry( points, segments, phiStart, phiLength ) { 27224 27225 Geometry.call( this ); 27226 27227 this.type = 'LatheGeometry'; 27228 27229 this.parameters = { 27230 points: points, 27231 segments: segments, 27232 phiStart: phiStart, 27233 phiLength: phiLength 27234 }; 27235 27236 this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); 27237 this.mergeVertices(); 27238 27239 } 27240 27241 LatheGeometry.prototype = Object.create( Geometry.prototype ); 27242 LatheGeometry.prototype.constructor = LatheGeometry; 27243 27244 /** 27245 * @author Mugen87 / https://github.com/Mugen87 27246 */ 27247 27248 function LatheBufferGeometry( points, segments, phiStart, phiLength ) { 27249 27250 BufferGeometry.call( this ); 27251 27252 this.type = 'LatheBufferGeometry'; 27253 27254 this.parameters = { 27255 points: points, 27256 segments: segments, 27257 phiStart: phiStart, 27258 phiLength: phiLength 27259 }; 27260 27261 segments = Math.floor( segments ) || 12; 27262 phiStart = phiStart || 0; 27263 phiLength = phiLength || Math.PI * 2; 27264 27265 // clamp phiLength so it's in range of [ 0, 2PI ] 27266 27267 phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); 27268 27269 27270 // buffers 27271 27272 var indices = []; 27273 var vertices = []; 27274 var uvs = []; 27275 27276 // helper variables 27277 27278 var base; 27279 var inverseSegments = 1.0 / segments; 27280 var vertex = new Vector3(); 27281 var uv = new Vector2(); 27282 var i, j; 27283 27284 // generate vertices and uvs 27285 27286 for ( i = 0; i <= segments; i ++ ) { 27287 27288 var phi = phiStart + i * inverseSegments * phiLength; 27289 27290 var sin = Math.sin( phi ); 27291 var cos = Math.cos( phi ); 27292 27293 for ( j = 0; j <= ( points.length - 1 ); j ++ ) { 27294 27295 // vertex 27296 27297 vertex.x = points[ j ].x * sin; 27298 vertex.y = points[ j ].y; 27299 vertex.z = points[ j ].x * cos; 27300 27301 vertices.push( vertex.x, vertex.y, vertex.z ); 27302 27303 // uv 27304 27305 uv.x = i / segments; 27306 uv.y = j / ( points.length - 1 ); 27307 27308 uvs.push( uv.x, uv.y ); 27309 27310 27311 } 27312 27313 } 27314 27315 // indices 27316 27317 for ( i = 0; i < segments; i ++ ) { 27318 27319 for ( j = 0; j < ( points.length - 1 ); j ++ ) { 27320 27321 base = j + i * points.length; 27322 27323 var a = base; 27324 var b = base + points.length; 27325 var c = base + points.length + 1; 27326 var d = base + 1; 27327 27328 // faces 27329 27330 indices.push( a, b, d ); 27331 indices.push( b, c, d ); 27332 27333 } 27334 27335 } 27336 27337 // build geometry 27338 27339 this.setIndex( indices ); 27340 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27341 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 27342 27343 // generate normals 27344 27345 this.computeVertexNormals(); 27346 27347 // if the geometry is closed, we need to average the normals along the seam. 27348 // because the corresponding vertices are identical (but still have different UVs). 27349 27350 if ( phiLength === Math.PI * 2 ) { 27351 27352 var normals = this.attributes.normal.array; 27353 var n1 = new Vector3(); 27354 var n2 = new Vector3(); 27355 var n = new Vector3(); 27356 27357 // this is the buffer offset for the last line of vertices 27358 27359 base = segments * points.length * 3; 27360 27361 for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { 27362 27363 // select the normal of the vertex in the first line 27364 27365 n1.x = normals[ j + 0 ]; 27366 n1.y = normals[ j + 1 ]; 27367 n1.z = normals[ j + 2 ]; 27368 27369 // select the normal of the vertex in the last line 27370 27371 n2.x = normals[ base + j + 0 ]; 27372 n2.y = normals[ base + j + 1 ]; 27373 n2.z = normals[ base + j + 2 ]; 27374 27375 // average normals 27376 27377 n.addVectors( n1, n2 ).normalize(); 27378 27379 // assign the new values to both normals 27380 27381 normals[ j + 0 ] = normals[ base + j + 0 ] = n.x; 27382 normals[ j + 1 ] = normals[ base + j + 1 ] = n.y; 27383 normals[ j + 2 ] = normals[ base + j + 2 ] = n.z; 27384 27385 } 27386 27387 } 27388 27389 } 27390 27391 LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 27392 LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; 27393 27394 /** 27395 * @author jonobr1 / http://jonobr1.com 27396 */ 27397 27398 function ShapeGeometry( shapes, curveSegments ) { 27399 27400 Geometry.call( this ); 27401 27402 this.type = 'ShapeGeometry'; 27403 27404 if ( typeof curveSegments === 'object' ) { 27405 27406 console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); 27407 27408 curveSegments = curveSegments.curveSegments; 27409 27410 } 27411 27412 this.parameters = { 27413 shapes: shapes, 27414 curveSegments: curveSegments 27415 }; 27416 27417 this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); 27418 this.mergeVertices(); 27419 27420 } 27421 27422 ShapeGeometry.prototype = Object.create( Geometry.prototype ); 27423 ShapeGeometry.prototype.constructor = ShapeGeometry; 27424 27425 /** 27426 * @author Mugen87 / https://github.com/Mugen87 27427 */ 27428 27429 function ShapeBufferGeometry( shapes, curveSegments ) { 27430 27431 BufferGeometry.call( this ); 27432 27433 this.type = 'ShapeBufferGeometry'; 27434 27435 this.parameters = { 27436 shapes: shapes, 27437 curveSegments: curveSegments 27438 }; 27439 27440 curveSegments = curveSegments || 12; 27441 27442 // buffers 27443 27444 var indices = []; 27445 var vertices = []; 27446 var normals = []; 27447 var uvs = []; 27448 27449 // helper variables 27450 27451 var groupStart = 0; 27452 var groupCount = 0; 27453 27454 // allow single and array values for "shapes" parameter 27455 27456 if ( Array.isArray( shapes ) === false ) { 27457 27458 addShape( shapes ); 27459 27460 } else { 27461 27462 for ( var i = 0; i < shapes.length; i ++ ) { 27463 27464 addShape( shapes[ i ] ); 27465 27466 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support 27467 27468 groupStart += groupCount; 27469 groupCount = 0; 27470 27471 } 27472 27473 } 27474 27475 // build geometry 27476 27477 this.setIndex( indices ); 27478 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27479 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 27480 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 27481 27482 27483 // helper functions 27484 27485 function addShape( shape ) { 27486 27487 var i, l, shapeHole; 27488 27489 var indexOffset = vertices.length / 3; 27490 var points = shape.extractPoints( curveSegments ); 27491 27492 var shapeVertices = points.shape; 27493 var shapeHoles = points.holes; 27494 27495 // check direction of vertices 27496 27497 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { 27498 27499 shapeVertices = shapeVertices.reverse(); 27500 27501 // also check if holes are in the opposite direction 27502 27503 for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { 27504 27505 shapeHole = shapeHoles[ i ]; 27506 27507 if ( ShapeUtils.isClockWise( shapeHole ) === true ) { 27508 27509 shapeHoles[ i ] = shapeHole.reverse(); 27510 27511 } 27512 27513 } 27514 27515 } 27516 27517 var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); 27518 27519 // join vertices of inner and outer paths to a single array 27520 27521 for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { 27522 27523 shapeHole = shapeHoles[ i ]; 27524 shapeVertices = shapeVertices.concat( shapeHole ); 27525 27526 } 27527 27528 // vertices, normals, uvs 27529 27530 for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { 27531 27532 var vertex = shapeVertices[ i ]; 27533 27534 vertices.push( vertex.x, vertex.y, 0 ); 27535 normals.push( 0, 0, 1 ); 27536 uvs.push( vertex.x, vertex.y ); // world uvs 27537 27538 } 27539 27540 // incides 27541 27542 for ( i = 0, l = faces.length; i < l; i ++ ) { 27543 27544 var face = faces[ i ]; 27545 27546 var a = face[ 0 ] + indexOffset; 27547 var b = face[ 1 ] + indexOffset; 27548 var c = face[ 2 ] + indexOffset; 27549 27550 indices.push( a, b, c ); 27551 groupCount += 3; 27552 27553 } 27554 27555 } 27556 27557 } 27558 27559 ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 27560 ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; 27561 27562 /** 27563 * @author WestLangley / http://github.com/WestLangley 27564 * @author Mugen87 / https://github.com/Mugen87 27565 */ 27566 27567 function EdgesGeometry( geometry, thresholdAngle ) { 27568 27569 BufferGeometry.call( this ); 27570 27571 this.type = 'EdgesGeometry'; 27572 27573 this.parameters = { 27574 thresholdAngle: thresholdAngle 27575 }; 27576 27577 thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; 27578 27579 // buffer 27580 27581 var vertices = []; 27582 27583 // helper variables 27584 27585 var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); 27586 var edge = [ 0, 0 ], edges = {}; 27587 var key, keys = [ 'a', 'b', 'c' ]; 27588 27589 // prepare source geometry 27590 27591 var geometry2; 27592 27593 if ( geometry.isBufferGeometry ) { 27594 27595 geometry2 = new Geometry(); 27596 geometry2.fromBufferGeometry( geometry ); 27597 27598 } else { 27599 27600 geometry2 = geometry.clone(); 27601 27602 } 27603 27604 geometry2.mergeVertices(); 27605 geometry2.computeFaceNormals(); 27606 27607 var sourceVertices = geometry2.vertices; 27608 var faces = geometry2.faces; 27609 27610 // now create a data structure where each entry represents an edge with its adjoining faces 27611 27612 for ( var i = 0, l = faces.length; i < l; i ++ ) { 27613 27614 var face = faces[ i ]; 27615 27616 for ( var j = 0; j < 3; j ++ ) { 27617 27618 edge[ 0 ] = face[ keys[ j ] ]; 27619 edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; 27620 edge.sort( sortFunction ); 27621 27622 key = edge.toString(); 27623 27624 if ( edges[ key ] === undefined ) { 27625 27626 edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; 27627 27628 } else { 27629 27630 edges[ key ].face2 = i; 27631 27632 } 27633 27634 } 27635 27636 } 27637 27638 // generate vertices 27639 27640 for ( key in edges ) { 27641 27642 var e = edges[ key ]; 27643 27644 // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree. 27645 27646 if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { 27647 27648 var vertex = sourceVertices[ e.index1 ]; 27649 vertices.push( vertex.x, vertex.y, vertex.z ); 27650 27651 vertex = sourceVertices[ e.index2 ]; 27652 vertices.push( vertex.x, vertex.y, vertex.z ); 27653 27654 } 27655 27656 } 27657 27658 // build geometry 27659 27660 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27661 27662 // custom array sort function 27663 27664 function sortFunction( a, b ) { 27665 27666 return a - b; 27667 27668 } 27669 27670 } 27671 27672 EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); 27673 EdgesGeometry.prototype.constructor = EdgesGeometry; 27674 27675 /** 27676 * @author mrdoob / http://mrdoob.com/ 27677 */ 27678 27679 function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { 27680 27681 Geometry.call( this ); 27682 27683 this.type = 'CylinderGeometry'; 27684 27685 this.parameters = { 27686 radiusTop: radiusTop, 27687 radiusBottom: radiusBottom, 27688 height: height, 27689 radialSegments: radialSegments, 27690 heightSegments: heightSegments, 27691 openEnded: openEnded, 27692 thetaStart: thetaStart, 27693 thetaLength: thetaLength 27694 }; 27695 27696 this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); 27697 this.mergeVertices(); 27698 27699 } 27700 27701 CylinderGeometry.prototype = Object.create( Geometry.prototype ); 27702 CylinderGeometry.prototype.constructor = CylinderGeometry; 27703 27704 /** 27705 * @author Mugen87 / https://github.com/Mugen87 27706 */ 27707 27708 function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { 27709 27710 BufferGeometry.call( this ); 27711 27712 this.type = 'CylinderBufferGeometry'; 27713 27714 this.parameters = { 27715 radiusTop: radiusTop, 27716 radiusBottom: radiusBottom, 27717 height: height, 27718 radialSegments: radialSegments, 27719 heightSegments: heightSegments, 27720 openEnded: openEnded, 27721 thetaStart: thetaStart, 27722 thetaLength: thetaLength 27723 }; 27724 27725 var scope = this; 27726 27727 radiusTop = radiusTop !== undefined ? radiusTop : 20; 27728 radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; 27729 height = height !== undefined ? height : 100; 27730 27731 radialSegments = Math.floor( radialSegments ) || 8; 27732 heightSegments = Math.floor( heightSegments ) || 1; 27733 27734 openEnded = openEnded !== undefined ? openEnded : false; 27735 thetaStart = thetaStart !== undefined ? thetaStart : 0.0; 27736 thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI; 27737 27738 // buffers 27739 27740 var indices = []; 27741 var vertices = []; 27742 var normals = []; 27743 var uvs = []; 27744 27745 // helper variables 27746 27747 var index = 0; 27748 var indexOffset = 0; 27749 var indexArray = []; 27750 var halfHeight = height / 2; 27751 var groupStart = 0; 27752 27753 // generate geometry 27754 27755 generateTorso(); 27756 27757 if ( openEnded === false ) { 27758 27759 if ( radiusTop > 0 ) generateCap( true ); 27760 if ( radiusBottom > 0 ) generateCap( false ); 27761 27762 } 27763 27764 // build geometry 27765 27766 this.setIndex( indices ); 27767 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 27768 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 27769 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 27770 27771 function generateTorso() { 27772 27773 var x, y; 27774 var normal = new Vector3(); 27775 var vertex = new Vector3(); 27776 27777 var groupCount = 0; 27778 27779 // this will be used to calculate the normal 27780 var slope = ( radiusBottom - radiusTop ) / height; 27781 27782 // generate vertices, normals and uvs 27783 27784 for ( y = 0; y <= heightSegments; y ++ ) { 27785 27786 var indexRow = []; 27787 27788 var v = y / heightSegments; 27789 27790 // calculate the radius of the current row 27791 27792 var radius = v * ( radiusBottom - radiusTop ) + radiusTop; 27793 27794 for ( x = 0; x <= radialSegments; x ++ ) { 27795 27796 var u = x / radialSegments; 27797 27798 var theta = u * thetaLength + thetaStart; 27799 27800 var sinTheta = Math.sin( theta ); 27801 var cosTheta = Math.cos( theta ); 27802 27803 // vertex 27804 27805 vertex.x = radius * sinTheta; 27806 vertex.y = - v * height + halfHeight; 27807 vertex.z = radius * cosTheta; 27808 vertices.push( vertex.x, vertex.y, vertex.z ); 27809 27810 // normal 27811 27812 normal.set( sinTheta, slope, cosTheta ).normalize(); 27813 normals.push( normal.x, normal.y, normal.z ); 27814 27815 // uv 27816 27817 uvs.push( u, 1 - v ); 27818 27819 // save index of vertex in respective row 27820 27821 indexRow.push( index ++ ); 27822 27823 } 27824 27825 // now save vertices of the row in our index array 27826 27827 indexArray.push( indexRow ); 27828 27829 } 27830 27831 // generate indices 27832 27833 for ( x = 0; x < radialSegments; x ++ ) { 27834 27835 for ( y = 0; y < heightSegments; y ++ ) { 27836 27837 // we use the index array to access the correct indices 27838 27839 var a = indexArray[ y ][ x ]; 27840 var b = indexArray[ y + 1 ][ x ]; 27841 var c = indexArray[ y + 1 ][ x + 1 ]; 27842 var d = indexArray[ y ][ x + 1 ]; 27843 27844 // faces 27845 27846 indices.push( a, b, d ); 27847 indices.push( b, c, d ); 27848 27849 // update group counter 27850 27851 groupCount += 6; 27852 27853 } 27854 27855 } 27856 27857 // add a group to the geometry. this will ensure multi material support 27858 27859 scope.addGroup( groupStart, groupCount, 0 ); 27860 27861 // calculate new start value for groups 27862 27863 groupStart += groupCount; 27864 27865 } 27866 27867 function generateCap( top ) { 27868 27869 var x, centerIndexStart, centerIndexEnd; 27870 27871 var uv = new Vector2(); 27872 var vertex = new Vector3(); 27873 27874 var groupCount = 0; 27875 27876 var radius = ( top === true ) ? radiusTop : radiusBottom; 27877 var sign = ( top === true ) ? 1 : - 1; 27878 27879 // save the index of the first center vertex 27880 centerIndexStart = index; 27881 27882 // first we generate the center vertex data of the cap. 27883 // because the geometry needs one set of uvs per face, 27884 // we must generate a center vertex per face/segment 27885 27886 for ( x = 1; x <= radialSegments; x ++ ) { 27887 27888 // vertex 27889 27890 vertices.push( 0, halfHeight * sign, 0 ); 27891 27892 // normal 27893 27894 normals.push( 0, sign, 0 ); 27895 27896 // uv 27897 27898 uvs.push( 0.5, 0.5 ); 27899 27900 // increase index 27901 27902 index ++; 27903 27904 } 27905 27906 // save the index of the last center vertex 27907 27908 centerIndexEnd = index; 27909 27910 // now we generate the surrounding vertices, normals and uvs 27911 27912 for ( x = 0; x <= radialSegments; x ++ ) { 27913 27914 var u = x / radialSegments; 27915 var theta = u * thetaLength + thetaStart; 27916 27917 var cosTheta = Math.cos( theta ); 27918 var sinTheta = Math.sin( theta ); 27919 27920 // vertex 27921 27922 vertex.x = radius * sinTheta; 27923 vertex.y = halfHeight * sign; 27924 vertex.z = radius * cosTheta; 27925 vertices.push( vertex.x, vertex.y, vertex.z ); 27926 27927 // normal 27928 27929 normals.push( 0, sign, 0 ); 27930 27931 // uv 27932 27933 uv.x = ( cosTheta * 0.5 ) + 0.5; 27934 uv.y = ( sinTheta * 0.5 * sign ) + 0.5; 27935 uvs.push( uv.x, uv.y ); 27936 27937 // increase index 27938 27939 index ++; 27940 27941 } 27942 27943 // generate indices 27944 27945 for ( x = 0; x < radialSegments; x ++ ) { 27946 27947 var c = centerIndexStart + x; 27948 var i = centerIndexEnd + x; 27949 27950 if ( top === true ) { 27951 27952 // face top 27953 27954 indices.push( i, i + 1, c ); 27955 27956 } else { 27957 27958 // face bottom 27959 27960 indices.push( i + 1, i, c ); 27961 27962 } 27963 27964 groupCount += 3; 27965 27966 } 27967 27968 // add a group to the geometry. this will ensure multi material support 27969 27970 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); 27971 27972 // calculate new start value for groups 27973 27974 groupStart += groupCount; 27975 27976 } 27977 27978 } 27979 27980 CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 27981 CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; 27982 27983 /** 27984 * @author abelnation / http://github.com/abelnation 27985 */ 27986 27987 function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { 27988 27989 CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); 27990 27991 this.type = 'ConeGeometry'; 27992 27993 this.parameters = { 27994 radius: radius, 27995 height: height, 27996 radialSegments: radialSegments, 27997 heightSegments: heightSegments, 27998 openEnded: openEnded, 27999 thetaStart: thetaStart, 28000 thetaLength: thetaLength 28001 }; 28002 28003 } 28004 28005 ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); 28006 ConeGeometry.prototype.constructor = ConeGeometry; 28007 28008 /** 28009 * @author: abelnation / http://github.com/abelnation 28010 */ 28011 28012 function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { 28013 28014 CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); 28015 28016 this.type = 'ConeBufferGeometry'; 28017 28018 this.parameters = { 28019 radius: radius, 28020 height: height, 28021 radialSegments: radialSegments, 28022 heightSegments: heightSegments, 28023 openEnded: openEnded, 28024 thetaStart: thetaStart, 28025 thetaLength: thetaLength 28026 }; 28027 28028 } 28029 28030 ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); 28031 ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; 28032 28033 /** 28034 * @author hughes 28035 */ 28036 28037 function CircleGeometry( radius, segments, thetaStart, thetaLength ) { 28038 28039 Geometry.call( this ); 28040 28041 this.type = 'CircleGeometry'; 28042 28043 this.parameters = { 28044 radius: radius, 28045 segments: segments, 28046 thetaStart: thetaStart, 28047 thetaLength: thetaLength 28048 }; 28049 28050 this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); 28051 28052 } 28053 28054 CircleGeometry.prototype = Object.create( Geometry.prototype ); 28055 CircleGeometry.prototype.constructor = CircleGeometry; 28056 28057 /** 28058 * @author benaadams / https://twitter.com/ben_a_adams 28059 * @author Mugen87 / https://github.com/Mugen87 28060 */ 28061 28062 function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { 28063 28064 BufferGeometry.call( this ); 28065 28066 this.type = 'CircleBufferGeometry'; 28067 28068 this.parameters = { 28069 radius: radius, 28070 segments: segments, 28071 thetaStart: thetaStart, 28072 thetaLength: thetaLength 28073 }; 28074 28075 radius = radius || 50; 28076 segments = segments !== undefined ? Math.max( 3, segments ) : 8; 28077 28078 thetaStart = thetaStart !== undefined ? thetaStart : 0; 28079 thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; 28080 28081 // buffers 28082 28083 var indices = []; 28084 var vertices = []; 28085 var normals = []; 28086 var uvs = []; 28087 28088 // helper variables 28089 28090 var i, s; 28091 var vertex = new Vector3(); 28092 var uv = new Vector2(); 28093 28094 // center point 28095 28096 vertices.push( 0, 0, 0 ); 28097 normals.push( 0, 0, 1 ); 28098 uvs.push( 0.5, 0.5 ); 28099 28100 for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { 28101 28102 var segment = thetaStart + s / segments * thetaLength; 28103 28104 // vertex 28105 28106 vertex.x = radius * Math.cos( segment ); 28107 vertex.y = radius * Math.sin( segment ); 28108 28109 vertices.push( vertex.x, vertex.y, vertex.z ); 28110 28111 // normal 28112 28113 normals.push( 0, 0, 1 ); 28114 28115 // uvs 28116 28117 uv.x = ( vertices[ i ] / radius + 1 ) / 2; 28118 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; 28119 28120 uvs.push( uv.x, uv.y ); 28121 28122 } 28123 28124 // indices 28125 28126 for ( i = 1; i <= segments; i ++ ) { 28127 28128 indices.push( i, i + 1, 0 ); 28129 28130 } 28131 28132 // build geometry 28133 28134 this.setIndex( indices ); 28135 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 28136 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 28137 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 28138 28139 } 28140 28141 CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 28142 CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; 28143 28144 28145 28146 var Geometries = Object.freeze({ 28147 WireframeGeometry: WireframeGeometry, 28148 ParametricGeometry: ParametricGeometry, 28149 ParametricBufferGeometry: ParametricBufferGeometry, 28150 TetrahedronGeometry: TetrahedronGeometry, 28151 TetrahedronBufferGeometry: TetrahedronBufferGeometry, 28152 OctahedronGeometry: OctahedronGeometry, 28153 OctahedronBufferGeometry: OctahedronBufferGeometry, 28154 IcosahedronGeometry: IcosahedronGeometry, 28155 IcosahedronBufferGeometry: IcosahedronBufferGeometry, 28156 DodecahedronGeometry: DodecahedronGeometry, 28157 DodecahedronBufferGeometry: DodecahedronBufferGeometry, 28158 PolyhedronGeometry: PolyhedronGeometry, 28159 PolyhedronBufferGeometry: PolyhedronBufferGeometry, 28160 TubeGeometry: TubeGeometry, 28161 TubeBufferGeometry: TubeBufferGeometry, 28162 TorusKnotGeometry: TorusKnotGeometry, 28163 TorusKnotBufferGeometry: TorusKnotBufferGeometry, 28164 TorusGeometry: TorusGeometry, 28165 TorusBufferGeometry: TorusBufferGeometry, 28166 TextGeometry: TextGeometry, 28167 SphereGeometry: SphereGeometry, 28168 SphereBufferGeometry: SphereBufferGeometry, 28169 RingGeometry: RingGeometry, 28170 RingBufferGeometry: RingBufferGeometry, 28171 PlaneGeometry: PlaneGeometry, 28172 PlaneBufferGeometry: PlaneBufferGeometry, 28173 LatheGeometry: LatheGeometry, 28174 LatheBufferGeometry: LatheBufferGeometry, 28175 ShapeGeometry: ShapeGeometry, 28176 ShapeBufferGeometry: ShapeBufferGeometry, 28177 ExtrudeGeometry: ExtrudeGeometry, 28178 EdgesGeometry: EdgesGeometry, 28179 ConeGeometry: ConeGeometry, 28180 ConeBufferGeometry: ConeBufferGeometry, 28181 CylinderGeometry: CylinderGeometry, 28182 CylinderBufferGeometry: CylinderBufferGeometry, 28183 CircleGeometry: CircleGeometry, 28184 CircleBufferGeometry: CircleBufferGeometry, 28185 BoxGeometry: BoxGeometry, 28186 BoxBufferGeometry: BoxBufferGeometry 28187 }); 28188 28189 /** 28190 * @author mrdoob / http://mrdoob.com/ 28191 */ 28192 28193 function ShadowMaterial() { 28194 28195 ShaderMaterial.call( this, { 28196 uniforms: UniformsUtils.merge( [ 28197 UniformsLib.lights, 28198 { 28199 opacity: { value: 1.0 } 28200 } 28201 ] ), 28202 vertexShader: ShaderChunk[ 'shadow_vert' ], 28203 fragmentShader: ShaderChunk[ 'shadow_frag' ] 28204 } ); 28205 28206 this.lights = true; 28207 this.transparent = true; 28208 28209 Object.defineProperties( this, { 28210 opacity: { 28211 enumerable: true, 28212 get: function () { 28213 return this.uniforms.opacity.value; 28214 }, 28215 set: function ( value ) { 28216 this.uniforms.opacity.value = value; 28217 } 28218 } 28219 } ); 28220 28221 } 28222 28223 ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype ); 28224 ShadowMaterial.prototype.constructor = ShadowMaterial; 28225 28226 ShadowMaterial.prototype.isShadowMaterial = true; 28227 28228 /** 28229 * @author mrdoob / http://mrdoob.com/ 28230 */ 28231 28232 function RawShaderMaterial( parameters ) { 28233 28234 ShaderMaterial.call( this, parameters ); 28235 28236 this.type = 'RawShaderMaterial'; 28237 28238 } 28239 28240 RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); 28241 RawShaderMaterial.prototype.constructor = RawShaderMaterial; 28242 28243 RawShaderMaterial.prototype.isRawShaderMaterial = true; 28244 28245 /** 28246 * @author mrdoob / http://mrdoob.com/ 28247 */ 28248 28249 function MultiMaterial( materials ) { 28250 28251 this.uuid = _Math.generateUUID(); 28252 28253 this.type = 'MultiMaterial'; 28254 28255 this.materials = Array.isArray( materials ) ? materials : []; 28256 28257 this.visible = true; 28258 28259 } 28260 28261 MultiMaterial.prototype = { 28262 28263 constructor: MultiMaterial, 28264 28265 isMultiMaterial: true, 28266 28267 toJSON: function ( meta ) { 28268 28269 var output = { 28270 metadata: { 28271 version: 4.2, 28272 type: 'material', 28273 generator: 'MaterialExporter' 28274 }, 28275 uuid: this.uuid, 28276 type: this.type, 28277 materials: [] 28278 }; 28279 28280 var materials = this.materials; 28281 28282 for ( var i = 0, l = materials.length; i < l; i ++ ) { 28283 28284 var material = materials[ i ].toJSON( meta ); 28285 delete material.metadata; 28286 28287 output.materials.push( material ); 28288 28289 } 28290 28291 output.visible = this.visible; 28292 28293 return output; 28294 28295 }, 28296 28297 clone: function () { 28298 28299 var material = new this.constructor(); 28300 28301 for ( var i = 0; i < this.materials.length; i ++ ) { 28302 28303 material.materials.push( this.materials[ i ].clone() ); 28304 28305 } 28306 28307 material.visible = this.visible; 28308 28309 return material; 28310 28311 } 28312 28313 }; 28314 28315 /** 28316 * @author WestLangley / http://github.com/WestLangley 28317 * 28318 * parameters = { 28319 * color: <hex>, 28320 * roughness: <float>, 28321 * metalness: <float>, 28322 * opacity: <float>, 28323 * 28324 * map: new THREE.Texture( <Image> ), 28325 * 28326 * lightMap: new THREE.Texture( <Image> ), 28327 * lightMapIntensity: <float> 28328 * 28329 * aoMap: new THREE.Texture( <Image> ), 28330 * aoMapIntensity: <float> 28331 * 28332 * emissive: <hex>, 28333 * emissiveIntensity: <float> 28334 * emissiveMap: new THREE.Texture( <Image> ), 28335 * 28336 * bumpMap: new THREE.Texture( <Image> ), 28337 * bumpScale: <float>, 28338 * 28339 * normalMap: new THREE.Texture( <Image> ), 28340 * normalScale: <Vector2>, 28341 * 28342 * displacementMap: new THREE.Texture( <Image> ), 28343 * displacementScale: <float>, 28344 * displacementBias: <float>, 28345 * 28346 * roughnessMap: new THREE.Texture( <Image> ), 28347 * 28348 * metalnessMap: new THREE.Texture( <Image> ), 28349 * 28350 * alphaMap: new THREE.Texture( <Image> ), 28351 * 28352 * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), 28353 * envMapIntensity: <float> 28354 * 28355 * refractionRatio: <float>, 28356 * 28357 * wireframe: <boolean>, 28358 * wireframeLinewidth: <float>, 28359 * 28360 * skinning: <bool>, 28361 * morphTargets: <bool>, 28362 * morphNormals: <bool> 28363 * } 28364 */ 28365 28366 function MeshStandardMaterial( parameters ) { 28367 28368 Material.call( this ); 28369 28370 this.defines = { 'STANDARD': '' }; 28371 28372 this.type = 'MeshStandardMaterial'; 28373 28374 this.color = new Color( 0xffffff ); // diffuse 28375 this.roughness = 0.5; 28376 this.metalness = 0.5; 28377 28378 this.map = null; 28379 28380 this.lightMap = null; 28381 this.lightMapIntensity = 1.0; 28382 28383 this.aoMap = null; 28384 this.aoMapIntensity = 1.0; 28385 28386 this.emissive = new Color( 0x000000 ); 28387 this.emissiveIntensity = 1.0; 28388 this.emissiveMap = null; 28389 28390 this.bumpMap = null; 28391 this.bumpScale = 1; 28392 28393 this.normalMap = null; 28394 this.normalScale = new Vector2( 1, 1 ); 28395 28396 this.displacementMap = null; 28397 this.displacementScale = 1; 28398 this.displacementBias = 0; 28399 28400 this.roughnessMap = null; 28401 28402 this.metalnessMap = null; 28403 28404 this.alphaMap = null; 28405 28406 this.envMap = null; 28407 this.envMapIntensity = 1.0; 28408 28409 this.refractionRatio = 0.98; 28410 28411 this.wireframe = false; 28412 this.wireframeLinewidth = 1; 28413 this.wireframeLinecap = 'round'; 28414 this.wireframeLinejoin = 'round'; 28415 28416 this.skinning = false; 28417 this.morphTargets = false; 28418 this.morphNormals = false; 28419 28420 this.setValues( parameters ); 28421 28422 } 28423 28424 MeshStandardMaterial.prototype = Object.create( Material.prototype ); 28425 MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; 28426 28427 MeshStandardMaterial.prototype.isMeshStandardMaterial = true; 28428 28429 MeshStandardMaterial.prototype.copy = function ( source ) { 28430 28431 Material.prototype.copy.call( this, source ); 28432 28433 this.defines = { 'STANDARD': '' }; 28434 28435 this.color.copy( source.color ); 28436 this.roughness = source.roughness; 28437 this.metalness = source.metalness; 28438 28439 this.map = source.map; 28440 28441 this.lightMap = source.lightMap; 28442 this.lightMapIntensity = source.lightMapIntensity; 28443 28444 this.aoMap = source.aoMap; 28445 this.aoMapIntensity = source.aoMapIntensity; 28446 28447 this.emissive.copy( source.emissive ); 28448 this.emissiveMap = source.emissiveMap; 28449 this.emissiveIntensity = source.emissiveIntensity; 28450 28451 this.bumpMap = source.bumpMap; 28452 this.bumpScale = source.bumpScale; 28453 28454 this.normalMap = source.normalMap; 28455 this.normalScale.copy( source.normalScale ); 28456 28457 this.displacementMap = source.displacementMap; 28458 this.displacementScale = source.displacementScale; 28459 this.displacementBias = source.displacementBias; 28460 28461 this.roughnessMap = source.roughnessMap; 28462 28463 this.metalnessMap = source.metalnessMap; 28464 28465 this.alphaMap = source.alphaMap; 28466 28467 this.envMap = source.envMap; 28468 this.envMapIntensity = source.envMapIntensity; 28469 28470 this.refractionRatio = source.refractionRatio; 28471 28472 this.wireframe = source.wireframe; 28473 this.wireframeLinewidth = source.wireframeLinewidth; 28474 this.wireframeLinecap = source.wireframeLinecap; 28475 this.wireframeLinejoin = source.wireframeLinejoin; 28476 28477 this.skinning = source.skinning; 28478 this.morphTargets = source.morphTargets; 28479 this.morphNormals = source.morphNormals; 28480 28481 return this; 28482 28483 }; 28484 28485 /** 28486 * @author WestLangley / http://github.com/WestLangley 28487 * 28488 * parameters = { 28489 * reflectivity: <float> 28490 * } 28491 */ 28492 28493 function MeshPhysicalMaterial( parameters ) { 28494 28495 MeshStandardMaterial.call( this ); 28496 28497 this.defines = { 'PHYSICAL': '' }; 28498 28499 this.type = 'MeshPhysicalMaterial'; 28500 28501 this.reflectivity = 0.5; // maps to F0 = 0.04 28502 28503 this.clearCoat = 0.0; 28504 this.clearCoatRoughness = 0.0; 28505 28506 this.setValues( parameters ); 28507 28508 } 28509 28510 MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); 28511 MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; 28512 28513 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; 28514 28515 MeshPhysicalMaterial.prototype.copy = function ( source ) { 28516 28517 MeshStandardMaterial.prototype.copy.call( this, source ); 28518 28519 this.defines = { 'PHYSICAL': '' }; 28520 28521 this.reflectivity = source.reflectivity; 28522 28523 this.clearCoat = source.clearCoat; 28524 this.clearCoatRoughness = source.clearCoatRoughness; 28525 28526 return this; 28527 28528 }; 28529 28530 /** 28531 * @author mrdoob / http://mrdoob.com/ 28532 * @author alteredq / http://alteredqualia.com/ 28533 * 28534 * parameters = { 28535 * color: <hex>, 28536 * specular: <hex>, 28537 * shininess: <float>, 28538 * opacity: <float>, 28539 * 28540 * map: new THREE.Texture( <Image> ), 28541 * 28542 * lightMap: new THREE.Texture( <Image> ), 28543 * lightMapIntensity: <float> 28544 * 28545 * aoMap: new THREE.Texture( <Image> ), 28546 * aoMapIntensity: <float> 28547 * 28548 * emissive: <hex>, 28549 * emissiveIntensity: <float> 28550 * emissiveMap: new THREE.Texture( <Image> ), 28551 * 28552 * bumpMap: new THREE.Texture( <Image> ), 28553 * bumpScale: <float>, 28554 * 28555 * normalMap: new THREE.Texture( <Image> ), 28556 * normalScale: <Vector2>, 28557 * 28558 * displacementMap: new THREE.Texture( <Image> ), 28559 * displacementScale: <float>, 28560 * displacementBias: <float>, 28561 * 28562 * specularMap: new THREE.Texture( <Image> ), 28563 * 28564 * alphaMap: new THREE.Texture( <Image> ), 28565 * 28566 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), 28567 * combine: THREE.Multiply, 28568 * reflectivity: <float>, 28569 * refractionRatio: <float>, 28570 * 28571 * wireframe: <boolean>, 28572 * wireframeLinewidth: <float>, 28573 * 28574 * skinning: <bool>, 28575 * morphTargets: <bool>, 28576 * morphNormals: <bool> 28577 * } 28578 */ 28579 28580 function MeshPhongMaterial( parameters ) { 28581 28582 Material.call( this ); 28583 28584 this.type = 'MeshPhongMaterial'; 28585 28586 this.color = new Color( 0xffffff ); // diffuse 28587 this.specular = new Color( 0x111111 ); 28588 this.shininess = 30; 28589 28590 this.map = null; 28591 28592 this.lightMap = null; 28593 this.lightMapIntensity = 1.0; 28594 28595 this.aoMap = null; 28596 this.aoMapIntensity = 1.0; 28597 28598 this.emissive = new Color( 0x000000 ); 28599 this.emissiveIntensity = 1.0; 28600 this.emissiveMap = null; 28601 28602 this.bumpMap = null; 28603 this.bumpScale = 1; 28604 28605 this.normalMap = null; 28606 this.normalScale = new Vector2( 1, 1 ); 28607 28608 this.displacementMap = null; 28609 this.displacementScale = 1; 28610 this.displacementBias = 0; 28611 28612 this.specularMap = null; 28613 28614 this.alphaMap = null; 28615 28616 this.envMap = null; 28617 this.combine = MultiplyOperation; 28618 this.reflectivity = 1; 28619 this.refractionRatio = 0.98; 28620 28621 this.wireframe = false; 28622 this.wireframeLinewidth = 1; 28623 this.wireframeLinecap = 'round'; 28624 this.wireframeLinejoin = 'round'; 28625 28626 this.skinning = false; 28627 this.morphTargets = false; 28628 this.morphNormals = false; 28629 28630 this.setValues( parameters ); 28631 28632 } 28633 28634 MeshPhongMaterial.prototype = Object.create( Material.prototype ); 28635 MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; 28636 28637 MeshPhongMaterial.prototype.isMeshPhongMaterial = true; 28638 28639 MeshPhongMaterial.prototype.copy = function ( source ) { 28640 28641 Material.prototype.copy.call( this, source ); 28642 28643 this.color.copy( source.color ); 28644 this.specular.copy( source.specular ); 28645 this.shininess = source.shininess; 28646 28647 this.map = source.map; 28648 28649 this.lightMap = source.lightMap; 28650 this.lightMapIntensity = source.lightMapIntensity; 28651 28652 this.aoMap = source.aoMap; 28653 this.aoMapIntensity = source.aoMapIntensity; 28654 28655 this.emissive.copy( source.emissive ); 28656 this.emissiveMap = source.emissiveMap; 28657 this.emissiveIntensity = source.emissiveIntensity; 28658 28659 this.bumpMap = source.bumpMap; 28660 this.bumpScale = source.bumpScale; 28661 28662 this.normalMap = source.normalMap; 28663 this.normalScale.copy( source.normalScale ); 28664 28665 this.displacementMap = source.displacementMap; 28666 this.displacementScale = source.displacementScale; 28667 this.displacementBias = source.displacementBias; 28668 28669 this.specularMap = source.specularMap; 28670 28671 this.alphaMap = source.alphaMap; 28672 28673 this.envMap = source.envMap; 28674 this.combine = source.combine; 28675 this.reflectivity = source.reflectivity; 28676 this.refractionRatio = source.refractionRatio; 28677 28678 this.wireframe = source.wireframe; 28679 this.wireframeLinewidth = source.wireframeLinewidth; 28680 this.wireframeLinecap = source.wireframeLinecap; 28681 this.wireframeLinejoin = source.wireframeLinejoin; 28682 28683 this.skinning = source.skinning; 28684 this.morphTargets = source.morphTargets; 28685 this.morphNormals = source.morphNormals; 28686 28687 return this; 28688 28689 }; 28690 28691 /** 28692 * @author takahirox / http://github.com/takahirox 28693 * 28694 * parameters = { 28695 * gradientMap: new THREE.Texture( <Image> ) 28696 * } 28697 */ 28698 28699 function MeshToonMaterial( parameters ) { 28700 28701 MeshPhongMaterial.call( this ); 28702 28703 this.defines = { 'TOON': '' }; 28704 28705 this.type = 'MeshToonMaterial'; 28706 28707 this.gradientMap = null; 28708 28709 this.setValues( parameters ); 28710 28711 } 28712 28713 MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); 28714 MeshToonMaterial.prototype.constructor = MeshToonMaterial; 28715 28716 MeshToonMaterial.prototype.isMeshToonMaterial = true; 28717 28718 MeshToonMaterial.prototype.copy = function ( source ) { 28719 28720 MeshPhongMaterial.prototype.copy.call( this, source ); 28721 28722 this.gradientMap = source.gradientMap; 28723 28724 return this; 28725 28726 }; 28727 28728 /** 28729 * @author mrdoob / http://mrdoob.com/ 28730 * @author WestLangley / http://github.com/WestLangley 28731 * 28732 * parameters = { 28733 * opacity: <float>, 28734 * 28735 * bumpMap: new THREE.Texture( <Image> ), 28736 * bumpScale: <float>, 28737 * 28738 * normalMap: new THREE.Texture( <Image> ), 28739 * normalScale: <Vector2>, 28740 * 28741 * displacementMap: new THREE.Texture( <Image> ), 28742 * displacementScale: <float>, 28743 * displacementBias: <float>, 28744 * 28745 * wireframe: <boolean>, 28746 * wireframeLinewidth: <float> 28747 * 28748 * skinning: <bool>, 28749 * morphTargets: <bool>, 28750 * morphNormals: <bool> 28751 * } 28752 */ 28753 28754 function MeshNormalMaterial( parameters ) { 28755 28756 Material.call( this, parameters ); 28757 28758 this.type = 'MeshNormalMaterial'; 28759 28760 this.bumpMap = null; 28761 this.bumpScale = 1; 28762 28763 this.normalMap = null; 28764 this.normalScale = new Vector2( 1, 1 ); 28765 28766 this.displacementMap = null; 28767 this.displacementScale = 1; 28768 this.displacementBias = 0; 28769 28770 this.wireframe = false; 28771 this.wireframeLinewidth = 1; 28772 28773 this.fog = false; 28774 this.lights = false; 28775 28776 this.skinning = false; 28777 this.morphTargets = false; 28778 this.morphNormals = false; 28779 28780 this.setValues( parameters ); 28781 28782 } 28783 28784 MeshNormalMaterial.prototype = Object.create( Material.prototype ); 28785 MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; 28786 28787 MeshNormalMaterial.prototype.isMeshNormalMaterial = true; 28788 28789 MeshNormalMaterial.prototype.copy = function ( source ) { 28790 28791 Material.prototype.copy.call( this, source ); 28792 28793 this.bumpMap = source.bumpMap; 28794 this.bumpScale = source.bumpScale; 28795 28796 this.normalMap = source.normalMap; 28797 this.normalScale.copy( source.normalScale ); 28798 28799 this.displacementMap = source.displacementMap; 28800 this.displacementScale = source.displacementScale; 28801 this.displacementBias = source.displacementBias; 28802 28803 this.wireframe = source.wireframe; 28804 this.wireframeLinewidth = source.wireframeLinewidth; 28805 28806 this.skinning = source.skinning; 28807 this.morphTargets = source.morphTargets; 28808 this.morphNormals = source.morphNormals; 28809 28810 return this; 28811 28812 }; 28813 28814 /** 28815 * @author mrdoob / http://mrdoob.com/ 28816 * @author alteredq / http://alteredqualia.com/ 28817 * 28818 * parameters = { 28819 * color: <hex>, 28820 * opacity: <float>, 28821 * 28822 * map: new THREE.Texture( <Image> ), 28823 * 28824 * lightMap: new THREE.Texture( <Image> ), 28825 * lightMapIntensity: <float> 28826 * 28827 * aoMap: new THREE.Texture( <Image> ), 28828 * aoMapIntensity: <float> 28829 * 28830 * emissive: <hex>, 28831 * emissiveIntensity: <float> 28832 * emissiveMap: new THREE.Texture( <Image> ), 28833 * 28834 * specularMap: new THREE.Texture( <Image> ), 28835 * 28836 * alphaMap: new THREE.Texture( <Image> ), 28837 * 28838 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), 28839 * combine: THREE.Multiply, 28840 * reflectivity: <float>, 28841 * refractionRatio: <float>, 28842 * 28843 * wireframe: <boolean>, 28844 * wireframeLinewidth: <float>, 28845 * 28846 * skinning: <bool>, 28847 * morphTargets: <bool>, 28848 * morphNormals: <bool> 28849 * } 28850 */ 28851 28852 function MeshLambertMaterial( parameters ) { 28853 28854 Material.call( this ); 28855 28856 this.type = 'MeshLambertMaterial'; 28857 28858 this.color = new Color( 0xffffff ); // diffuse 28859 28860 this.map = null; 28861 28862 this.lightMap = null; 28863 this.lightMapIntensity = 1.0; 28864 28865 this.aoMap = null; 28866 this.aoMapIntensity = 1.0; 28867 28868 this.emissive = new Color( 0x000000 ); 28869 this.emissiveIntensity = 1.0; 28870 this.emissiveMap = null; 28871 28872 this.specularMap = null; 28873 28874 this.alphaMap = null; 28875 28876 this.envMap = null; 28877 this.combine = MultiplyOperation; 28878 this.reflectivity = 1; 28879 this.refractionRatio = 0.98; 28880 28881 this.wireframe = false; 28882 this.wireframeLinewidth = 1; 28883 this.wireframeLinecap = 'round'; 28884 this.wireframeLinejoin = 'round'; 28885 28886 this.skinning = false; 28887 this.morphTargets = false; 28888 this.morphNormals = false; 28889 28890 this.setValues( parameters ); 28891 28892 } 28893 28894 MeshLambertMaterial.prototype = Object.create( Material.prototype ); 28895 MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; 28896 28897 MeshLambertMaterial.prototype.isMeshLambertMaterial = true; 28898 28899 MeshLambertMaterial.prototype.copy = function ( source ) { 28900 28901 Material.prototype.copy.call( this, source ); 28902 28903 this.color.copy( source.color ); 28904 28905 this.map = source.map; 28906 28907 this.lightMap = source.lightMap; 28908 this.lightMapIntensity = source.lightMapIntensity; 28909 28910 this.aoMap = source.aoMap; 28911 this.aoMapIntensity = source.aoMapIntensity; 28912 28913 this.emissive.copy( source.emissive ); 28914 this.emissiveMap = source.emissiveMap; 28915 this.emissiveIntensity = source.emissiveIntensity; 28916 28917 this.specularMap = source.specularMap; 28918 28919 this.alphaMap = source.alphaMap; 28920 28921 this.envMap = source.envMap; 28922 this.combine = source.combine; 28923 this.reflectivity = source.reflectivity; 28924 this.refractionRatio = source.refractionRatio; 28925 28926 this.wireframe = source.wireframe; 28927 this.wireframeLinewidth = source.wireframeLinewidth; 28928 this.wireframeLinecap = source.wireframeLinecap; 28929 this.wireframeLinejoin = source.wireframeLinejoin; 28930 28931 this.skinning = source.skinning; 28932 this.morphTargets = source.morphTargets; 28933 this.morphNormals = source.morphNormals; 28934 28935 return this; 28936 28937 }; 28938 28939 /** 28940 * @author alteredq / http://alteredqualia.com/ 28941 * 28942 * parameters = { 28943 * color: <hex>, 28944 * opacity: <float>, 28945 * 28946 * linewidth: <float>, 28947 * 28948 * scale: <float>, 28949 * dashSize: <float>, 28950 * gapSize: <float> 28951 * } 28952 */ 28953 28954 function LineDashedMaterial( parameters ) { 28955 28956 Material.call( this ); 28957 28958 this.type = 'LineDashedMaterial'; 28959 28960 this.color = new Color( 0xffffff ); 28961 28962 this.linewidth = 1; 28963 28964 this.scale = 1; 28965 this.dashSize = 3; 28966 this.gapSize = 1; 28967 28968 this.lights = false; 28969 28970 this.setValues( parameters ); 28971 28972 } 28973 28974 LineDashedMaterial.prototype = Object.create( Material.prototype ); 28975 LineDashedMaterial.prototype.constructor = LineDashedMaterial; 28976 28977 LineDashedMaterial.prototype.isLineDashedMaterial = true; 28978 28979 LineDashedMaterial.prototype.copy = function ( source ) { 28980 28981 Material.prototype.copy.call( this, source ); 28982 28983 this.color.copy( source.color ); 28984 28985 this.linewidth = source.linewidth; 28986 28987 this.scale = source.scale; 28988 this.dashSize = source.dashSize; 28989 this.gapSize = source.gapSize; 28990 28991 return this; 28992 28993 }; 28994 28995 28996 28997 var Materials = Object.freeze({ 28998 ShadowMaterial: ShadowMaterial, 28999 SpriteMaterial: SpriteMaterial, 29000 RawShaderMaterial: RawShaderMaterial, 29001 ShaderMaterial: ShaderMaterial, 29002 PointsMaterial: PointsMaterial, 29003 MultiMaterial: MultiMaterial, 29004 MeshPhysicalMaterial: MeshPhysicalMaterial, 29005 MeshStandardMaterial: MeshStandardMaterial, 29006 MeshPhongMaterial: MeshPhongMaterial, 29007 MeshToonMaterial: MeshToonMaterial, 29008 MeshNormalMaterial: MeshNormalMaterial, 29009 MeshLambertMaterial: MeshLambertMaterial, 29010 MeshDepthMaterial: MeshDepthMaterial, 29011 MeshBasicMaterial: MeshBasicMaterial, 29012 LineDashedMaterial: LineDashedMaterial, 29013 LineBasicMaterial: LineBasicMaterial, 29014 Material: Material 29015 }); 29016 29017 /** 29018 * @author mrdoob / http://mrdoob.com/ 29019 */ 29020 29021 var Cache = { 29022 29023 enabled: false, 29024 29025 files: {}, 29026 29027 add: function ( key, file ) { 29028 29029 if ( this.enabled === false ) return; 29030 29031 // console.log( 'THREE.Cache', 'Adding key:', key ); 29032 29033 this.files[ key ] = file; 29034 29035 }, 29036 29037 get: function ( key ) { 29038 29039 if ( this.enabled === false ) return; 29040 29041 // console.log( 'THREE.Cache', 'Checking key:', key ); 29042 29043 return this.files[ key ]; 29044 29045 }, 29046 29047 remove: function ( key ) { 29048 29049 delete this.files[ key ]; 29050 29051 }, 29052 29053 clear: function () { 29054 29055 this.files = {}; 29056 29057 } 29058 29059 }; 29060 29061 /** 29062 * @author mrdoob / http://mrdoob.com/ 29063 */ 29064 29065 function LoadingManager( onLoad, onProgress, onError ) { 29066 29067 var scope = this; 29068 29069 var isLoading = false, itemsLoaded = 0, itemsTotal = 0; 29070 29071 this.onStart = undefined; 29072 this.onLoad = onLoad; 29073 this.onProgress = onProgress; 29074 this.onError = onError; 29075 29076 this.itemStart = function ( url ) { 29077 29078 itemsTotal ++; 29079 29080 if ( isLoading === false ) { 29081 29082 if ( scope.onStart !== undefined ) { 29083 29084 scope.onStart( url, itemsLoaded, itemsTotal ); 29085 29086 } 29087 29088 } 29089 29090 isLoading = true; 29091 29092 }; 29093 29094 this.itemEnd = function ( url ) { 29095 29096 itemsLoaded ++; 29097 29098 if ( scope.onProgress !== undefined ) { 29099 29100 scope.onProgress( url, itemsLoaded, itemsTotal ); 29101 29102 } 29103 29104 if ( itemsLoaded === itemsTotal ) { 29105 29106 isLoading = false; 29107 29108 if ( scope.onLoad !== undefined ) { 29109 29110 scope.onLoad(); 29111 29112 } 29113 29114 } 29115 29116 }; 29117 29118 this.itemError = function ( url ) { 29119 29120 if ( scope.onError !== undefined ) { 29121 29122 scope.onError( url ); 29123 29124 } 29125 29126 }; 29127 29128 } 29129 29130 var DefaultLoadingManager = new LoadingManager(); 29131 29132 /** 29133 * @author mrdoob / http://mrdoob.com/ 29134 */ 29135 29136 function FileLoader( manager ) { 29137 29138 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29139 29140 } 29141 29142 Object.assign( FileLoader.prototype, { 29143 29144 load: function ( url, onLoad, onProgress, onError ) { 29145 29146 if ( url === undefined ) url = ''; 29147 29148 if ( this.path !== undefined ) url = this.path + url; 29149 29150 var scope = this; 29151 29152 var cached = Cache.get( url ); 29153 29154 if ( cached !== undefined ) { 29155 29156 scope.manager.itemStart( url ); 29157 29158 setTimeout( function () { 29159 29160 if ( onLoad ) onLoad( cached ); 29161 29162 scope.manager.itemEnd( url ); 29163 29164 }, 0 ); 29165 29166 return cached; 29167 29168 } 29169 29170 // Check for data: URI 29171 var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; 29172 var dataUriRegexResult = url.match( dataUriRegex ); 29173 29174 // Safari can not handle Data URIs through XMLHttpRequest so process manually 29175 if ( dataUriRegexResult ) { 29176 29177 var mimeType = dataUriRegexResult[ 1 ]; 29178 var isBase64 = !! dataUriRegexResult[ 2 ]; 29179 var data = dataUriRegexResult[ 3 ]; 29180 29181 data = window.decodeURIComponent( data ); 29182 29183 if ( isBase64 ) data = window.atob( data ); 29184 29185 try { 29186 29187 var response; 29188 var responseType = ( this.responseType || '' ).toLowerCase(); 29189 29190 switch ( responseType ) { 29191 29192 case 'arraybuffer': 29193 case 'blob': 29194 29195 response = new ArrayBuffer( data.length ); 29196 29197 var view = new Uint8Array( response ); 29198 29199 for ( var i = 0; i < data.length; i ++ ) { 29200 29201 view[ i ] = data.charCodeAt( i ); 29202 29203 } 29204 29205 if ( responseType === 'blob' ) { 29206 29207 response = new Blob( [ response ], { type: mimeType } ); 29208 29209 } 29210 29211 break; 29212 29213 case 'document': 29214 29215 var parser = new DOMParser(); 29216 response = parser.parseFromString( data, mimeType ); 29217 29218 break; 29219 29220 case 'json': 29221 29222 response = JSON.parse( data ); 29223 29224 break; 29225 29226 default: // 'text' or other 29227 29228 response = data; 29229 29230 break; 29231 29232 } 29233 29234 // Wait for next browser tick 29235 window.setTimeout( function () { 29236 29237 if ( onLoad ) onLoad( response ); 29238 29239 scope.manager.itemEnd( url ); 29240 29241 }, 0 ); 29242 29243 } catch ( error ) { 29244 29245 // Wait for next browser tick 29246 window.setTimeout( function () { 29247 29248 if ( onError ) onError( error ); 29249 29250 scope.manager.itemError( url ); 29251 29252 }, 0 ); 29253 29254 } 29255 29256 } else { 29257 29258 var request = new XMLHttpRequest(); 29259 request.open( 'GET', url, true ); 29260 29261 request.addEventListener( 'load', function ( event ) { 29262 29263 var response = event.target.response; 29264 29265 Cache.add( url, response ); 29266 29267 if ( this.status === 200 ) { 29268 29269 if ( onLoad ) onLoad( response ); 29270 29271 scope.manager.itemEnd( url ); 29272 29273 } else if ( this.status === 0 ) { 29274 29275 // Some browsers return HTTP Status 0 when using non-http protocol 29276 // e.g. 'file://' or 'data://'. Handle as success. 29277 29278 console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); 29279 29280 if ( onLoad ) onLoad( response ); 29281 29282 scope.manager.itemEnd( url ); 29283 29284 } else { 29285 29286 if ( onError ) onError( event ); 29287 29288 scope.manager.itemError( url ); 29289 29290 } 29291 29292 }, false ); 29293 29294 if ( onProgress !== undefined ) { 29295 29296 request.addEventListener( 'progress', function ( event ) { 29297 29298 onProgress( event ); 29299 29300 }, false ); 29301 29302 } 29303 29304 request.addEventListener( 'error', function ( event ) { 29305 29306 if ( onError ) onError( event ); 29307 29308 scope.manager.itemError( url ); 29309 29310 }, false ); 29311 29312 if ( this.responseType !== undefined ) request.responseType = this.responseType; 29313 if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; 29314 29315 if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); 29316 29317 request.send( null ); 29318 29319 } 29320 29321 scope.manager.itemStart( url ); 29322 29323 return request; 29324 29325 }, 29326 29327 setPath: function ( value ) { 29328 29329 this.path = value; 29330 return this; 29331 29332 }, 29333 29334 setResponseType: function ( value ) { 29335 29336 this.responseType = value; 29337 return this; 29338 29339 }, 29340 29341 setWithCredentials: function ( value ) { 29342 29343 this.withCredentials = value; 29344 return this; 29345 29346 }, 29347 29348 setMimeType: function ( value ) { 29349 29350 this.mimeType = value; 29351 return this; 29352 29353 } 29354 29355 } ); 29356 29357 /** 29358 * @author mrdoob / http://mrdoob.com/ 29359 * 29360 * Abstract Base class to block based textures loader (dds, pvr, ...) 29361 */ 29362 29363 function CompressedTextureLoader( manager ) { 29364 29365 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29366 29367 // override in sub classes 29368 this._parser = null; 29369 29370 } 29371 29372 Object.assign( CompressedTextureLoader.prototype, { 29373 29374 load: function ( url, onLoad, onProgress, onError ) { 29375 29376 var scope = this; 29377 29378 var images = []; 29379 29380 var texture = new CompressedTexture(); 29381 texture.image = images; 29382 29383 var loader = new FileLoader( this.manager ); 29384 loader.setPath( this.path ); 29385 loader.setResponseType( 'arraybuffer' ); 29386 29387 function loadTexture( i ) { 29388 29389 loader.load( url[ i ], function ( buffer ) { 29390 29391 var texDatas = scope._parser( buffer, true ); 29392 29393 images[ i ] = { 29394 width: texDatas.width, 29395 height: texDatas.height, 29396 format: texDatas.format, 29397 mipmaps: texDatas.mipmaps 29398 }; 29399 29400 loaded += 1; 29401 29402 if ( loaded === 6 ) { 29403 29404 if ( texDatas.mipmapCount === 1 ) 29405 texture.minFilter = LinearFilter; 29406 29407 texture.format = texDatas.format; 29408 texture.needsUpdate = true; 29409 29410 if ( onLoad ) onLoad( texture ); 29411 29412 } 29413 29414 }, onProgress, onError ); 29415 29416 } 29417 29418 if ( Array.isArray( url ) ) { 29419 29420 var loaded = 0; 29421 29422 for ( var i = 0, il = url.length; i < il; ++ i ) { 29423 29424 loadTexture( i ); 29425 29426 } 29427 29428 } else { 29429 29430 // compressed cubemap texture stored in a single DDS file 29431 29432 loader.load( url, function ( buffer ) { 29433 29434 var texDatas = scope._parser( buffer, true ); 29435 29436 if ( texDatas.isCubemap ) { 29437 29438 var faces = texDatas.mipmaps.length / texDatas.mipmapCount; 29439 29440 for ( var f = 0; f < faces; f ++ ) { 29441 29442 images[ f ] = { mipmaps : [] }; 29443 29444 for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { 29445 29446 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); 29447 images[ f ].format = texDatas.format; 29448 images[ f ].width = texDatas.width; 29449 images[ f ].height = texDatas.height; 29450 29451 } 29452 29453 } 29454 29455 } else { 29456 29457 texture.image.width = texDatas.width; 29458 texture.image.height = texDatas.height; 29459 texture.mipmaps = texDatas.mipmaps; 29460 29461 } 29462 29463 if ( texDatas.mipmapCount === 1 ) { 29464 29465 texture.minFilter = LinearFilter; 29466 29467 } 29468 29469 texture.format = texDatas.format; 29470 texture.needsUpdate = true; 29471 29472 if ( onLoad ) onLoad( texture ); 29473 29474 }, onProgress, onError ); 29475 29476 } 29477 29478 return texture; 29479 29480 }, 29481 29482 setPath: function ( value ) { 29483 29484 this.path = value; 29485 return this; 29486 29487 } 29488 29489 } ); 29490 29491 /** 29492 * @author Nikos M. / https://github.com/foo123/ 29493 * 29494 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) 29495 */ 29496 29497 function DataTextureLoader( manager ) { 29498 29499 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29500 29501 // override in sub classes 29502 this._parser = null; 29503 29504 } 29505 29506 Object.assign( DataTextureLoader.prototype, { 29507 29508 load: function ( url, onLoad, onProgress, onError ) { 29509 29510 var scope = this; 29511 29512 var texture = new DataTexture(); 29513 29514 var loader = new FileLoader( this.manager ); 29515 loader.setResponseType( 'arraybuffer' ); 29516 29517 loader.load( url, function ( buffer ) { 29518 29519 var texData = scope._parser( buffer ); 29520 29521 if ( ! texData ) return; 29522 29523 if ( undefined !== texData.image ) { 29524 29525 texture.image = texData.image; 29526 29527 } else if ( undefined !== texData.data ) { 29528 29529 texture.image.width = texData.width; 29530 texture.image.height = texData.height; 29531 texture.image.data = texData.data; 29532 29533 } 29534 29535 texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping; 29536 texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping; 29537 29538 texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter; 29539 texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter; 29540 29541 texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; 29542 29543 if ( undefined !== texData.format ) { 29544 29545 texture.format = texData.format; 29546 29547 } 29548 if ( undefined !== texData.type ) { 29549 29550 texture.type = texData.type; 29551 29552 } 29553 29554 if ( undefined !== texData.mipmaps ) { 29555 29556 texture.mipmaps = texData.mipmaps; 29557 29558 } 29559 29560 if ( 1 === texData.mipmapCount ) { 29561 29562 texture.minFilter = LinearFilter; 29563 29564 } 29565 29566 texture.needsUpdate = true; 29567 29568 if ( onLoad ) onLoad( texture, texData ); 29569 29570 }, onProgress, onError ); 29571 29572 29573 return texture; 29574 29575 } 29576 29577 } ); 29578 29579 /** 29580 * @author mrdoob / http://mrdoob.com/ 29581 */ 29582 29583 function ImageLoader( manager ) { 29584 29585 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29586 29587 } 29588 29589 Object.assign( ImageLoader.prototype, { 29590 29591 load: function ( url, onLoad, onProgress, onError ) { 29592 29593 if ( url === undefined ) url = ''; 29594 29595 if ( this.path !== undefined ) url = this.path + url; 29596 29597 var scope = this; 29598 29599 var cached = Cache.get( url ); 29600 29601 if ( cached !== undefined ) { 29602 29603 scope.manager.itemStart( url ); 29604 29605 setTimeout( function () { 29606 29607 if ( onLoad ) onLoad( cached ); 29608 29609 scope.manager.itemEnd( url ); 29610 29611 }, 0 ); 29612 29613 return cached; 29614 29615 } 29616 29617 var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); 29618 29619 image.addEventListener( 'load', function () { 29620 29621 Cache.add( url, this ); 29622 29623 if ( onLoad ) onLoad( this ); 29624 29625 scope.manager.itemEnd( url ); 29626 29627 }, false ); 29628 29629 /* 29630 image.addEventListener( 'progress', function ( event ) { 29631 29632 if ( onProgress ) onProgress( event ); 29633 29634 }, false ); 29635 */ 29636 29637 image.addEventListener( 'error', function ( event ) { 29638 29639 if ( onError ) onError( event ); 29640 29641 scope.manager.itemError( url ); 29642 29643 }, false ); 29644 29645 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; 29646 29647 scope.manager.itemStart( url ); 29648 29649 image.src = url; 29650 29651 return image; 29652 29653 }, 29654 29655 setCrossOrigin: function ( value ) { 29656 29657 this.crossOrigin = value; 29658 return this; 29659 29660 }, 29661 29662 setPath: function ( value ) { 29663 29664 this.path = value; 29665 return this; 29666 29667 } 29668 29669 } ); 29670 29671 /** 29672 * @author mrdoob / http://mrdoob.com/ 29673 */ 29674 29675 function CubeTextureLoader( manager ) { 29676 29677 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29678 29679 } 29680 29681 Object.assign( CubeTextureLoader.prototype, { 29682 29683 load: function ( urls, onLoad, onProgress, onError ) { 29684 29685 var texture = new CubeTexture(); 29686 29687 var loader = new ImageLoader( this.manager ); 29688 loader.setCrossOrigin( this.crossOrigin ); 29689 loader.setPath( this.path ); 29690 29691 var loaded = 0; 29692 29693 function loadTexture( i ) { 29694 29695 loader.load( urls[ i ], function ( image ) { 29696 29697 texture.images[ i ] = image; 29698 29699 loaded ++; 29700 29701 if ( loaded === 6 ) { 29702 29703 texture.needsUpdate = true; 29704 29705 if ( onLoad ) onLoad( texture ); 29706 29707 } 29708 29709 }, undefined, onError ); 29710 29711 } 29712 29713 for ( var i = 0; i < urls.length; ++ i ) { 29714 29715 loadTexture( i ); 29716 29717 } 29718 29719 return texture; 29720 29721 }, 29722 29723 setCrossOrigin: function ( value ) { 29724 29725 this.crossOrigin = value; 29726 return this; 29727 29728 }, 29729 29730 setPath: function ( value ) { 29731 29732 this.path = value; 29733 return this; 29734 29735 } 29736 29737 } ); 29738 29739 /** 29740 * @author mrdoob / http://mrdoob.com/ 29741 */ 29742 29743 function TextureLoader( manager ) { 29744 29745 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29746 29747 } 29748 29749 Object.assign( TextureLoader.prototype, { 29750 29751 load: function ( url, onLoad, onProgress, onError ) { 29752 29753 var texture = new Texture(); 29754 29755 var loader = new ImageLoader( this.manager ); 29756 loader.setCrossOrigin( this.crossOrigin ); 29757 loader.setPath( this.path ); 29758 loader.load( url, function ( image ) { 29759 29760 // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. 29761 var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; 29762 29763 texture.format = isJPEG ? RGBFormat : RGBAFormat; 29764 texture.image = image; 29765 texture.needsUpdate = true; 29766 29767 if ( onLoad !== undefined ) { 29768 29769 onLoad( texture ); 29770 29771 } 29772 29773 }, onProgress, onError ); 29774 29775 return texture; 29776 29777 }, 29778 29779 setCrossOrigin: function ( value ) { 29780 29781 this.crossOrigin = value; 29782 return this; 29783 29784 }, 29785 29786 setPath: function ( value ) { 29787 29788 this.path = value; 29789 return this; 29790 29791 } 29792 29793 } ); 29794 29795 /** 29796 * @author mrdoob / http://mrdoob.com/ 29797 * @author alteredq / http://alteredqualia.com/ 29798 */ 29799 29800 function Light( color, intensity ) { 29801 29802 Object3D.call( this ); 29803 29804 this.type = 'Light'; 29805 29806 this.color = new Color( color ); 29807 this.intensity = intensity !== undefined ? intensity : 1; 29808 29809 this.receiveShadow = undefined; 29810 29811 } 29812 29813 Light.prototype = Object.assign( Object.create( Object3D.prototype ), { 29814 29815 constructor: Light, 29816 29817 isLight: true, 29818 29819 copy: function ( source ) { 29820 29821 Object3D.prototype.copy.call( this, source ); 29822 29823 this.color.copy( source.color ); 29824 this.intensity = source.intensity; 29825 29826 return this; 29827 29828 }, 29829 29830 toJSON: function ( meta ) { 29831 29832 var data = Object3D.prototype.toJSON.call( this, meta ); 29833 29834 data.object.color = this.color.getHex(); 29835 data.object.intensity = this.intensity; 29836 29837 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); 29838 29839 if ( this.distance !== undefined ) data.object.distance = this.distance; 29840 if ( this.angle !== undefined ) data.object.angle = this.angle; 29841 if ( this.decay !== undefined ) data.object.decay = this.decay; 29842 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; 29843 29844 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); 29845 29846 return data; 29847 29848 } 29849 29850 } ); 29851 29852 /** 29853 * @author alteredq / http://alteredqualia.com/ 29854 */ 29855 29856 function HemisphereLight( skyColor, groundColor, intensity ) { 29857 29858 Light.call( this, skyColor, intensity ); 29859 29860 this.type = 'HemisphereLight'; 29861 29862 this.castShadow = undefined; 29863 29864 this.position.copy( Object3D.DefaultUp ); 29865 this.updateMatrix(); 29866 29867 this.groundColor = new Color( groundColor ); 29868 29869 } 29870 29871 HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { 29872 29873 constructor: HemisphereLight, 29874 29875 isHemisphereLight: true, 29876 29877 copy: function ( source ) { 29878 29879 Light.prototype.copy.call( this, source ); 29880 29881 this.groundColor.copy( source.groundColor ); 29882 29883 return this; 29884 29885 } 29886 29887 } ); 29888 29889 /** 29890 * @author mrdoob / http://mrdoob.com/ 29891 */ 29892 29893 function LightShadow( camera ) { 29894 29895 this.camera = camera; 29896 29897 this.bias = 0; 29898 this.radius = 1; 29899 29900 this.mapSize = new Vector2( 512, 512 ); 29901 29902 this.map = null; 29903 this.matrix = new Matrix4(); 29904 29905 } 29906 29907 Object.assign( LightShadow.prototype, { 29908 29909 copy: function ( source ) { 29910 29911 this.camera = source.camera.clone(); 29912 29913 this.bias = source.bias; 29914 this.radius = source.radius; 29915 29916 this.mapSize.copy( source.mapSize ); 29917 29918 return this; 29919 29920 }, 29921 29922 clone: function () { 29923 29924 return new this.constructor().copy( this ); 29925 29926 }, 29927 29928 toJSON: function () { 29929 29930 var object = {}; 29931 29932 if ( this.bias !== 0 ) object.bias = this.bias; 29933 if ( this.radius !== 1 ) object.radius = this.radius; 29934 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); 29935 29936 object.camera = this.camera.toJSON( false ).object; 29937 delete object.camera.matrix; 29938 29939 return object; 29940 29941 } 29942 29943 } ); 29944 29945 /** 29946 * @author mrdoob / http://mrdoob.com/ 29947 */ 29948 29949 function SpotLightShadow() { 29950 29951 LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); 29952 29953 } 29954 29955 SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { 29956 29957 constructor: SpotLightShadow, 29958 29959 isSpotLightShadow: true, 29960 29961 update: function ( light ) { 29962 29963 var fov = _Math.RAD2DEG * 2 * light.angle; 29964 var aspect = this.mapSize.width / this.mapSize.height; 29965 var far = light.distance || 500; 29966 29967 var camera = this.camera; 29968 29969 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { 29970 29971 camera.fov = fov; 29972 camera.aspect = aspect; 29973 camera.far = far; 29974 camera.updateProjectionMatrix(); 29975 29976 } 29977 29978 } 29979 29980 } ); 29981 29982 /** 29983 * @author alteredq / http://alteredqualia.com/ 29984 */ 29985 29986 function SpotLight( color, intensity, distance, angle, penumbra, decay ) { 29987 29988 Light.call( this, color, intensity ); 29989 29990 this.type = 'SpotLight'; 29991 29992 this.position.copy( Object3D.DefaultUp ); 29993 this.updateMatrix(); 29994 29995 this.target = new Object3D(); 29996 29997 Object.defineProperty( this, 'power', { 29998 get: function () { 29999 // intensity = power per solid angle. 30000 // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf 30001 return this.intensity * Math.PI; 30002 }, 30003 set: function ( power ) { 30004 // intensity = power per solid angle. 30005 // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf 30006 this.intensity = power / Math.PI; 30007 } 30008 } ); 30009 30010 this.distance = ( distance !== undefined ) ? distance : 0; 30011 this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; 30012 this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; 30013 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. 30014 30015 this.shadow = new SpotLightShadow(); 30016 30017 } 30018 30019 SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { 30020 30021 constructor: SpotLight, 30022 30023 isSpotLight: true, 30024 30025 copy: function ( source ) { 30026 30027 Light.prototype.copy.call( this, source ); 30028 30029 this.distance = source.distance; 30030 this.angle = source.angle; 30031 this.penumbra = source.penumbra; 30032 this.decay = source.decay; 30033 30034 this.target = source.target.clone(); 30035 30036 this.shadow = source.shadow.clone(); 30037 30038 return this; 30039 30040 } 30041 30042 } ); 30043 30044 /** 30045 * @author mrdoob / http://mrdoob.com/ 30046 */ 30047 30048 30049 function PointLight( color, intensity, distance, decay ) { 30050 30051 Light.call( this, color, intensity ); 30052 30053 this.type = 'PointLight'; 30054 30055 Object.defineProperty( this, 'power', { 30056 get: function () { 30057 // intensity = power per solid angle. 30058 // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf 30059 return this.intensity * 4 * Math.PI; 30060 30061 }, 30062 set: function ( power ) { 30063 // intensity = power per solid angle. 30064 // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf 30065 this.intensity = power / ( 4 * Math.PI ); 30066 } 30067 } ); 30068 30069 this.distance = ( distance !== undefined ) ? distance : 0; 30070 this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. 30071 30072 this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); 30073 30074 } 30075 30076 PointLight.prototype = Object.assign( Object.create( Light.prototype ), { 30077 30078 constructor: PointLight, 30079 30080 isPointLight: true, 30081 30082 copy: function ( source ) { 30083 30084 Light.prototype.copy.call( this, source ); 30085 30086 this.distance = source.distance; 30087 this.decay = source.decay; 30088 30089 this.shadow = source.shadow.clone(); 30090 30091 return this; 30092 30093 } 30094 30095 } ); 30096 30097 /** 30098 * @author mrdoob / http://mrdoob.com/ 30099 */ 30100 30101 function DirectionalLightShadow( ) { 30102 30103 LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); 30104 30105 } 30106 30107 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { 30108 30109 constructor: DirectionalLightShadow 30110 30111 } ); 30112 30113 /** 30114 * @author mrdoob / http://mrdoob.com/ 30115 * @author alteredq / http://alteredqualia.com/ 30116 */ 30117 30118 function DirectionalLight( color, intensity ) { 30119 30120 Light.call( this, color, intensity ); 30121 30122 this.type = 'DirectionalLight'; 30123 30124 this.position.copy( Object3D.DefaultUp ); 30125 this.updateMatrix(); 30126 30127 this.target = new Object3D(); 30128 30129 this.shadow = new DirectionalLightShadow(); 30130 30131 } 30132 30133 DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { 30134 30135 constructor: DirectionalLight, 30136 30137 isDirectionalLight: true, 30138 30139 copy: function ( source ) { 30140 30141 Light.prototype.copy.call( this, source ); 30142 30143 this.target = source.target.clone(); 30144 30145 this.shadow = source.shadow.clone(); 30146 30147 return this; 30148 30149 } 30150 30151 } ); 30152 30153 /** 30154 * @author mrdoob / http://mrdoob.com/ 30155 */ 30156 30157 function AmbientLight( color, intensity ) { 30158 30159 Light.call( this, color, intensity ); 30160 30161 this.type = 'AmbientLight'; 30162 30163 this.castShadow = undefined; 30164 30165 } 30166 30167 AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { 30168 30169 constructor: AmbientLight, 30170 30171 isAmbientLight: true 30172 30173 } ); 30174 30175 /** 30176 * @author tschw 30177 * @author Ben Houston / http://clara.io/ 30178 * @author David Sarno / http://lighthaus.us/ 30179 */ 30180 30181 var AnimationUtils = { 30182 30183 // same as Array.prototype.slice, but also works on typed arrays 30184 arraySlice: function( array, from, to ) { 30185 30186 if ( AnimationUtils.isTypedArray( array ) ) { 30187 30188 return new array.constructor( array.subarray( from, to ) ); 30189 30190 } 30191 30192 return array.slice( from, to ); 30193 30194 }, 30195 30196 // converts an array to a specific type 30197 convertArray: function( array, type, forceClone ) { 30198 30199 if ( ! array || // let 'undefined' and 'null' pass 30200 ! forceClone && array.constructor === type ) return array; 30201 30202 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { 30203 30204 return new type( array ); // create typed array 30205 30206 } 30207 30208 return Array.prototype.slice.call( array ); // create Array 30209 30210 }, 30211 30212 isTypedArray: function( object ) { 30213 30214 return ArrayBuffer.isView( object ) && 30215 ! ( object instanceof DataView ); 30216 30217 }, 30218 30219 // returns an array by which times and values can be sorted 30220 getKeyframeOrder: function( times ) { 30221 30222 function compareTime( i, j ) { 30223 30224 return times[ i ] - times[ j ]; 30225 30226 } 30227 30228 var n = times.length; 30229 var result = new Array( n ); 30230 for ( var i = 0; i !== n; ++ i ) result[ i ] = i; 30231 30232 result.sort( compareTime ); 30233 30234 return result; 30235 30236 }, 30237 30238 // uses the array previously returned by 'getKeyframeOrder' to sort data 30239 sortedArray: function( values, stride, order ) { 30240 30241 var nValues = values.length; 30242 var result = new values.constructor( nValues ); 30243 30244 for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { 30245 30246 var srcOffset = order[ i ] * stride; 30247 30248 for ( var j = 0; j !== stride; ++ j ) { 30249 30250 result[ dstOffset ++ ] = values[ srcOffset + j ]; 30251 30252 } 30253 30254 } 30255 30256 return result; 30257 30258 }, 30259 30260 // function for parsing AOS keyframe formats 30261 flattenJSON: function( jsonKeys, times, values, valuePropertyName ) { 30262 30263 var i = 1, key = jsonKeys[ 0 ]; 30264 30265 while ( key !== undefined && key[ valuePropertyName ] === undefined ) { 30266 30267 key = jsonKeys[ i ++ ]; 30268 30269 } 30270 30271 if ( key === undefined ) return; // no data 30272 30273 var value = key[ valuePropertyName ]; 30274 if ( value === undefined ) return; // no data 30275 30276 if ( Array.isArray( value ) ) { 30277 30278 do { 30279 30280 value = key[ valuePropertyName ]; 30281 30282 if ( value !== undefined ) { 30283 30284 times.push( key.time ); 30285 values.push.apply( values, value ); // push all elements 30286 30287 } 30288 30289 key = jsonKeys[ i ++ ]; 30290 30291 } while ( key !== undefined ); 30292 30293 } else if ( value.toArray !== undefined ) { 30294 // ...assume THREE.Math-ish 30295 30296 do { 30297 30298 value = key[ valuePropertyName ]; 30299 30300 if ( value !== undefined ) { 30301 30302 times.push( key.time ); 30303 value.toArray( values, values.length ); 30304 30305 } 30306 30307 key = jsonKeys[ i ++ ]; 30308 30309 } while ( key !== undefined ); 30310 30311 } else { 30312 // otherwise push as-is 30313 30314 do { 30315 30316 value = key[ valuePropertyName ]; 30317 30318 if ( value !== undefined ) { 30319 30320 times.push( key.time ); 30321 values.push( value ); 30322 30323 } 30324 30325 key = jsonKeys[ i ++ ]; 30326 30327 } while ( key !== undefined ); 30328 30329 } 30330 30331 } 30332 30333 }; 30334 30335 /** 30336 * Abstract base class of interpolants over parametric samples. 30337 * 30338 * The parameter domain is one dimensional, typically the time or a path 30339 * along a curve defined by the data. 30340 * 30341 * The sample values can have any dimensionality and derived classes may 30342 * apply special interpretations to the data. 30343 * 30344 * This class provides the interval seek in a Template Method, deferring 30345 * the actual interpolation to derived classes. 30346 * 30347 * Time complexity is O(1) for linear access crossing at most two points 30348 * and O(log N) for random access, where N is the number of positions. 30349 * 30350 * References: 30351 * 30352 * http://www.oodesign.com/template-method-pattern.html 30353 * 30354 * @author tschw 30355 */ 30356 30357 function Interpolant( 30358 parameterPositions, sampleValues, sampleSize, resultBuffer ) { 30359 30360 this.parameterPositions = parameterPositions; 30361 this._cachedIndex = 0; 30362 30363 this.resultBuffer = resultBuffer !== undefined ? 30364 resultBuffer : new sampleValues.constructor( sampleSize ); 30365 this.sampleValues = sampleValues; 30366 this.valueSize = sampleSize; 30367 30368 } 30369 30370 Interpolant.prototype = { 30371 30372 constructor: Interpolant, 30373 30374 evaluate: function( t ) { 30375 30376 var pp = this.parameterPositions, 30377 i1 = this._cachedIndex, 30378 30379 t1 = pp[ i1 ], 30380 t0 = pp[ i1 - 1 ]; 30381 30382 validate_interval: { 30383 30384 seek: { 30385 30386 var right; 30387 30388 linear_scan: { 30389 //- See http://jsperf.com/comparison-to-undefined/3 30390 //- slower code: 30391 //- 30392 //- if ( t >= t1 || t1 === undefined ) { 30393 forward_scan: if ( ! ( t < t1 ) ) { 30394 30395 for ( var giveUpAt = i1 + 2; ;) { 30396 30397 if ( t1 === undefined ) { 30398 30399 if ( t < t0 ) break forward_scan; 30400 30401 // after end 30402 30403 i1 = pp.length; 30404 this._cachedIndex = i1; 30405 return this.afterEnd_( i1 - 1, t, t0 ); 30406 30407 } 30408 30409 if ( i1 === giveUpAt ) break; // this loop 30410 30411 t0 = t1; 30412 t1 = pp[ ++ i1 ]; 30413 30414 if ( t < t1 ) { 30415 30416 // we have arrived at the sought interval 30417 break seek; 30418 30419 } 30420 30421 } 30422 30423 // prepare binary search on the right side of the index 30424 right = pp.length; 30425 break linear_scan; 30426 30427 } 30428 30429 //- slower code: 30430 //- if ( t < t0 || t0 === undefined ) { 30431 if ( ! ( t >= t0 ) ) { 30432 30433 // looping? 30434 30435 var t1global = pp[ 1 ]; 30436 30437 if ( t < t1global ) { 30438 30439 i1 = 2; // + 1, using the scan for the details 30440 t0 = t1global; 30441 30442 } 30443 30444 // linear reverse scan 30445 30446 for ( var giveUpAt = i1 - 2; ;) { 30447 30448 if ( t0 === undefined ) { 30449 30450 // before start 30451 30452 this._cachedIndex = 0; 30453 return this.beforeStart_( 0, t, t1 ); 30454 30455 } 30456 30457 if ( i1 === giveUpAt ) break; // this loop 30458 30459 t1 = t0; 30460 t0 = pp[ -- i1 - 1 ]; 30461 30462 if ( t >= t0 ) { 30463 30464 // we have arrived at the sought interval 30465 break seek; 30466 30467 } 30468 30469 } 30470 30471 // prepare binary search on the left side of the index 30472 right = i1; 30473 i1 = 0; 30474 break linear_scan; 30475 30476 } 30477 30478 // the interval is valid 30479 30480 break validate_interval; 30481 30482 } // linear scan 30483 30484 // binary search 30485 30486 while ( i1 < right ) { 30487 30488 var mid = ( i1 + right ) >>> 1; 30489 30490 if ( t < pp[ mid ] ) { 30491 30492 right = mid; 30493 30494 } else { 30495 30496 i1 = mid + 1; 30497 30498 } 30499 30500 } 30501 30502 t1 = pp[ i1 ]; 30503 t0 = pp[ i1 - 1 ]; 30504 30505 // check boundary cases, again 30506 30507 if ( t0 === undefined ) { 30508 30509 this._cachedIndex = 0; 30510 return this.beforeStart_( 0, t, t1 ); 30511 30512 } 30513 30514 if ( t1 === undefined ) { 30515 30516 i1 = pp.length; 30517 this._cachedIndex = i1; 30518 return this.afterEnd_( i1 - 1, t0, t ); 30519 30520 } 30521 30522 } // seek 30523 30524 this._cachedIndex = i1; 30525 30526 this.intervalChanged_( i1, t0, t1 ); 30527 30528 } // validate_interval 30529 30530 return this.interpolate_( i1, t0, t, t1 ); 30531 30532 }, 30533 30534 settings: null, // optional, subclass-specific settings structure 30535 // Note: The indirection allows central control of many interpolants. 30536 30537 // --- Protected interface 30538 30539 DefaultSettings_: {}, 30540 30541 getSettings_: function() { 30542 30543 return this.settings || this.DefaultSettings_; 30544 30545 }, 30546 30547 copySampleValue_: function( index ) { 30548 30549 // copies a sample value to the result buffer 30550 30551 var result = this.resultBuffer, 30552 values = this.sampleValues, 30553 stride = this.valueSize, 30554 offset = index * stride; 30555 30556 for ( var i = 0; i !== stride; ++ i ) { 30557 30558 result[ i ] = values[ offset + i ]; 30559 30560 } 30561 30562 return result; 30563 30564 }, 30565 30566 // Template methods for derived classes: 30567 30568 interpolate_: function( i1, t0, t, t1 ) { 30569 30570 throw new Error( "call to abstract method" ); 30571 // implementations shall return this.resultBuffer 30572 30573 }, 30574 30575 intervalChanged_: function( i1, t0, t1 ) { 30576 30577 // empty 30578 30579 } 30580 30581 }; 30582 30583 Object.assign( Interpolant.prototype, { 30584 30585 beforeStart_: //( 0, t, t0 ), returns this.resultBuffer 30586 Interpolant.prototype.copySampleValue_, 30587 30588 afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer 30589 Interpolant.prototype.copySampleValue_ 30590 30591 } ); 30592 30593 /** 30594 * Fast and simple cubic spline interpolant. 30595 * 30596 * It was derived from a Hermitian construction setting the first derivative 30597 * at each sample position to the linear slope between neighboring positions 30598 * over their parameter interval. 30599 * 30600 * @author tschw 30601 */ 30602 30603 function CubicInterpolant( 30604 parameterPositions, sampleValues, sampleSize, resultBuffer ) { 30605 30606 Interpolant.call( 30607 this, parameterPositions, sampleValues, sampleSize, resultBuffer ); 30608 30609 this._weightPrev = -0; 30610 this._offsetPrev = -0; 30611 this._weightNext = -0; 30612 this._offsetNext = -0; 30613 30614 } 30615 30616 CubicInterpolant.prototype = 30617 Object.assign( Object.create( Interpolant.prototype ), { 30618 30619 constructor: CubicInterpolant, 30620 30621 DefaultSettings_: { 30622 30623 endingStart: ZeroCurvatureEnding, 30624 endingEnd: ZeroCurvatureEnding 30625 30626 }, 30627 30628 intervalChanged_: function( i1, t0, t1 ) { 30629 30630 var pp = this.parameterPositions, 30631 iPrev = i1 - 2, 30632 iNext = i1 + 1, 30633 30634 tPrev = pp[ iPrev ], 30635 tNext = pp[ iNext ]; 30636 30637 if ( tPrev === undefined ) { 30638 30639 switch ( this.getSettings_().endingStart ) { 30640 30641 case ZeroSlopeEnding: 30642 30643 // f'(t0) = 0 30644 iPrev = i1; 30645 tPrev = 2 * t0 - t1; 30646 30647 break; 30648 30649 case WrapAroundEnding: 30650 30651 // use the other end of the curve 30652 iPrev = pp.length - 2; 30653 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; 30654 30655 break; 30656 30657 default: // ZeroCurvatureEnding 30658 30659 // f''(t0) = 0 a.k.a. Natural Spline 30660 iPrev = i1; 30661 tPrev = t1; 30662 30663 } 30664 30665 } 30666 30667 if ( tNext === undefined ) { 30668 30669 switch ( this.getSettings_().endingEnd ) { 30670 30671 case ZeroSlopeEnding: 30672 30673 // f'(tN) = 0 30674 iNext = i1; 30675 tNext = 2 * t1 - t0; 30676 30677 break; 30678 30679 case WrapAroundEnding: 30680 30681 // use the other end of the curve 30682 iNext = 1; 30683 tNext = t1 + pp[ 1 ] - pp[ 0 ]; 30684 30685 break; 30686 30687 default: // ZeroCurvatureEnding 30688 30689 // f''(tN) = 0, a.k.a. Natural Spline 30690 iNext = i1 - 1; 30691 tNext = t0; 30692 30693 } 30694 30695 } 30696 30697 var halfDt = ( t1 - t0 ) * 0.5, 30698 stride = this.valueSize; 30699 30700 this._weightPrev = halfDt / ( t0 - tPrev ); 30701 this._weightNext = halfDt / ( tNext - t1 ); 30702 this._offsetPrev = iPrev * stride; 30703 this._offsetNext = iNext * stride; 30704 30705 }, 30706 30707 interpolate_: function( i1, t0, t, t1 ) { 30708 30709 var result = this.resultBuffer, 30710 values = this.sampleValues, 30711 stride = this.valueSize, 30712 30713 o1 = i1 * stride, o0 = o1 - stride, 30714 oP = this._offsetPrev, oN = this._offsetNext, 30715 wP = this._weightPrev, wN = this._weightNext, 30716 30717 p = ( t - t0 ) / ( t1 - t0 ), 30718 pp = p * p, 30719 ppp = pp * p; 30720 30721 // evaluate polynomials 30722 30723 var sP = - wP * ppp + 2 * wP * pp - wP * p; 30724 var s0 = ( 1 + wP ) * ppp + (-1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1; 30725 var s1 = (-1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; 30726 var sN = wN * ppp - wN * pp; 30727 30728 // combine data linearly 30729 30730 for ( var i = 0; i !== stride; ++ i ) { 30731 30732 result[ i ] = 30733 sP * values[ oP + i ] + 30734 s0 * values[ o0 + i ] + 30735 s1 * values[ o1 + i ] + 30736 sN * values[ oN + i ]; 30737 30738 } 30739 30740 return result; 30741 30742 } 30743 30744 } ); 30745 30746 /** 30747 * @author tschw 30748 */ 30749 30750 function LinearInterpolant( 30751 parameterPositions, sampleValues, sampleSize, resultBuffer ) { 30752 30753 Interpolant.call( 30754 this, parameterPositions, sampleValues, sampleSize, resultBuffer ); 30755 30756 } 30757 30758 LinearInterpolant.prototype = 30759 Object.assign( Object.create( Interpolant.prototype ), { 30760 30761 constructor: LinearInterpolant, 30762 30763 interpolate_: function( i1, t0, t, t1 ) { 30764 30765 var result = this.resultBuffer, 30766 values = this.sampleValues, 30767 stride = this.valueSize, 30768 30769 offset1 = i1 * stride, 30770 offset0 = offset1 - stride, 30771 30772 weight1 = ( t - t0 ) / ( t1 - t0 ), 30773 weight0 = 1 - weight1; 30774 30775 for ( var i = 0; i !== stride; ++ i ) { 30776 30777 result[ i ] = 30778 values[ offset0 + i ] * weight0 + 30779 values[ offset1 + i ] * weight1; 30780 30781 } 30782 30783 return result; 30784 30785 } 30786 30787 } ); 30788 30789 /** 30790 * 30791 * Interpolant that evaluates to the sample value at the position preceeding 30792 * the parameter. 30793 * 30794 * @author tschw 30795 */ 30796 30797 function DiscreteInterpolant( 30798 parameterPositions, sampleValues, sampleSize, resultBuffer ) { 30799 30800 Interpolant.call( 30801 this, parameterPositions, sampleValues, sampleSize, resultBuffer ); 30802 30803 } 30804 30805 DiscreteInterpolant.prototype = 30806 Object.assign( Object.create( Interpolant.prototype ), { 30807 30808 constructor: DiscreteInterpolant, 30809 30810 interpolate_: function( i1, t0, t, t1 ) { 30811 30812 return this.copySampleValue_( i1 - 1 ); 30813 30814 } 30815 30816 } ); 30817 30818 var KeyframeTrackPrototype; 30819 30820 KeyframeTrackPrototype = { 30821 30822 TimeBufferType: Float32Array, 30823 ValueBufferType: Float32Array, 30824 30825 DefaultInterpolation: InterpolateLinear, 30826 30827 InterpolantFactoryMethodDiscrete: function ( result ) { 30828 30829 return new DiscreteInterpolant( 30830 this.times, this.values, this.getValueSize(), result ); 30831 30832 }, 30833 30834 InterpolantFactoryMethodLinear: function ( result ) { 30835 30836 return new LinearInterpolant( 30837 this.times, this.values, this.getValueSize(), result ); 30838 30839 }, 30840 30841 InterpolantFactoryMethodSmooth: function ( result ) { 30842 30843 return new CubicInterpolant( 30844 this.times, this.values, this.getValueSize(), result ); 30845 30846 }, 30847 30848 setInterpolation: function ( interpolation ) { 30849 30850 var factoryMethod; 30851 30852 switch ( interpolation ) { 30853 30854 case InterpolateDiscrete: 30855 30856 factoryMethod = this.InterpolantFactoryMethodDiscrete; 30857 30858 break; 30859 30860 case InterpolateLinear: 30861 30862 factoryMethod = this.InterpolantFactoryMethodLinear; 30863 30864 break; 30865 30866 case InterpolateSmooth: 30867 30868 factoryMethod = this.InterpolantFactoryMethodSmooth; 30869 30870 break; 30871 30872 } 30873 30874 if ( factoryMethod === undefined ) { 30875 30876 var message = "unsupported interpolation for " + 30877 this.ValueTypeName + " keyframe track named " + this.name; 30878 30879 if ( this.createInterpolant === undefined ) { 30880 30881 // fall back to default, unless the default itself is messed up 30882 if ( interpolation !== this.DefaultInterpolation ) { 30883 30884 this.setInterpolation( this.DefaultInterpolation ); 30885 30886 } else { 30887 30888 throw new Error( message ); // fatal, in this case 30889 30890 } 30891 30892 } 30893 30894 console.warn( message ); 30895 return; 30896 30897 } 30898 30899 this.createInterpolant = factoryMethod; 30900 30901 }, 30902 30903 getInterpolation: function () { 30904 30905 switch ( this.createInterpolant ) { 30906 30907 case this.InterpolantFactoryMethodDiscrete: 30908 30909 return InterpolateDiscrete; 30910 30911 case this.InterpolantFactoryMethodLinear: 30912 30913 return InterpolateLinear; 30914 30915 case this.InterpolantFactoryMethodSmooth: 30916 30917 return InterpolateSmooth; 30918 30919 } 30920 30921 }, 30922 30923 getValueSize: function () { 30924 30925 return this.values.length / this.times.length; 30926 30927 }, 30928 30929 // move all keyframes either forwards or backwards in time 30930 shift: function ( timeOffset ) { 30931 30932 if ( timeOffset !== 0.0 ) { 30933 30934 var times = this.times; 30935 30936 for ( var i = 0, n = times.length; i !== n; ++ i ) { 30937 30938 times[ i ] += timeOffset; 30939 30940 } 30941 30942 } 30943 30944 return this; 30945 30946 }, 30947 30948 // scale all keyframe times by a factor (useful for frame <-> seconds conversions) 30949 scale: function ( timeScale ) { 30950 30951 if ( timeScale !== 1.0 ) { 30952 30953 var times = this.times; 30954 30955 for ( var i = 0, n = times.length; i !== n; ++ i ) { 30956 30957 times[ i ] *= timeScale; 30958 30959 } 30960 30961 } 30962 30963 return this; 30964 30965 }, 30966 30967 // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. 30968 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values 30969 trim: function ( startTime, endTime ) { 30970 30971 var times = this.times, 30972 nKeys = times.length, 30973 from = 0, 30974 to = nKeys - 1; 30975 30976 while ( from !== nKeys && times[ from ] < startTime ) ++ from; 30977 while ( to !== - 1 && times[ to ] > endTime ) -- to; 30978 30979 ++ to; // inclusive -> exclusive bound 30980 30981 if ( from !== 0 || to !== nKeys ) { 30982 30983 // empty tracks are forbidden, so keep at least one keyframe 30984 if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; 30985 30986 var stride = this.getValueSize(); 30987 this.times = AnimationUtils.arraySlice( times, from, to ); 30988 this.values = AnimationUtils. 30989 arraySlice( this.values, from * stride, to * stride ); 30990 30991 } 30992 30993 return this; 30994 30995 }, 30996 30997 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable 30998 validate: function () { 30999 31000 var valid = true; 31001 31002 var valueSize = this.getValueSize(); 31003 if ( valueSize - Math.floor( valueSize ) !== 0 ) { 31004 31005 console.error( "invalid value size in track", this ); 31006 valid = false; 31007 31008 } 31009 31010 var times = this.times, 31011 values = this.values, 31012 31013 nKeys = times.length; 31014 31015 if ( nKeys === 0 ) { 31016 31017 console.error( "track is empty", this ); 31018 valid = false; 31019 31020 } 31021 31022 var prevTime = null; 31023 31024 for ( var i = 0; i !== nKeys; i ++ ) { 31025 31026 var currTime = times[ i ]; 31027 31028 if ( typeof currTime === 'number' && isNaN( currTime ) ) { 31029 31030 console.error( "time is not a valid number", this, i, currTime ); 31031 valid = false; 31032 break; 31033 31034 } 31035 31036 if ( prevTime !== null && prevTime > currTime ) { 31037 31038 console.error( "out of order keys", this, i, currTime, prevTime ); 31039 valid = false; 31040 break; 31041 31042 } 31043 31044 prevTime = currTime; 31045 31046 } 31047 31048 if ( values !== undefined ) { 31049 31050 if ( AnimationUtils.isTypedArray( values ) ) { 31051 31052 for ( var i = 0, n = values.length; i !== n; ++ i ) { 31053 31054 var value = values[ i ]; 31055 31056 if ( isNaN( value ) ) { 31057 31058 console.error( "value is not a valid number", this, i, value ); 31059 valid = false; 31060 break; 31061 31062 } 31063 31064 } 31065 31066 } 31067 31068 } 31069 31070 return valid; 31071 31072 }, 31073 31074 // removes equivalent sequential keys as common in morph target sequences 31075 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) 31076 optimize: function () { 31077 31078 var times = this.times, 31079 values = this.values, 31080 stride = this.getValueSize(), 31081 31082 smoothInterpolation = this.getInterpolation() === InterpolateSmooth, 31083 31084 writeIndex = 1, 31085 lastIndex = times.length - 1; 31086 31087 for ( var i = 1; i < lastIndex; ++ i ) { 31088 31089 var keep = false; 31090 31091 var time = times[ i ]; 31092 var timeNext = times[ i + 1 ]; 31093 31094 // remove adjacent keyframes scheduled at the same time 31095 31096 if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { 31097 31098 if ( ! smoothInterpolation ) { 31099 31100 // remove unnecessary keyframes same as their neighbors 31101 31102 var offset = i * stride, 31103 offsetP = offset - stride, 31104 offsetN = offset + stride; 31105 31106 for ( var j = 0; j !== stride; ++ j ) { 31107 31108 var value = values[ offset + j ]; 31109 31110 if ( value !== values[ offsetP + j ] || 31111 value !== values[ offsetN + j ] ) { 31112 31113 keep = true; 31114 break; 31115 31116 } 31117 31118 } 31119 31120 } else keep = true; 31121 31122 } 31123 31124 // in-place compaction 31125 31126 if ( keep ) { 31127 31128 if ( i !== writeIndex ) { 31129 31130 times[ writeIndex ] = times[ i ]; 31131 31132 var readOffset = i * stride, 31133 writeOffset = writeIndex * stride; 31134 31135 for ( var j = 0; j !== stride; ++ j ) 31136 31137 values[ writeOffset + j ] = values[ readOffset + j ]; 31138 31139 } 31140 31141 ++ writeIndex; 31142 31143 } 31144 31145 } 31146 31147 // flush last keyframe (compaction looks ahead) 31148 31149 if ( lastIndex > 0 ) { 31150 31151 times[ writeIndex ] = times[ lastIndex ]; 31152 31153 for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) 31154 31155 values[ writeOffset + j ] = values[ readOffset + j ]; 31156 31157 ++ writeIndex; 31158 31159 } 31160 31161 if ( writeIndex !== times.length ) { 31162 31163 this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); 31164 this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); 31165 31166 } 31167 31168 return this; 31169 31170 } 31171 31172 }; 31173 31174 function KeyframeTrackConstructor( name, times, values, interpolation ) { 31175 31176 if( name === undefined ) throw new Error( "track name is undefined" ); 31177 31178 if( times === undefined || times.length === 0 ) { 31179 31180 throw new Error( "no keyframes in track named " + name ); 31181 31182 } 31183 31184 this.name = name; 31185 31186 this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); 31187 this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); 31188 31189 this.setInterpolation( interpolation || this.DefaultInterpolation ); 31190 31191 this.validate(); 31192 this.optimize(); 31193 31194 } 31195 31196 /** 31197 * 31198 * A Track of vectored keyframe values. 31199 * 31200 * 31201 * @author Ben Houston / http://clara.io/ 31202 * @author David Sarno / http://lighthaus.us/ 31203 * @author tschw 31204 */ 31205 31206 function VectorKeyframeTrack( name, times, values, interpolation ) { 31207 31208 KeyframeTrackConstructor.call( this, name, times, values, interpolation ); 31209 31210 } 31211 31212 VectorKeyframeTrack.prototype = 31213 Object.assign( Object.create( KeyframeTrackPrototype ), { 31214 31215 constructor: VectorKeyframeTrack, 31216 31217 ValueTypeName: 'vector' 31218 31219 // ValueBufferType is inherited 31220 31221 // DefaultInterpolation is inherited 31222 31223 } ); 31224 31225 /** 31226 * Spherical linear unit quaternion interpolant. 31227 * 31228 * @author tschw 31229 */ 31230 31231 function QuaternionLinearInterpolant( 31232 parameterPositions, sampleValues, sampleSize, resultBuffer ) { 31233 31234 Interpolant.call( 31235 this, parameterPositions, sampleValues, sampleSize, resultBuffer ); 31236 31237 } 31238 31239 QuaternionLinearInterpolant.prototype = 31240 Object.assign( Object.create( Interpolant.prototype ), { 31241 31242 constructor: QuaternionLinearInterpolant, 31243 31244 interpolate_: function( i1, t0, t, t1 ) { 31245 31246 var result = this.resultBuffer, 31247 values = this.sampleValues, 31248 stride = this.valueSize, 31249 31250 offset = i1 * stride, 31251 31252 alpha = ( t - t0 ) / ( t1 - t0 ); 31253 31254 for ( var end = offset + stride; offset !== end; offset += 4 ) { 31255 31256 Quaternion.slerpFlat( result, 0, 31257 values, offset - stride, values, offset, alpha ); 31258 31259 } 31260 31261 return result; 31262 31263 } 31264 31265 } ); 31266 31267 /** 31268 * 31269 * A Track of quaternion keyframe values. 31270 * 31271 * @author Ben Houston / http://clara.io/ 31272 * @author David Sarno / http://lighthaus.us/ 31273 * @author tschw 31274 */ 31275 31276 function QuaternionKeyframeTrack( name, times, values, interpolation ) { 31277 31278 KeyframeTrackConstructor.call( this, name, times, values, interpolation ); 31279 31280 } 31281 31282 QuaternionKeyframeTrack.prototype = 31283 Object.assign( Object.create( KeyframeTrackPrototype ), { 31284 31285 constructor: QuaternionKeyframeTrack, 31286 31287 ValueTypeName: 'quaternion', 31288 31289 // ValueBufferType is inherited 31290 31291 DefaultInterpolation: InterpolateLinear, 31292 31293 InterpolantFactoryMethodLinear: function( result ) { 31294 31295 return new QuaternionLinearInterpolant( 31296 this.times, this.values, this.getValueSize(), result ); 31297 31298 }, 31299 31300 InterpolantFactoryMethodSmooth: undefined // not yet implemented 31301 31302 } ); 31303 31304 /** 31305 * 31306 * A Track of numeric keyframe values. 31307 * 31308 * @author Ben Houston / http://clara.io/ 31309 * @author David Sarno / http://lighthaus.us/ 31310 * @author tschw 31311 */ 31312 31313 function NumberKeyframeTrack( name, times, values, interpolation ) { 31314 31315 KeyframeTrackConstructor.call( this, name, times, values, interpolation ); 31316 31317 } 31318 31319 NumberKeyframeTrack.prototype = 31320 Object.assign( Object.create( KeyframeTrackPrototype ), { 31321 31322 constructor: NumberKeyframeTrack, 31323 31324 ValueTypeName: 'number' 31325 31326 // ValueBufferType is inherited 31327 31328 // DefaultInterpolation is inherited 31329 31330 } ); 31331 31332 /** 31333 * 31334 * A Track that interpolates Strings 31335 * 31336 * 31337 * @author Ben Houston / http://clara.io/ 31338 * @author David Sarno / http://lighthaus.us/ 31339 * @author tschw 31340 */ 31341 31342 function StringKeyframeTrack( name, times, values, interpolation ) { 31343 31344 KeyframeTrackConstructor.call( this, name, times, values, interpolation ); 31345 31346 } 31347 31348 StringKeyframeTrack.prototype = 31349 Object.assign( Object.create( KeyframeTrackPrototype ), { 31350 31351 constructor: StringKeyframeTrack, 31352 31353 ValueTypeName: 'string', 31354 ValueBufferType: Array, 31355 31356 DefaultInterpolation: InterpolateDiscrete, 31357 31358 InterpolantFactoryMethodLinear: undefined, 31359 31360 InterpolantFactoryMethodSmooth: undefined 31361 31362 } ); 31363 31364 /** 31365 * 31366 * A Track of Boolean keyframe values. 31367 * 31368 * 31369 * @author Ben Houston / http://clara.io/ 31370 * @author David Sarno / http://lighthaus.us/ 31371 * @author tschw 31372 */ 31373 31374 function BooleanKeyframeTrack( name, times, values ) { 31375 31376 KeyframeTrackConstructor.call( this, name, times, values ); 31377 31378 } 31379 31380 BooleanKeyframeTrack.prototype = 31381 Object.assign( Object.create( KeyframeTrackPrototype ), { 31382 31383 constructor: BooleanKeyframeTrack, 31384 31385 ValueTypeName: 'bool', 31386 ValueBufferType: Array, 31387 31388 DefaultInterpolation: InterpolateDiscrete, 31389 31390 InterpolantFactoryMethodLinear: undefined, 31391 InterpolantFactoryMethodSmooth: undefined 31392 31393 // Note: Actually this track could have a optimized / compressed 31394 // representation of a single value and a custom interpolant that 31395 // computes "firstValue ^ isOdd( index )". 31396 31397 } ); 31398 31399 /** 31400 * 31401 * A Track of keyframe values that represent color. 31402 * 31403 * 31404 * @author Ben Houston / http://clara.io/ 31405 * @author David Sarno / http://lighthaus.us/ 31406 * @author tschw 31407 */ 31408 31409 function ColorKeyframeTrack( name, times, values, interpolation ) { 31410 31411 KeyframeTrackConstructor.call( this, name, times, values, interpolation ); 31412 31413 } 31414 31415 ColorKeyframeTrack.prototype = 31416 Object.assign( Object.create( KeyframeTrackPrototype ), { 31417 31418 constructor: ColorKeyframeTrack, 31419 31420 ValueTypeName: 'color' 31421 31422 // ValueBufferType is inherited 31423 31424 // DefaultInterpolation is inherited 31425 31426 31427 // Note: Very basic implementation and nothing special yet. 31428 // However, this is the place for color space parameterization. 31429 31430 } ); 31431 31432 /** 31433 * 31434 * A timed sequence of keyframes for a specific property. 31435 * 31436 * 31437 * @author Ben Houston / http://clara.io/ 31438 * @author David Sarno / http://lighthaus.us/ 31439 * @author tschw 31440 */ 31441 31442 function KeyframeTrack( name, times, values, interpolation ) { 31443 31444 KeyframeTrackConstructor.apply( this, arguments ); 31445 31446 } 31447 31448 KeyframeTrack.prototype = KeyframeTrackPrototype; 31449 KeyframeTrackPrototype.constructor = KeyframeTrack; 31450 31451 // Static methods: 31452 31453 Object.assign( KeyframeTrack, { 31454 31455 // Serialization (in static context, because of constructor invocation 31456 // and automatic invocation of .toJSON): 31457 31458 parse: function( json ) { 31459 31460 if( json.type === undefined ) { 31461 31462 throw new Error( "track type undefined, can not parse" ); 31463 31464 } 31465 31466 var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); 31467 31468 if ( json.times === undefined ) { 31469 31470 var times = [], values = []; 31471 31472 AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); 31473 31474 json.times = times; 31475 json.values = values; 31476 31477 } 31478 31479 // derived classes can define a static parse method 31480 if ( trackType.parse !== undefined ) { 31481 31482 return trackType.parse( json ); 31483 31484 } else { 31485 31486 // by default, we asssume a constructor compatible with the base 31487 return new trackType( 31488 json.name, json.times, json.values, json.interpolation ); 31489 31490 } 31491 31492 }, 31493 31494 toJSON: function( track ) { 31495 31496 var trackType = track.constructor; 31497 31498 var json; 31499 31500 // derived classes can define a static toJSON method 31501 if ( trackType.toJSON !== undefined ) { 31502 31503 json = trackType.toJSON( track ); 31504 31505 } else { 31506 31507 // by default, we assume the data can be serialized as-is 31508 json = { 31509 31510 'name': track.name, 31511 'times': AnimationUtils.convertArray( track.times, Array ), 31512 'values': AnimationUtils.convertArray( track.values, Array ) 31513 31514 }; 31515 31516 var interpolation = track.getInterpolation(); 31517 31518 if ( interpolation !== track.DefaultInterpolation ) { 31519 31520 json.interpolation = interpolation; 31521 31522 } 31523 31524 } 31525 31526 json.type = track.ValueTypeName; // mandatory 31527 31528 return json; 31529 31530 }, 31531 31532 _getTrackTypeForValueTypeName: function( typeName ) { 31533 31534 switch( typeName.toLowerCase() ) { 31535 31536 case "scalar": 31537 case "double": 31538 case "float": 31539 case "number": 31540 case "integer": 31541 31542 return NumberKeyframeTrack; 31543 31544 case "vector": 31545 case "vector2": 31546 case "vector3": 31547 case "vector4": 31548 31549 return VectorKeyframeTrack; 31550 31551 case "color": 31552 31553 return ColorKeyframeTrack; 31554 31555 case "quaternion": 31556 31557 return QuaternionKeyframeTrack; 31558 31559 case "bool": 31560 case "boolean": 31561 31562 return BooleanKeyframeTrack; 31563 31564 case "string": 31565 31566 return StringKeyframeTrack; 31567 31568 } 31569 31570 throw new Error( "Unsupported typeName: " + typeName ); 31571 31572 } 31573 31574 } ); 31575 31576 /** 31577 * 31578 * Reusable set of Tracks that represent an animation. 31579 * 31580 * @author Ben Houston / http://clara.io/ 31581 * @author David Sarno / http://lighthaus.us/ 31582 */ 31583 31584 function AnimationClip( name, duration, tracks ) { 31585 31586 this.name = name; 31587 this.tracks = tracks; 31588 this.duration = ( duration !== undefined ) ? duration : -1; 31589 31590 this.uuid = _Math.generateUUID(); 31591 31592 // this means it should figure out its duration by scanning the tracks 31593 if ( this.duration < 0 ) { 31594 31595 this.resetDuration(); 31596 31597 } 31598 31599 this.optimize(); 31600 31601 } 31602 31603 AnimationClip.prototype = { 31604 31605 constructor: AnimationClip, 31606 31607 resetDuration: function() { 31608 31609 var tracks = this.tracks, 31610 duration = 0; 31611 31612 for ( var i = 0, n = tracks.length; i !== n; ++ i ) { 31613 31614 var track = this.tracks[ i ]; 31615 31616 duration = Math.max( duration, track.times[ track.times.length - 1 ] ); 31617 31618 } 31619 31620 this.duration = duration; 31621 31622 }, 31623 31624 trim: function() { 31625 31626 for ( var i = 0; i < this.tracks.length; i ++ ) { 31627 31628 this.tracks[ i ].trim( 0, this.duration ); 31629 31630 } 31631 31632 return this; 31633 31634 }, 31635 31636 optimize: function() { 31637 31638 for ( var i = 0; i < this.tracks.length; i ++ ) { 31639 31640 this.tracks[ i ].optimize(); 31641 31642 } 31643 31644 return this; 31645 31646 } 31647 31648 }; 31649 31650 // Static methods: 31651 31652 Object.assign( AnimationClip, { 31653 31654 parse: function( json ) { 31655 31656 var tracks = [], 31657 jsonTracks = json.tracks, 31658 frameTime = 1.0 / ( json.fps || 1.0 ); 31659 31660 for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { 31661 31662 tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); 31663 31664 } 31665 31666 return new AnimationClip( json.name, json.duration, tracks ); 31667 31668 }, 31669 31670 31671 toJSON: function( clip ) { 31672 31673 var tracks = [], 31674 clipTracks = clip.tracks; 31675 31676 var json = { 31677 31678 'name': clip.name, 31679 'duration': clip.duration, 31680 'tracks': tracks 31681 31682 }; 31683 31684 for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { 31685 31686 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); 31687 31688 } 31689 31690 return json; 31691 31692 }, 31693 31694 31695 CreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) { 31696 31697 var numMorphTargets = morphTargetSequence.length; 31698 var tracks = []; 31699 31700 for ( var i = 0; i < numMorphTargets; i ++ ) { 31701 31702 var times = []; 31703 var values = []; 31704 31705 times.push( 31706 ( i + numMorphTargets - 1 ) % numMorphTargets, 31707 i, 31708 ( i + 1 ) % numMorphTargets ); 31709 31710 values.push( 0, 1, 0 ); 31711 31712 var order = AnimationUtils.getKeyframeOrder( times ); 31713 times = AnimationUtils.sortedArray( times, 1, order ); 31714 values = AnimationUtils.sortedArray( values, 1, order ); 31715 31716 // if there is a key at the first frame, duplicate it as the 31717 // last frame as well for perfect loop. 31718 if ( ! noLoop && times[ 0 ] === 0 ) { 31719 31720 times.push( numMorphTargets ); 31721 values.push( values[ 0 ] ); 31722 31723 } 31724 31725 tracks.push( 31726 new NumberKeyframeTrack( 31727 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', 31728 times, values 31729 ).scale( 1.0 / fps ) ); 31730 } 31731 31732 return new AnimationClip( name, -1, tracks ); 31733 31734 }, 31735 31736 findByName: function( objectOrClipArray, name ) { 31737 31738 var clipArray = objectOrClipArray; 31739 31740 if ( ! Array.isArray( objectOrClipArray ) ) { 31741 31742 var o = objectOrClipArray; 31743 clipArray = o.geometry && o.geometry.animations || o.animations; 31744 31745 } 31746 31747 for ( var i = 0; i < clipArray.length; i ++ ) { 31748 31749 if ( clipArray[ i ].name === name ) { 31750 31751 return clipArray[ i ]; 31752 31753 } 31754 } 31755 31756 return null; 31757 31758 }, 31759 31760 CreateClipsFromMorphTargetSequences: function( morphTargets, fps, noLoop ) { 31761 31762 var animationToMorphTargets = {}; 31763 31764 // tested with https://regex101.com/ on trick sequences 31765 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 31766 var pattern = /^([\w-]*?)([\d]+)$/; 31767 31768 // sort morph target names into animation groups based 31769 // patterns like Walk_001, Walk_002, Run_001, Run_002 31770 for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { 31771 31772 var morphTarget = morphTargets[ i ]; 31773 var parts = morphTarget.name.match( pattern ); 31774 31775 if ( parts && parts.length > 1 ) { 31776 31777 var name = parts[ 1 ]; 31778 31779 var animationMorphTargets = animationToMorphTargets[ name ]; 31780 if ( ! animationMorphTargets ) { 31781 31782 animationToMorphTargets[ name ] = animationMorphTargets = []; 31783 31784 } 31785 31786 animationMorphTargets.push( morphTarget ); 31787 31788 } 31789 31790 } 31791 31792 var clips = []; 31793 31794 for ( var name in animationToMorphTargets ) { 31795 31796 clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); 31797 31798 } 31799 31800 return clips; 31801 31802 }, 31803 31804 // parse the animation.hierarchy format 31805 parseAnimation: function( animation, bones ) { 31806 31807 if ( ! animation ) { 31808 31809 console.error( " no animation in JSONLoader data" ); 31810 return null; 31811 31812 } 31813 31814 var addNonemptyTrack = function( 31815 trackType, trackName, animationKeys, propertyName, destTracks ) { 31816 31817 // only return track if there are actually keys. 31818 if ( animationKeys.length !== 0 ) { 31819 31820 var times = []; 31821 var values = []; 31822 31823 AnimationUtils.flattenJSON( 31824 animationKeys, times, values, propertyName ); 31825 31826 // empty keys are filtered out, so check again 31827 if ( times.length !== 0 ) { 31828 31829 destTracks.push( new trackType( trackName, times, values ) ); 31830 31831 } 31832 31833 } 31834 31835 }; 31836 31837 var tracks = []; 31838 31839 var clipName = animation.name || 'default'; 31840 // automatic length determination in AnimationClip. 31841 var duration = animation.length || -1; 31842 var fps = animation.fps || 30; 31843 31844 var hierarchyTracks = animation.hierarchy || []; 31845 31846 for ( var h = 0; h < hierarchyTracks.length; h ++ ) { 31847 31848 var animationKeys = hierarchyTracks[ h ].keys; 31849 31850 // skip empty tracks 31851 if ( ! animationKeys || animationKeys.length === 0 ) continue; 31852 31853 // process morph targets in a way exactly compatible 31854 // with AnimationHandler.init( animation ) 31855 if ( animationKeys[0].morphTargets ) { 31856 31857 // figure out all morph targets used in this track 31858 var morphTargetNames = {}; 31859 for ( var k = 0; k < animationKeys.length; k ++ ) { 31860 31861 if ( animationKeys[k].morphTargets ) { 31862 31863 for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { 31864 31865 morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1; 31866 } 31867 31868 } 31869 31870 } 31871 31872 // create a track for each morph target with all zero 31873 // morphTargetInfluences except for the keys in which 31874 // the morphTarget is named. 31875 for ( var morphTargetName in morphTargetNames ) { 31876 31877 var times = []; 31878 var values = []; 31879 31880 for ( var m = 0; m !== animationKeys[k].morphTargets.length; ++ m ) { 31881 31882 var animationKey = animationKeys[k]; 31883 31884 times.push( animationKey.time ); 31885 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); 31886 31887 } 31888 31889 tracks.push( new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); 31890 31891 } 31892 31893 duration = morphTargetNames.length * ( fps || 1.0 ); 31894 31895 } else { 31896 // ...assume skeletal animation 31897 31898 var boneName = '.bones[' + bones[ h ].name + ']'; 31899 31900 addNonemptyTrack( 31901 VectorKeyframeTrack, boneName + '.position', 31902 animationKeys, 'pos', tracks ); 31903 31904 addNonemptyTrack( 31905 QuaternionKeyframeTrack, boneName + '.quaternion', 31906 animationKeys, 'rot', tracks ); 31907 31908 addNonemptyTrack( 31909 VectorKeyframeTrack, boneName + '.scale', 31910 animationKeys, 'scl', tracks ); 31911 31912 } 31913 31914 } 31915 31916 if ( tracks.length === 0 ) { 31917 31918 return null; 31919 31920 } 31921 31922 var clip = new AnimationClip( clipName, duration, tracks ); 31923 31924 return clip; 31925 31926 } 31927 31928 } ); 31929 31930 /** 31931 * @author mrdoob / http://mrdoob.com/ 31932 */ 31933 31934 function MaterialLoader( manager ) { 31935 31936 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 31937 this.textures = {}; 31938 31939 } 31940 31941 Object.assign( MaterialLoader.prototype, { 31942 31943 load: function ( url, onLoad, onProgress, onError ) { 31944 31945 var scope = this; 31946 31947 var loader = new FileLoader( scope.manager ); 31948 loader.load( url, function ( text ) { 31949 31950 onLoad( scope.parse( JSON.parse( text ) ) ); 31951 31952 }, onProgress, onError ); 31953 31954 }, 31955 31956 setTextures: function ( value ) { 31957 31958 this.textures = value; 31959 31960 }, 31961 31962 parse: function ( json ) { 31963 31964 var textures = this.textures; 31965 31966 function getTexture( name ) { 31967 31968 if ( textures[ name ] === undefined ) { 31969 31970 console.warn( 'THREE.MaterialLoader: Undefined texture', name ); 31971 31972 } 31973 31974 return textures[ name ]; 31975 31976 } 31977 31978 var material = new Materials[ json.type ](); 31979 31980 if ( json.uuid !== undefined ) material.uuid = json.uuid; 31981 if ( json.name !== undefined ) material.name = json.name; 31982 if ( json.color !== undefined ) material.color.setHex( json.color ); 31983 if ( json.roughness !== undefined ) material.roughness = json.roughness; 31984 if ( json.metalness !== undefined ) material.metalness = json.metalness; 31985 if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); 31986 if ( json.specular !== undefined ) material.specular.setHex( json.specular ); 31987 if ( json.shininess !== undefined ) material.shininess = json.shininess; 31988 if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; 31989 if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; 31990 if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; 31991 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; 31992 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; 31993 if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; 31994 if ( json.fog !== undefined ) material.fog = json.fog; 31995 if ( json.shading !== undefined ) material.shading = json.shading; 31996 if ( json.blending !== undefined ) material.blending = json.blending; 31997 if ( json.side !== undefined ) material.side = json.side; 31998 if ( json.opacity !== undefined ) material.opacity = json.opacity; 31999 if ( json.transparent !== undefined ) material.transparent = json.transparent; 32000 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; 32001 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; 32002 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; 32003 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; 32004 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; 32005 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; 32006 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; 32007 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; 32008 if ( json.skinning !== undefined ) material.skinning = json.skinning; 32009 if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; 32010 32011 // for PointsMaterial 32012 32013 if ( json.size !== undefined ) material.size = json.size; 32014 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; 32015 32016 // maps 32017 32018 if ( json.map !== undefined ) material.map = getTexture( json.map ); 32019 32020 if ( json.alphaMap !== undefined ) { 32021 32022 material.alphaMap = getTexture( json.alphaMap ); 32023 material.transparent = true; 32024 32025 } 32026 32027 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); 32028 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; 32029 32030 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); 32031 if ( json.normalScale !== undefined ) { 32032 32033 var normalScale = json.normalScale; 32034 32035 if ( Array.isArray( normalScale ) === false ) { 32036 32037 // Blender exporter used to export a scalar. See #7459 32038 32039 normalScale = [ normalScale, normalScale ]; 32040 32041 } 32042 32043 material.normalScale = new Vector2().fromArray( normalScale ); 32044 32045 } 32046 32047 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); 32048 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; 32049 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; 32050 32051 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); 32052 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); 32053 32054 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); 32055 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; 32056 32057 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); 32058 32059 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); 32060 32061 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; 32062 32063 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); 32064 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; 32065 32066 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); 32067 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; 32068 32069 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); 32070 32071 // MultiMaterial 32072 32073 if ( json.materials !== undefined ) { 32074 32075 for ( var i = 0, l = json.materials.length; i < l; i ++ ) { 32076 32077 material.materials.push( this.parse( json.materials[ i ] ) ); 32078 32079 } 32080 32081 } 32082 32083 return material; 32084 32085 } 32086 32087 } ); 32088 32089 /** 32090 * @author mrdoob / http://mrdoob.com/ 32091 */ 32092 32093 function BufferGeometryLoader( manager ) { 32094 32095 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 32096 32097 } 32098 32099 Object.assign( BufferGeometryLoader.prototype, { 32100 32101 load: function ( url, onLoad, onProgress, onError ) { 32102 32103 var scope = this; 32104 32105 var loader = new FileLoader( scope.manager ); 32106 loader.load( url, function ( text ) { 32107 32108 onLoad( scope.parse( JSON.parse( text ) ) ); 32109 32110 }, onProgress, onError ); 32111 32112 }, 32113 32114 parse: function ( json ) { 32115 32116 var geometry = new BufferGeometry(); 32117 32118 var index = json.data.index; 32119 32120 var TYPED_ARRAYS = { 32121 'Int8Array': Int8Array, 32122 'Uint8Array': Uint8Array, 32123 'Uint8ClampedArray': Uint8ClampedArray, 32124 'Int16Array': Int16Array, 32125 'Uint16Array': Uint16Array, 32126 'Int32Array': Int32Array, 32127 'Uint32Array': Uint32Array, 32128 'Float32Array': Float32Array, 32129 'Float64Array': Float64Array 32130 }; 32131 32132 if ( index !== undefined ) { 32133 32134 var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); 32135 geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); 32136 32137 } 32138 32139 var attributes = json.data.attributes; 32140 32141 for ( var key in attributes ) { 32142 32143 var attribute = attributes[ key ]; 32144 var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); 32145 32146 geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); 32147 32148 } 32149 32150 var groups = json.data.groups || json.data.drawcalls || json.data.offsets; 32151 32152 if ( groups !== undefined ) { 32153 32154 for ( var i = 0, n = groups.length; i !== n; ++ i ) { 32155 32156 var group = groups[ i ]; 32157 32158 geometry.addGroup( group.start, group.count, group.materialIndex ); 32159 32160 } 32161 32162 } 32163 32164 var boundingSphere = json.data.boundingSphere; 32165 32166 if ( boundingSphere !== undefined ) { 32167 32168 var center = new Vector3(); 32169 32170 if ( boundingSphere.center !== undefined ) { 32171 32172 center.fromArray( boundingSphere.center ); 32173 32174 } 32175 32176 geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); 32177 32178 } 32179 32180 return geometry; 32181 32182 } 32183 32184 } ); 32185 32186 /** 32187 * @author alteredq / http://alteredqualia.com/ 32188 */ 32189 32190 function Loader() { 32191 32192 this.onLoadStart = function () {}; 32193 this.onLoadProgress = function () {}; 32194 this.onLoadComplete = function () {}; 32195 32196 } 32197 32198 Loader.prototype = { 32199 32200 constructor: Loader, 32201 32202 crossOrigin: undefined, 32203 32204 extractUrlBase: function ( url ) { 32205 32206 var parts = url.split( '/' ); 32207 32208 if ( parts.length === 1 ) return './'; 32209 32210 parts.pop(); 32211 32212 return parts.join( '/' ) + '/'; 32213 32214 }, 32215 32216 initMaterials: function ( materials, texturePath, crossOrigin ) { 32217 32218 var array = []; 32219 32220 for ( var i = 0; i < materials.length; ++ i ) { 32221 32222 array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); 32223 32224 } 32225 32226 return array; 32227 32228 }, 32229 32230 createMaterial: ( function () { 32231 32232 var BlendingMode = { 32233 NoBlending: NoBlending, 32234 NormalBlending: NormalBlending, 32235 AdditiveBlending: AdditiveBlending, 32236 SubtractiveBlending: SubtractiveBlending, 32237 MultiplyBlending: MultiplyBlending, 32238 CustomBlending: CustomBlending 32239 }; 32240 32241 var color, textureLoader, materialLoader; 32242 32243 return function createMaterial( m, texturePath, crossOrigin ) { 32244 32245 if ( color === undefined ) color = new Color(); 32246 if ( textureLoader === undefined ) textureLoader = new TextureLoader(); 32247 if ( materialLoader === undefined ) materialLoader = new MaterialLoader(); 32248 32249 // convert from old material format 32250 32251 var textures = {}; 32252 32253 function loadTexture( path, repeat, offset, wrap, anisotropy ) { 32254 32255 var fullPath = texturePath + path; 32256 var loader = Loader.Handlers.get( fullPath ); 32257 32258 var texture; 32259 32260 if ( loader !== null ) { 32261 32262 texture = loader.load( fullPath ); 32263 32264 } else { 32265 32266 textureLoader.setCrossOrigin( crossOrigin ); 32267 texture = textureLoader.load( fullPath ); 32268 32269 } 32270 32271 if ( repeat !== undefined ) { 32272 32273 texture.repeat.fromArray( repeat ); 32274 32275 if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; 32276 if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; 32277 32278 } 32279 32280 if ( offset !== undefined ) { 32281 32282 texture.offset.fromArray( offset ); 32283 32284 } 32285 32286 if ( wrap !== undefined ) { 32287 32288 if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; 32289 if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; 32290 32291 if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; 32292 if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; 32293 32294 } 32295 32296 if ( anisotropy !== undefined ) { 32297 32298 texture.anisotropy = anisotropy; 32299 32300 } 32301 32302 var uuid = _Math.generateUUID(); 32303 32304 textures[ uuid ] = texture; 32305 32306 return uuid; 32307 32308 } 32309 32310 // 32311 32312 var json = { 32313 uuid: _Math.generateUUID(), 32314 type: 'MeshLambertMaterial' 32315 }; 32316 32317 for ( var name in m ) { 32318 32319 var value = m[ name ]; 32320 32321 switch ( name ) { 32322 32323 case 'DbgColor': 32324 case 'DbgIndex': 32325 case 'opticalDensity': 32326 case 'illumination': 32327 break; 32328 case 'DbgName': 32329 json.name = value; 32330 break; 32331 case 'blending': 32332 json.blending = BlendingMode[ value ]; 32333 break; 32334 case 'colorAmbient': 32335 case 'mapAmbient': 32336 console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); 32337 break; 32338 case 'colorDiffuse': 32339 json.color = color.fromArray( value ).getHex(); 32340 break; 32341 case 'colorSpecular': 32342 json.specular = color.fromArray( value ).getHex(); 32343 break; 32344 case 'colorEmissive': 32345 json.emissive = color.fromArray( value ).getHex(); 32346 break; 32347 case 'specularCoef': 32348 json.shininess = value; 32349 break; 32350 case 'shading': 32351 if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; 32352 if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; 32353 if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; 32354 break; 32355 case 'mapDiffuse': 32356 json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); 32357 break; 32358 case 'mapDiffuseRepeat': 32359 case 'mapDiffuseOffset': 32360 case 'mapDiffuseWrap': 32361 case 'mapDiffuseAnisotropy': 32362 break; 32363 case 'mapEmissive': 32364 json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); 32365 break; 32366 case 'mapEmissiveRepeat': 32367 case 'mapEmissiveOffset': 32368 case 'mapEmissiveWrap': 32369 case 'mapEmissiveAnisotropy': 32370 break; 32371 case 'mapLight': 32372 json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); 32373 break; 32374 case 'mapLightRepeat': 32375 case 'mapLightOffset': 32376 case 'mapLightWrap': 32377 case 'mapLightAnisotropy': 32378 break; 32379 case 'mapAO': 32380 json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); 32381 break; 32382 case 'mapAORepeat': 32383 case 'mapAOOffset': 32384 case 'mapAOWrap': 32385 case 'mapAOAnisotropy': 32386 break; 32387 case 'mapBump': 32388 json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); 32389 break; 32390 case 'mapBumpScale': 32391 json.bumpScale = value; 32392 break; 32393 case 'mapBumpRepeat': 32394 case 'mapBumpOffset': 32395 case 'mapBumpWrap': 32396 case 'mapBumpAnisotropy': 32397 break; 32398 case 'mapNormal': 32399 json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); 32400 break; 32401 case 'mapNormalFactor': 32402 json.normalScale = [ value, value ]; 32403 break; 32404 case 'mapNormalRepeat': 32405 case 'mapNormalOffset': 32406 case 'mapNormalWrap': 32407 case 'mapNormalAnisotropy': 32408 break; 32409 case 'mapSpecular': 32410 json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); 32411 break; 32412 case 'mapSpecularRepeat': 32413 case 'mapSpecularOffset': 32414 case 'mapSpecularWrap': 32415 case 'mapSpecularAnisotropy': 32416 break; 32417 case 'mapMetalness': 32418 json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); 32419 break; 32420 case 'mapMetalnessRepeat': 32421 case 'mapMetalnessOffset': 32422 case 'mapMetalnessWrap': 32423 case 'mapMetalnessAnisotropy': 32424 break; 32425 case 'mapRoughness': 32426 json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); 32427 break; 32428 case 'mapRoughnessRepeat': 32429 case 'mapRoughnessOffset': 32430 case 'mapRoughnessWrap': 32431 case 'mapRoughnessAnisotropy': 32432 break; 32433 case 'mapAlpha': 32434 json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); 32435 break; 32436 case 'mapAlphaRepeat': 32437 case 'mapAlphaOffset': 32438 case 'mapAlphaWrap': 32439 case 'mapAlphaAnisotropy': 32440 break; 32441 case 'flipSided': 32442 json.side = BackSide; 32443 break; 32444 case 'doubleSided': 32445 json.side = DoubleSide; 32446 break; 32447 case 'transparency': 32448 console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); 32449 json.opacity = value; 32450 break; 32451 case 'depthTest': 32452 case 'depthWrite': 32453 case 'colorWrite': 32454 case 'opacity': 32455 case 'reflectivity': 32456 case 'transparent': 32457 case 'visible': 32458 case 'wireframe': 32459 json[ name ] = value; 32460 break; 32461 case 'vertexColors': 32462 if ( value === true ) json.vertexColors = VertexColors; 32463 if ( value === 'face' ) json.vertexColors = FaceColors; 32464 break; 32465 default: 32466 console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); 32467 break; 32468 32469 } 32470 32471 } 32472 32473 if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; 32474 if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; 32475 32476 if ( json.opacity < 1 ) json.transparent = true; 32477 32478 materialLoader.setTextures( textures ); 32479 32480 return materialLoader.parse( json ); 32481 32482 }; 32483 32484 } )() 32485 32486 }; 32487 32488 Loader.Handlers = { 32489 32490 handlers: [], 32491 32492 add: function ( regex, loader ) { 32493 32494 this.handlers.push( regex, loader ); 32495 32496 }, 32497 32498 get: function ( file ) { 32499 32500 var handlers = this.handlers; 32501 32502 for ( var i = 0, l = handlers.length; i < l; i += 2 ) { 32503 32504 var regex = handlers[ i ]; 32505 var loader = handlers[ i + 1 ]; 32506 32507 if ( regex.test( file ) ) { 32508 32509 return loader; 32510 32511 } 32512 32513 } 32514 32515 return null; 32516 32517 } 32518 32519 }; 32520 32521 /** 32522 * @author mrdoob / http://mrdoob.com/ 32523 * @author alteredq / http://alteredqualia.com/ 32524 */ 32525 32526 function JSONLoader( manager ) { 32527 32528 if ( typeof manager === 'boolean' ) { 32529 32530 console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); 32531 manager = undefined; 32532 32533 } 32534 32535 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 32536 32537 this.withCredentials = false; 32538 32539 } 32540 32541 Object.assign( JSONLoader.prototype, { 32542 32543 load: function( url, onLoad, onProgress, onError ) { 32544 32545 var scope = this; 32546 32547 var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url ); 32548 32549 var loader = new FileLoader( this.manager ); 32550 loader.setWithCredentials( this.withCredentials ); 32551 loader.load( url, function ( text ) { 32552 32553 var json = JSON.parse( text ); 32554 var metadata = json.metadata; 32555 32556 if ( metadata !== undefined ) { 32557 32558 var type = metadata.type; 32559 32560 if ( type !== undefined ) { 32561 32562 if ( type.toLowerCase() === 'object' ) { 32563 32564 console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); 32565 return; 32566 32567 } 32568 32569 if ( type.toLowerCase() === 'scene' ) { 32570 32571 console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); 32572 return; 32573 32574 } 32575 32576 } 32577 32578 } 32579 32580 var object = scope.parse( json, texturePath ); 32581 onLoad( object.geometry, object.materials ); 32582 32583 }, onProgress, onError ); 32584 32585 }, 32586 32587 setTexturePath: function ( value ) { 32588 32589 this.texturePath = value; 32590 32591 }, 32592 32593 parse: function ( json, texturePath ) { 32594 32595 var geometry = new Geometry(), 32596 scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; 32597 32598 parseModel( scale ); 32599 32600 parseSkin(); 32601 parseMorphing( scale ); 32602 parseAnimations(); 32603 32604 geometry.computeFaceNormals(); 32605 geometry.computeBoundingSphere(); 32606 32607 function parseModel( scale ) { 32608 32609 function isBitSet( value, position ) { 32610 32611 return value & ( 1 << position ); 32612 32613 } 32614 32615 var i, j, fi, 32616 32617 offset, zLength, 32618 32619 colorIndex, normalIndex, uvIndex, materialIndex, 32620 32621 type, 32622 isQuad, 32623 hasMaterial, 32624 hasFaceVertexUv, 32625 hasFaceNormal, hasFaceVertexNormal, 32626 hasFaceColor, hasFaceVertexColor, 32627 32628 vertex, face, faceA, faceB, hex, normal, 32629 32630 uvLayer, uv, u, v, 32631 32632 faces = json.faces, 32633 vertices = json.vertices, 32634 normals = json.normals, 32635 colors = json.colors, 32636 32637 nUvLayers = 0; 32638 32639 if ( json.uvs !== undefined ) { 32640 32641 // disregard empty arrays 32642 32643 for ( i = 0; i < json.uvs.length; i ++ ) { 32644 32645 if ( json.uvs[ i ].length ) nUvLayers ++; 32646 32647 } 32648 32649 for ( i = 0; i < nUvLayers; i ++ ) { 32650 32651 geometry.faceVertexUvs[ i ] = []; 32652 32653 } 32654 32655 } 32656 32657 offset = 0; 32658 zLength = vertices.length; 32659 32660 while ( offset < zLength ) { 32661 32662 vertex = new Vector3(); 32663 32664 vertex.x = vertices[ offset ++ ] * scale; 32665 vertex.y = vertices[ offset ++ ] * scale; 32666 vertex.z = vertices[ offset ++ ] * scale; 32667 32668 geometry.vertices.push( vertex ); 32669 32670 } 32671 32672 offset = 0; 32673 zLength = faces.length; 32674 32675 while ( offset < zLength ) { 32676 32677 type = faces[ offset ++ ]; 32678 32679 32680 isQuad = isBitSet( type, 0 ); 32681 hasMaterial = isBitSet( type, 1 ); 32682 hasFaceVertexUv = isBitSet( type, 3 ); 32683 hasFaceNormal = isBitSet( type, 4 ); 32684 hasFaceVertexNormal = isBitSet( type, 5 ); 32685 hasFaceColor = isBitSet( type, 6 ); 32686 hasFaceVertexColor = isBitSet( type, 7 ); 32687 32688 // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); 32689 32690 if ( isQuad ) { 32691 32692 faceA = new Face3(); 32693 faceA.a = faces[ offset ]; 32694 faceA.b = faces[ offset + 1 ]; 32695 faceA.c = faces[ offset + 3 ]; 32696 32697 faceB = new Face3(); 32698 faceB.a = faces[ offset + 1 ]; 32699 faceB.b = faces[ offset + 2 ]; 32700 faceB.c = faces[ offset + 3 ]; 32701 32702 offset += 4; 32703 32704 if ( hasMaterial ) { 32705 32706 materialIndex = faces[ offset ++ ]; 32707 faceA.materialIndex = materialIndex; 32708 faceB.materialIndex = materialIndex; 32709 32710 } 32711 32712 // to get face <=> uv index correspondence 32713 32714 fi = geometry.faces.length; 32715 32716 if ( hasFaceVertexUv ) { 32717 32718 for ( i = 0; i < nUvLayers; i ++ ) { 32719 32720 uvLayer = json.uvs[ i ]; 32721 32722 geometry.faceVertexUvs[ i ][ fi ] = []; 32723 geometry.faceVertexUvs[ i ][ fi + 1 ] = []; 32724 32725 for ( j = 0; j < 4; j ++ ) { 32726 32727 uvIndex = faces[ offset ++ ]; 32728 32729 u = uvLayer[ uvIndex * 2 ]; 32730 v = uvLayer[ uvIndex * 2 + 1 ]; 32731 32732 uv = new Vector2( u, v ); 32733 32734 if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); 32735 if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); 32736 32737 } 32738 32739 } 32740 32741 } 32742 32743 if ( hasFaceNormal ) { 32744 32745 normalIndex = faces[ offset ++ ] * 3; 32746 32747 faceA.normal.set( 32748 normals[ normalIndex ++ ], 32749 normals[ normalIndex ++ ], 32750 normals[ normalIndex ] 32751 ); 32752 32753 faceB.normal.copy( faceA.normal ); 32754 32755 } 32756 32757 if ( hasFaceVertexNormal ) { 32758 32759 for ( i = 0; i < 4; i ++ ) { 32760 32761 normalIndex = faces[ offset ++ ] * 3; 32762 32763 normal = new Vector3( 32764 normals[ normalIndex ++ ], 32765 normals[ normalIndex ++ ], 32766 normals[ normalIndex ] 32767 ); 32768 32769 32770 if ( i !== 2 ) faceA.vertexNormals.push( normal ); 32771 if ( i !== 0 ) faceB.vertexNormals.push( normal ); 32772 32773 } 32774 32775 } 32776 32777 32778 if ( hasFaceColor ) { 32779 32780 colorIndex = faces[ offset ++ ]; 32781 hex = colors[ colorIndex ]; 32782 32783 faceA.color.setHex( hex ); 32784 faceB.color.setHex( hex ); 32785 32786 } 32787 32788 32789 if ( hasFaceVertexColor ) { 32790 32791 for ( i = 0; i < 4; i ++ ) { 32792 32793 colorIndex = faces[ offset ++ ]; 32794 hex = colors[ colorIndex ]; 32795 32796 if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); 32797 if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); 32798 32799 } 32800 32801 } 32802 32803 geometry.faces.push( faceA ); 32804 geometry.faces.push( faceB ); 32805 32806 } else { 32807 32808 face = new Face3(); 32809 face.a = faces[ offset ++ ]; 32810 face.b = faces[ offset ++ ]; 32811 face.c = faces[ offset ++ ]; 32812 32813 if ( hasMaterial ) { 32814 32815 materialIndex = faces[ offset ++ ]; 32816 face.materialIndex = materialIndex; 32817 32818 } 32819 32820 // to get face <=> uv index correspondence 32821 32822 fi = geometry.faces.length; 32823 32824 if ( hasFaceVertexUv ) { 32825 32826 for ( i = 0; i < nUvLayers; i ++ ) { 32827 32828 uvLayer = json.uvs[ i ]; 32829 32830 geometry.faceVertexUvs[ i ][ fi ] = []; 32831 32832 for ( j = 0; j < 3; j ++ ) { 32833 32834 uvIndex = faces[ offset ++ ]; 32835 32836 u = uvLayer[ uvIndex * 2 ]; 32837 v = uvLayer[ uvIndex * 2 + 1 ]; 32838 32839 uv = new Vector2( u, v ); 32840 32841 geometry.faceVertexUvs[ i ][ fi ].push( uv ); 32842 32843 } 32844 32845 } 32846 32847 } 32848 32849 if ( hasFaceNormal ) { 32850 32851 normalIndex = faces[ offset ++ ] * 3; 32852 32853 face.normal.set( 32854 normals[ normalIndex ++ ], 32855 normals[ normalIndex ++ ], 32856 normals[ normalIndex ] 32857 ); 32858 32859 } 32860 32861 if ( hasFaceVertexNormal ) { 32862 32863 for ( i = 0; i < 3; i ++ ) { 32864 32865 normalIndex = faces[ offset ++ ] * 3; 32866 32867 normal = new Vector3( 32868 normals[ normalIndex ++ ], 32869 normals[ normalIndex ++ ], 32870 normals[ normalIndex ] 32871 ); 32872 32873 face.vertexNormals.push( normal ); 32874 32875 } 32876 32877 } 32878 32879 32880 if ( hasFaceColor ) { 32881 32882 colorIndex = faces[ offset ++ ]; 32883 face.color.setHex( colors[ colorIndex ] ); 32884 32885 } 32886 32887 32888 if ( hasFaceVertexColor ) { 32889 32890 for ( i = 0; i < 3; i ++ ) { 32891 32892 colorIndex = faces[ offset ++ ]; 32893 face.vertexColors.push( new Color( colors[ colorIndex ] ) ); 32894 32895 } 32896 32897 } 32898 32899 geometry.faces.push( face ); 32900 32901 } 32902 32903 } 32904 32905 } 32906 32907 function parseSkin() { 32908 32909 var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; 32910 32911 if ( json.skinWeights ) { 32912 32913 for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { 32914 32915 var x = json.skinWeights[ i ]; 32916 var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; 32917 var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; 32918 var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; 32919 32920 geometry.skinWeights.push( new Vector4( x, y, z, w ) ); 32921 32922 } 32923 32924 } 32925 32926 if ( json.skinIndices ) { 32927 32928 for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { 32929 32930 var a = json.skinIndices[ i ]; 32931 var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; 32932 var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; 32933 var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; 32934 32935 geometry.skinIndices.push( new Vector4( a, b, c, d ) ); 32936 32937 } 32938 32939 } 32940 32941 geometry.bones = json.bones; 32942 32943 if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { 32944 32945 console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + 32946 geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); 32947 32948 } 32949 32950 } 32951 32952 function parseMorphing( scale ) { 32953 32954 if ( json.morphTargets !== undefined ) { 32955 32956 for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { 32957 32958 geometry.morphTargets[ i ] = {}; 32959 geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; 32960 geometry.morphTargets[ i ].vertices = []; 32961 32962 var dstVertices = geometry.morphTargets[ i ].vertices; 32963 var srcVertices = json.morphTargets[ i ].vertices; 32964 32965 for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { 32966 32967 var vertex = new Vector3(); 32968 vertex.x = srcVertices[ v ] * scale; 32969 vertex.y = srcVertices[ v + 1 ] * scale; 32970 vertex.z = srcVertices[ v + 2 ] * scale; 32971 32972 dstVertices.push( vertex ); 32973 32974 } 32975 32976 } 32977 32978 } 32979 32980 if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { 32981 32982 console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); 32983 32984 var faces = geometry.faces; 32985 var morphColors = json.morphColors[ 0 ].colors; 32986 32987 for ( var i = 0, l = faces.length; i < l; i ++ ) { 32988 32989 faces[ i ].color.fromArray( morphColors, i * 3 ); 32990 32991 } 32992 32993 } 32994 32995 } 32996 32997 function parseAnimations() { 32998 32999 var outputAnimations = []; 33000 33001 // parse old style Bone/Hierarchy animations 33002 var animations = []; 33003 33004 if ( json.animation !== undefined ) { 33005 33006 animations.push( json.animation ); 33007 33008 } 33009 33010 if ( json.animations !== undefined ) { 33011 33012 if ( json.animations.length ) { 33013 33014 animations = animations.concat( json.animations ); 33015 33016 } else { 33017 33018 animations.push( json.animations ); 33019 33020 } 33021 33022 } 33023 33024 for ( var i = 0; i < animations.length; i ++ ) { 33025 33026 var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); 33027 if ( clip ) outputAnimations.push( clip ); 33028 33029 } 33030 33031 // parse implicit morph animations 33032 if ( geometry.morphTargets ) { 33033 33034 // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. 33035 var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); 33036 outputAnimations = outputAnimations.concat( morphAnimationClips ); 33037 33038 } 33039 33040 if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; 33041 33042 } 33043 33044 if ( json.materials === undefined || json.materials.length === 0 ) { 33045 33046 return { geometry: geometry }; 33047 33048 } else { 33049 33050 var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); 33051 33052 return { geometry: geometry, materials: materials }; 33053 33054 } 33055 33056 } 33057 33058 } ); 33059 33060 /** 33061 * @author mrdoob / http://mrdoob.com/ 33062 */ 33063 33064 function ObjectLoader( manager ) { 33065 33066 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 33067 this.texturePath = ''; 33068 33069 } 33070 33071 Object.assign( ObjectLoader.prototype, { 33072 33073 load: function ( url, onLoad, onProgress, onError ) { 33074 33075 if ( this.texturePath === '' ) { 33076 33077 this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); 33078 33079 } 33080 33081 var scope = this; 33082 33083 var loader = new FileLoader( scope.manager ); 33084 loader.load( url, function ( text ) { 33085 33086 var json = null; 33087 33088 try { 33089 33090 json = JSON.parse( text ); 33091 33092 } catch ( error ) { 33093 33094 if ( onError !== undefined ) onError( error ); 33095 33096 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); 33097 33098 return; 33099 33100 } 33101 33102 var metadata = json.metadata; 33103 33104 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { 33105 33106 console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); 33107 return; 33108 33109 } 33110 33111 scope.parse( json, onLoad ); 33112 33113 }, onProgress, onError ); 33114 33115 }, 33116 33117 setTexturePath: function ( value ) { 33118 33119 this.texturePath = value; 33120 33121 }, 33122 33123 setCrossOrigin: function ( value ) { 33124 33125 this.crossOrigin = value; 33126 33127 }, 33128 33129 parse: function ( json, onLoad ) { 33130 33131 var geometries = this.parseGeometries( json.geometries ); 33132 33133 var images = this.parseImages( json.images, function () { 33134 33135 if ( onLoad !== undefined ) onLoad( object ); 33136 33137 } ); 33138 33139 var textures = this.parseTextures( json.textures, images ); 33140 var materials = this.parseMaterials( json.materials, textures ); 33141 33142 var object = this.parseObject( json.object, geometries, materials ); 33143 33144 if ( json.animations ) { 33145 33146 object.animations = this.parseAnimations( json.animations ); 33147 33148 } 33149 33150 if ( json.images === undefined || json.images.length === 0 ) { 33151 33152 if ( onLoad !== undefined ) onLoad( object ); 33153 33154 } 33155 33156 return object; 33157 33158 }, 33159 33160 parseGeometries: function ( json ) { 33161 33162 var geometries = {}; 33163 33164 if ( json !== undefined ) { 33165 33166 var geometryLoader = new JSONLoader(); 33167 var bufferGeometryLoader = new BufferGeometryLoader(); 33168 33169 for ( var i = 0, l = json.length; i < l; i ++ ) { 33170 33171 var geometry; 33172 var data = json[ i ]; 33173 33174 switch ( data.type ) { 33175 33176 case 'PlaneGeometry': 33177 case 'PlaneBufferGeometry': 33178 33179 geometry = new Geometries[ data.type ]( 33180 data.width, 33181 data.height, 33182 data.widthSegments, 33183 data.heightSegments 33184 ); 33185 33186 break; 33187 33188 case 'BoxGeometry': 33189 case 'BoxBufferGeometry': 33190 case 'CubeGeometry': // backwards compatible 33191 33192 geometry = new Geometries[ data.type ]( 33193 data.width, 33194 data.height, 33195 data.depth, 33196 data.widthSegments, 33197 data.heightSegments, 33198 data.depthSegments 33199 ); 33200 33201 break; 33202 33203 case 'CircleGeometry': 33204 case 'CircleBufferGeometry': 33205 33206 geometry = new Geometries[ data.type ]( 33207 data.radius, 33208 data.segments, 33209 data.thetaStart, 33210 data.thetaLength 33211 ); 33212 33213 break; 33214 33215 case 'CylinderGeometry': 33216 case 'CylinderBufferGeometry': 33217 33218 geometry = new Geometries[ data.type ]( 33219 data.radiusTop, 33220 data.radiusBottom, 33221 data.height, 33222 data.radialSegments, 33223 data.heightSegments, 33224 data.openEnded, 33225 data.thetaStart, 33226 data.thetaLength 33227 ); 33228 33229 break; 33230 33231 case 'ConeGeometry': 33232 case 'ConeBufferGeometry': 33233 33234 geometry = new Geometries[ data.type ]( 33235 data.radius, 33236 data.height, 33237 data.radialSegments, 33238 data.heightSegments, 33239 data.openEnded, 33240 data.thetaStart, 33241 data.thetaLength 33242 ); 33243 33244 break; 33245 33246 case 'SphereGeometry': 33247 case 'SphereBufferGeometry': 33248 33249 geometry = new Geometries[ data.type ]( 33250 data.radius, 33251 data.widthSegments, 33252 data.heightSegments, 33253 data.phiStart, 33254 data.phiLength, 33255 data.thetaStart, 33256 data.thetaLength 33257 ); 33258 33259 break; 33260 33261 case 'DodecahedronGeometry': 33262 case 'IcosahedronGeometry': 33263 case 'OctahedronGeometry': 33264 case 'TetrahedronGeometry': 33265 33266 geometry = new Geometries[ data.type ]( 33267 data.radius, 33268 data.detail 33269 ); 33270 33271 break; 33272 33273 case 'RingGeometry': 33274 case 'RingBufferGeometry': 33275 33276 geometry = new Geometries[ data.type ]( 33277 data.innerRadius, 33278 data.outerRadius, 33279 data.thetaSegments, 33280 data.phiSegments, 33281 data.thetaStart, 33282 data.thetaLength 33283 ); 33284 33285 break; 33286 33287 case 'TorusGeometry': 33288 case 'TorusBufferGeometry': 33289 33290 geometry = new Geometries[ data.type ]( 33291 data.radius, 33292 data.tube, 33293 data.radialSegments, 33294 data.tubularSegments, 33295 data.arc 33296 ); 33297 33298 break; 33299 33300 case 'TorusKnotGeometry': 33301 case 'TorusKnotBufferGeometry': 33302 33303 geometry = new Geometries[ data.type ]( 33304 data.radius, 33305 data.tube, 33306 data.tubularSegments, 33307 data.radialSegments, 33308 data.p, 33309 data.q 33310 ); 33311 33312 break; 33313 33314 case 'LatheGeometry': 33315 case 'LatheBufferGeometry': 33316 33317 geometry = new Geometries[ data.type ]( 33318 data.points, 33319 data.segments, 33320 data.phiStart, 33321 data.phiLength 33322 ); 33323 33324 break; 33325 33326 case 'BufferGeometry': 33327 33328 geometry = bufferGeometryLoader.parse( data ); 33329 33330 break; 33331 33332 case 'Geometry': 33333 33334 geometry = geometryLoader.parse( data.data, this.texturePath ).geometry; 33335 33336 break; 33337 33338 default: 33339 33340 console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); 33341 33342 continue; 33343 33344 } 33345 33346 geometry.uuid = data.uuid; 33347 33348 if ( data.name !== undefined ) geometry.name = data.name; 33349 33350 geometries[ data.uuid ] = geometry; 33351 33352 } 33353 33354 } 33355 33356 return geometries; 33357 33358 }, 33359 33360 parseMaterials: function ( json, textures ) { 33361 33362 var materials = {}; 33363 33364 if ( json !== undefined ) { 33365 33366 var loader = new MaterialLoader(); 33367 loader.setTextures( textures ); 33368 33369 for ( var i = 0, l = json.length; i < l; i ++ ) { 33370 33371 var material = loader.parse( json[ i ] ); 33372 materials[ material.uuid ] = material; 33373 33374 } 33375 33376 } 33377 33378 return materials; 33379 33380 }, 33381 33382 parseAnimations: function ( json ) { 33383 33384 var animations = []; 33385 33386 for ( var i = 0; i < json.length; i ++ ) { 33387 33388 var clip = AnimationClip.parse( json[ i ] ); 33389 33390 animations.push( clip ); 33391 33392 } 33393 33394 return animations; 33395 33396 }, 33397 33398 parseImages: function ( json, onLoad ) { 33399 33400 var scope = this; 33401 var images = {}; 33402 33403 function loadImage( url ) { 33404 33405 scope.manager.itemStart( url ); 33406 33407 return loader.load( url, function () { 33408 33409 scope.manager.itemEnd( url ); 33410 33411 }, undefined, function () { 33412 33413 scope.manager.itemError( url ); 33414 33415 } ); 33416 33417 } 33418 33419 if ( json !== undefined && json.length > 0 ) { 33420 33421 var manager = new LoadingManager( onLoad ); 33422 33423 var loader = new ImageLoader( manager ); 33424 loader.setCrossOrigin( this.crossOrigin ); 33425 33426 for ( var i = 0, l = json.length; i < l; i ++ ) { 33427 33428 var image = json[ i ]; 33429 var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; 33430 33431 images[ image.uuid ] = loadImage( path ); 33432 33433 } 33434 33435 } 33436 33437 return images; 33438 33439 }, 33440 33441 parseTextures: function ( json, images ) { 33442 33443 var TextureMapping = { 33444 UVMapping: UVMapping, 33445 CubeReflectionMapping: CubeReflectionMapping, 33446 CubeRefractionMapping: CubeRefractionMapping, 33447 EquirectangularReflectionMapping: EquirectangularReflectionMapping, 33448 EquirectangularRefractionMapping: EquirectangularRefractionMapping, 33449 SphericalReflectionMapping: SphericalReflectionMapping, 33450 CubeUVReflectionMapping: CubeUVReflectionMapping, 33451 CubeUVRefractionMapping: CubeUVRefractionMapping 33452 }; 33453 33454 var TextureWrapping = { 33455 RepeatWrapping: RepeatWrapping, 33456 ClampToEdgeWrapping: ClampToEdgeWrapping, 33457 MirroredRepeatWrapping: MirroredRepeatWrapping 33458 }; 33459 33460 var TextureFilter = { 33461 NearestFilter: NearestFilter, 33462 NearestMipMapNearestFilter: NearestMipMapNearestFilter, 33463 NearestMipMapLinearFilter: NearestMipMapLinearFilter, 33464 LinearFilter: LinearFilter, 33465 LinearMipMapNearestFilter: LinearMipMapNearestFilter, 33466 LinearMipMapLinearFilter: LinearMipMapLinearFilter 33467 }; 33468 33469 function parseConstant( value, type ) { 33470 33471 if ( typeof( value ) === 'number' ) return value; 33472 33473 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); 33474 33475 return type[ value ]; 33476 33477 } 33478 33479 var textures = {}; 33480 33481 if ( json !== undefined ) { 33482 33483 for ( var i = 0, l = json.length; i < l; i ++ ) { 33484 33485 var data = json[ i ]; 33486 33487 if ( data.image === undefined ) { 33488 33489 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); 33490 33491 } 33492 33493 if ( images[ data.image ] === undefined ) { 33494 33495 console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); 33496 33497 } 33498 33499 var texture = new Texture( images[ data.image ] ); 33500 texture.needsUpdate = true; 33501 33502 texture.uuid = data.uuid; 33503 33504 if ( data.name !== undefined ) texture.name = data.name; 33505 33506 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TextureMapping ); 33507 33508 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); 33509 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); 33510 if ( data.wrap !== undefined ) { 33511 33512 texture.wrapS = parseConstant( data.wrap[ 0 ], TextureWrapping ); 33513 texture.wrapT = parseConstant( data.wrap[ 1 ], TextureWrapping ); 33514 33515 } 33516 33517 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TextureFilter ); 33518 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TextureFilter ); 33519 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; 33520 33521 if ( data.flipY !== undefined ) texture.flipY = data.flipY; 33522 33523 textures[ data.uuid ] = texture; 33524 33525 } 33526 33527 } 33528 33529 return textures; 33530 33531 }, 33532 33533 parseObject: function () { 33534 33535 var matrix = new Matrix4(); 33536 33537 return function parseObject( data, geometries, materials ) { 33538 33539 var object; 33540 33541 function getGeometry( name ) { 33542 33543 if ( geometries[ name ] === undefined ) { 33544 33545 console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); 33546 33547 } 33548 33549 return geometries[ name ]; 33550 33551 } 33552 33553 function getMaterial( name ) { 33554 33555 if ( name === undefined ) return undefined; 33556 33557 if ( materials[ name ] === undefined ) { 33558 33559 console.warn( 'THREE.ObjectLoader: Undefined material', name ); 33560 33561 } 33562 33563 return materials[ name ]; 33564 33565 } 33566 33567 switch ( data.type ) { 33568 33569 case 'Scene': 33570 33571 object = new Scene(); 33572 33573 if ( data.background !== undefined ) { 33574 33575 if ( Number.isInteger( data.background ) ) { 33576 33577 object.background = new Color( data.background ); 33578 33579 } 33580 33581 } 33582 33583 if ( data.fog !== undefined ) { 33584 33585 if ( data.fog.type === 'Fog' ) { 33586 33587 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); 33588 33589 } else if ( data.fog.type === 'FogExp2' ) { 33590 33591 object.fog = new FogExp2( data.fog.color, data.fog.density ); 33592 33593 } 33594 33595 } 33596 33597 break; 33598 33599 case 'PerspectiveCamera': 33600 33601 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); 33602 33603 if ( data.focus !== undefined ) object.focus = data.focus; 33604 if ( data.zoom !== undefined ) object.zoom = data.zoom; 33605 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; 33606 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; 33607 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); 33608 33609 break; 33610 33611 case 'OrthographicCamera': 33612 33613 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); 33614 33615 break; 33616 33617 case 'AmbientLight': 33618 33619 object = new AmbientLight( data.color, data.intensity ); 33620 33621 break; 33622 33623 case 'DirectionalLight': 33624 33625 object = new DirectionalLight( data.color, data.intensity ); 33626 33627 break; 33628 33629 case 'PointLight': 33630 33631 object = new PointLight( data.color, data.intensity, data.distance, data.decay ); 33632 33633 break; 33634 33635 case 'SpotLight': 33636 33637 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); 33638 33639 break; 33640 33641 case 'HemisphereLight': 33642 33643 object = new HemisphereLight( data.color, data.groundColor, data.intensity ); 33644 33645 break; 33646 33647 case 'Mesh': 33648 33649 var geometry = getGeometry( data.geometry ); 33650 var material = getMaterial( data.material ); 33651 33652 if ( geometry.bones && geometry.bones.length > 0 ) { 33653 33654 object = new SkinnedMesh( geometry, material ); 33655 33656 } else { 33657 33658 object = new Mesh( geometry, material ); 33659 33660 } 33661 33662 break; 33663 33664 case 'LOD': 33665 33666 object = new LOD(); 33667 33668 break; 33669 33670 case 'Line': 33671 33672 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); 33673 33674 break; 33675 33676 case 'LineSegments': 33677 33678 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); 33679 33680 break; 33681 33682 case 'PointCloud': 33683 case 'Points': 33684 33685 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); 33686 33687 break; 33688 33689 case 'Sprite': 33690 33691 object = new Sprite( getMaterial( data.material ) ); 33692 33693 break; 33694 33695 case 'Group': 33696 33697 object = new Group(); 33698 33699 break; 33700 33701 case 'SkinnedMesh': 33702 33703 console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh type. Instantiates Object3D instead.' ); 33704 33705 default: 33706 33707 object = new Object3D(); 33708 33709 } 33710 33711 object.uuid = data.uuid; 33712 33713 if ( data.name !== undefined ) object.name = data.name; 33714 if ( data.matrix !== undefined ) { 33715 33716 matrix.fromArray( data.matrix ); 33717 matrix.decompose( object.position, object.quaternion, object.scale ); 33718 33719 } else { 33720 33721 if ( data.position !== undefined ) object.position.fromArray( data.position ); 33722 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); 33723 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); 33724 if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); 33725 33726 } 33727 33728 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; 33729 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; 33730 33731 if ( data.shadow ) { 33732 33733 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; 33734 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; 33735 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); 33736 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); 33737 33738 } 33739 33740 if ( data.visible !== undefined ) object.visible = data.visible; 33741 if ( data.userData !== undefined ) object.userData = data.userData; 33742 33743 if ( data.children !== undefined ) { 33744 33745 for ( var child in data.children ) { 33746 33747 object.add( this.parseObject( data.children[ child ], geometries, materials ) ); 33748 33749 } 33750 33751 } 33752 33753 if ( data.type === 'LOD' ) { 33754 33755 var levels = data.levels; 33756 33757 for ( var l = 0; l < levels.length; l ++ ) { 33758 33759 var level = levels[ l ]; 33760 var child = object.getObjectByProperty( 'uuid', level.object ); 33761 33762 if ( child !== undefined ) { 33763 33764 object.addLevel( child, level.distance ); 33765 33766 } 33767 33768 } 33769 33770 } 33771 33772 return object; 33773 33774 }; 33775 33776 }() 33777 33778 } ); 33779 33780 /** 33781 * @author zz85 / http://www.lab4games.net/zz85/blog 33782 * 33783 * Bezier Curves formulas obtained from 33784 * http://en.wikipedia.org/wiki/Bézier_curve 33785 */ 33786 33787 function CatmullRom( t, p0, p1, p2, p3 ) { 33788 33789 var v0 = ( p2 - p0 ) * 0.5; 33790 var v1 = ( p3 - p1 ) * 0.5; 33791 var t2 = t * t; 33792 var t3 = t * t2; 33793 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; 33794 33795 } 33796 33797 // 33798 33799 function QuadraticBezierP0( t, p ) { 33800 33801 var k = 1 - t; 33802 return k * k * p; 33803 33804 } 33805 33806 function QuadraticBezierP1( t, p ) { 33807 33808 return 2 * ( 1 - t ) * t * p; 33809 33810 } 33811 33812 function QuadraticBezierP2( t, p ) { 33813 33814 return t * t * p; 33815 33816 } 33817 33818 function QuadraticBezier( t, p0, p1, p2 ) { 33819 33820 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + 33821 QuadraticBezierP2( t, p2 ); 33822 33823 } 33824 33825 // 33826 33827 function CubicBezierP0( t, p ) { 33828 33829 var k = 1 - t; 33830 return k * k * k * p; 33831 33832 } 33833 33834 function CubicBezierP1( t, p ) { 33835 33836 var k = 1 - t; 33837 return 3 * k * k * t * p; 33838 33839 } 33840 33841 function CubicBezierP2( t, p ) { 33842 33843 return 3 * ( 1 - t ) * t * t * p; 33844 33845 } 33846 33847 function CubicBezierP3( t, p ) { 33848 33849 return t * t * t * p; 33850 33851 } 33852 33853 function CubicBezier( t, p0, p1, p2, p3 ) { 33854 33855 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + 33856 CubicBezierP3( t, p3 ); 33857 33858 } 33859 33860 /** 33861 * @author zz85 / http://www.lab4games.net/zz85/blog 33862 * Extensible curve object 33863 * 33864 * Some common of Curve methods 33865 * .getPoint(t), getTangent(t) 33866 * .getPointAt(u), getTangentAt(u) 33867 * .getPoints(), .getSpacedPoints() 33868 * .getLength() 33869 * .updateArcLengths() 33870 * 33871 * This following classes subclasses THREE.Curve: 33872 * 33873 * -- 2d classes -- 33874 * THREE.LineCurve 33875 * THREE.QuadraticBezierCurve 33876 * THREE.CubicBezierCurve 33877 * THREE.SplineCurve 33878 * THREE.ArcCurve 33879 * THREE.EllipseCurve 33880 * 33881 * -- 3d classes -- 33882 * THREE.LineCurve3 33883 * THREE.QuadraticBezierCurve3 33884 * THREE.CubicBezierCurve3 33885 * THREE.CatmullRomCurve3 33886 * 33887 * A series of curves can be represented as a THREE.CurvePath 33888 * 33889 **/ 33890 33891 /************************************************************** 33892 * Abstract Curve base class 33893 **************************************************************/ 33894 33895 function Curve() {} 33896 33897 Curve.prototype = { 33898 33899 constructor: Curve, 33900 33901 // Virtual base class method to overwrite and implement in subclasses 33902 // - t [0 .. 1] 33903 33904 getPoint: function ( t ) { 33905 33906 console.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); 33907 return null; 33908 33909 }, 33910 33911 // Get point at relative position in curve according to arc length 33912 // - u [0 .. 1] 33913 33914 getPointAt: function ( u ) { 33915 33916 var t = this.getUtoTmapping( u ); 33917 return this.getPoint( t ); 33918 33919 }, 33920 33921 // Get sequence of points using getPoint( t ) 33922 33923 getPoints: function ( divisions ) { 33924 33925 if ( isNaN( divisions ) ) divisions = 5; 33926 33927 var points = []; 33928 33929 for ( var d = 0; d <= divisions; d ++ ) { 33930 33931 points.push( this.getPoint( d / divisions ) ); 33932 33933 } 33934 33935 return points; 33936 33937 }, 33938 33939 // Get sequence of points using getPointAt( u ) 33940 33941 getSpacedPoints: function ( divisions ) { 33942 33943 if ( isNaN( divisions ) ) divisions = 5; 33944 33945 var points = []; 33946 33947 for ( var d = 0; d <= divisions; d ++ ) { 33948 33949 points.push( this.getPointAt( d / divisions ) ); 33950 33951 } 33952 33953 return points; 33954 33955 }, 33956 33957 // Get total curve arc length 33958 33959 getLength: function () { 33960 33961 var lengths = this.getLengths(); 33962 return lengths[ lengths.length - 1 ]; 33963 33964 }, 33965 33966 // Get list of cumulative segment lengths 33967 33968 getLengths: function ( divisions ) { 33969 33970 if ( isNaN( divisions ) ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200; 33971 33972 if ( this.cacheArcLengths 33973 && ( this.cacheArcLengths.length === divisions + 1 ) 33974 && ! this.needsUpdate ) { 33975 33976 //console.log( "cached", this.cacheArcLengths ); 33977 return this.cacheArcLengths; 33978 33979 } 33980 33981 this.needsUpdate = false; 33982 33983 var cache = []; 33984 var current, last = this.getPoint( 0 ); 33985 var p, sum = 0; 33986 33987 cache.push( 0 ); 33988 33989 for ( p = 1; p <= divisions; p ++ ) { 33990 33991 current = this.getPoint ( p / divisions ); 33992 sum += current.distanceTo( last ); 33993 cache.push( sum ); 33994 last = current; 33995 33996 } 33997 33998 this.cacheArcLengths = cache; 33999 34000 return cache; // { sums: cache, sum:sum }; Sum is in the last element. 34001 34002 }, 34003 34004 updateArcLengths: function() { 34005 34006 this.needsUpdate = true; 34007 this.getLengths(); 34008 34009 }, 34010 34011 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant 34012 34013 getUtoTmapping: function ( u, distance ) { 34014 34015 var arcLengths = this.getLengths(); 34016 34017 var i = 0, il = arcLengths.length; 34018 34019 var targetArcLength; // The targeted u distance value to get 34020 34021 if ( distance ) { 34022 34023 targetArcLength = distance; 34024 34025 } else { 34026 34027 targetArcLength = u * arcLengths[ il - 1 ]; 34028 34029 } 34030 34031 //var time = Date.now(); 34032 34033 // binary search for the index with largest value smaller than target u distance 34034 34035 var low = 0, high = il - 1, comparison; 34036 34037 while ( low <= high ) { 34038 34039 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 34040 34041 comparison = arcLengths[ i ] - targetArcLength; 34042 34043 if ( comparison < 0 ) { 34044 34045 low = i + 1; 34046 34047 } else if ( comparison > 0 ) { 34048 34049 high = i - 1; 34050 34051 } else { 34052 34053 high = i; 34054 break; 34055 34056 // DONE 34057 34058 } 34059 34060 } 34061 34062 i = high; 34063 34064 //console.log('b' , i, low, high, Date.now()- time); 34065 34066 if ( arcLengths[ i ] === targetArcLength ) { 34067 34068 var t = i / ( il - 1 ); 34069 return t; 34070 34071 } 34072 34073 // we could get finer grain at lengths, or use simple interpolation between two points 34074 34075 var lengthBefore = arcLengths[ i ]; 34076 var lengthAfter = arcLengths[ i + 1 ]; 34077 34078 var segmentLength = lengthAfter - lengthBefore; 34079 34080 // determine where we are between the 'before' and 'after' points 34081 34082 var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; 34083 34084 // add that fractional amount to t 34085 34086 var t = ( i + segmentFraction ) / ( il - 1 ); 34087 34088 return t; 34089 34090 }, 34091 34092 // Returns a unit vector tangent at t 34093 // In case any sub curve does not implement its tangent derivation, 34094 // 2 points a small delta apart will be used to find its gradient 34095 // which seems to give a reasonable approximation 34096 34097 getTangent: function( t ) { 34098 34099 var delta = 0.0001; 34100 var t1 = t - delta; 34101 var t2 = t + delta; 34102 34103 // Capping in case of danger 34104 34105 if ( t1 < 0 ) t1 = 0; 34106 if ( t2 > 1 ) t2 = 1; 34107 34108 var pt1 = this.getPoint( t1 ); 34109 var pt2 = this.getPoint( t2 ); 34110 34111 var vec = pt2.clone().sub( pt1 ); 34112 return vec.normalize(); 34113 34114 }, 34115 34116 getTangentAt: function ( u ) { 34117 34118 var t = this.getUtoTmapping( u ); 34119 return this.getTangent( t ); 34120 34121 }, 34122 34123 computeFrenetFrames: function ( segments, closed ) { 34124 34125 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf 34126 34127 var normal = new Vector3(); 34128 34129 var tangents = []; 34130 var normals = []; 34131 var binormals = []; 34132 34133 var vec = new Vector3(); 34134 var mat = new Matrix4(); 34135 34136 var i, u, theta; 34137 34138 // compute the tangent vectors for each segment on the curve 34139 34140 for ( i = 0; i <= segments; i ++ ) { 34141 34142 u = i / segments; 34143 34144 tangents[ i ] = this.getTangentAt( u ); 34145 tangents[ i ].normalize(); 34146 34147 } 34148 34149 // select an initial normal vector perpendicular to the first tangent vector, 34150 // and in the direction of the minimum tangent xyz component 34151 34152 normals[ 0 ] = new Vector3(); 34153 binormals[ 0 ] = new Vector3(); 34154 var min = Number.MAX_VALUE; 34155 var tx = Math.abs( tangents[ 0 ].x ); 34156 var ty = Math.abs( tangents[ 0 ].y ); 34157 var tz = Math.abs( tangents[ 0 ].z ); 34158 34159 if ( tx <= min ) { 34160 34161 min = tx; 34162 normal.set( 1, 0, 0 ); 34163 34164 } 34165 34166 if ( ty <= min ) { 34167 34168 min = ty; 34169 normal.set( 0, 1, 0 ); 34170 34171 } 34172 34173 if ( tz <= min ) { 34174 34175 normal.set( 0, 0, 1 ); 34176 34177 } 34178 34179 vec.crossVectors( tangents[ 0 ], normal ).normalize(); 34180 34181 normals[ 0 ].crossVectors( tangents[ 0 ], vec ); 34182 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); 34183 34184 34185 // compute the slowly-varying normal and binormal vectors for each segment on the curve 34186 34187 for ( i = 1; i <= segments; i ++ ) { 34188 34189 normals[ i ] = normals[ i - 1 ].clone(); 34190 34191 binormals[ i ] = binormals[ i - 1 ].clone(); 34192 34193 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); 34194 34195 if ( vec.length() > Number.EPSILON ) { 34196 34197 vec.normalize(); 34198 34199 theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors 34200 34201 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); 34202 34203 } 34204 34205 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 34206 34207 } 34208 34209 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same 34210 34211 if ( closed === true ) { 34212 34213 theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); 34214 theta /= segments; 34215 34216 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { 34217 34218 theta = - theta; 34219 34220 } 34221 34222 for ( i = 1; i <= segments; i ++ ) { 34223 34224 // twist a little... 34225 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); 34226 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 34227 34228 } 34229 34230 } 34231 34232 return { 34233 tangents: tangents, 34234 normals: normals, 34235 binormals: binormals 34236 }; 34237 34238 } 34239 34240 }; 34241 34242 function LineCurve( v1, v2 ) { 34243 34244 this.v1 = v1; 34245 this.v2 = v2; 34246 34247 } 34248 34249 LineCurve.prototype = Object.create( Curve.prototype ); 34250 LineCurve.prototype.constructor = LineCurve; 34251 34252 LineCurve.prototype.isLineCurve = true; 34253 34254 LineCurve.prototype.getPoint = function ( t ) { 34255 34256 if ( t === 1 ) { 34257 34258 return this.v2.clone(); 34259 34260 } 34261 34262 var point = this.v2.clone().sub( this.v1 ); 34263 point.multiplyScalar( t ).add( this.v1 ); 34264 34265 return point; 34266 34267 }; 34268 34269 // Line curve is linear, so we can overwrite default getPointAt 34270 34271 LineCurve.prototype.getPointAt = function ( u ) { 34272 34273 return this.getPoint( u ); 34274 34275 }; 34276 34277 LineCurve.prototype.getTangent = function ( t ) { 34278 34279 var tangent = this.v2.clone().sub( this.v1 ); 34280 34281 return tangent.normalize(); 34282 34283 }; 34284 34285 /** 34286 * @author zz85 / http://www.lab4games.net/zz85/blog 34287 * 34288 **/ 34289 34290 /************************************************************** 34291 * Curved Path - a curve path is simply a array of connected 34292 * curves, but retains the api of a curve 34293 **************************************************************/ 34294 34295 function CurvePath() { 34296 34297 this.curves = []; 34298 34299 this.autoClose = false; // Automatically closes the path 34300 34301 } 34302 34303 CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { 34304 34305 constructor: CurvePath, 34306 34307 add: function ( curve ) { 34308 34309 this.curves.push( curve ); 34310 34311 }, 34312 34313 closePath: function () { 34314 34315 // Add a line curve if start and end of lines are not connected 34316 var startPoint = this.curves[ 0 ].getPoint( 0 ); 34317 var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); 34318 34319 if ( ! startPoint.equals( endPoint ) ) { 34320 34321 this.curves.push( new LineCurve( endPoint, startPoint ) ); 34322 34323 } 34324 34325 }, 34326 34327 // To get accurate point with reference to 34328 // entire path distance at time t, 34329 // following has to be done: 34330 34331 // 1. Length of each sub path have to be known 34332 // 2. Locate and identify type of curve 34333 // 3. Get t for the curve 34334 // 4. Return curve.getPointAt(t') 34335 34336 getPoint: function ( t ) { 34337 34338 var d = t * this.getLength(); 34339 var curveLengths = this.getCurveLengths(); 34340 var i = 0; 34341 34342 // To think about boundaries points. 34343 34344 while ( i < curveLengths.length ) { 34345 34346 if ( curveLengths[ i ] >= d ) { 34347 34348 var diff = curveLengths[ i ] - d; 34349 var curve = this.curves[ i ]; 34350 34351 var segmentLength = curve.getLength(); 34352 var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; 34353 34354 return curve.getPointAt( u ); 34355 34356 } 34357 34358 i ++; 34359 34360 } 34361 34362 return null; 34363 34364 // loop where sum != 0, sum > d , sum+1 <d 34365 34366 }, 34367 34368 // We cannot use the default THREE.Curve getPoint() with getLength() because in 34369 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath 34370 // getPoint() depends on getLength 34371 34372 getLength: function () { 34373 34374 var lens = this.getCurveLengths(); 34375 return lens[ lens.length - 1 ]; 34376 34377 }, 34378 34379 // cacheLengths must be recalculated. 34380 updateArcLengths: function () { 34381 34382 this.needsUpdate = true; 34383 this.cacheLengths = null; 34384 this.getLengths(); 34385 34386 }, 34387 34388 // Compute lengths and cache them 34389 // We cannot overwrite getLengths() because UtoT mapping uses it. 34390 34391 getCurveLengths: function () { 34392 34393 // We use cache values if curves and cache array are same length 34394 34395 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) { 34396 34397 return this.cacheLengths; 34398 34399 } 34400 34401 // Get length of sub-curve 34402 // Push sums into cached array 34403 34404 var lengths = [], sums = 0; 34405 34406 for ( var i = 0, l = this.curves.length; i < l; i ++ ) { 34407 34408 sums += this.curves[ i ].getLength(); 34409 lengths.push( sums ); 34410 34411 } 34412 34413 this.cacheLengths = lengths; 34414 34415 return lengths; 34416 34417 }, 34418 34419 getSpacedPoints: function ( divisions ) { 34420 34421 if ( isNaN( divisions ) ) divisions = 40; 34422 34423 var points = []; 34424 34425 for ( var i = 0; i <= divisions; i ++ ) { 34426 34427 points.push( this.getPoint( i / divisions ) ); 34428 34429 } 34430 34431 if ( this.autoClose ) { 34432 34433 points.push( points[ 0 ] ); 34434 34435 } 34436 34437 return points; 34438 34439 }, 34440 34441 getPoints: function ( divisions ) { 34442 34443 divisions = divisions || 12; 34444 34445 var points = [], last; 34446 34447 for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { 34448 34449 var curve = curves[ i ]; 34450 var resolution = (curve && curve.isEllipseCurve) ? divisions * 2 34451 : (curve && curve.isLineCurve) ? 1 34452 : (curve && curve.isSplineCurve) ? divisions * curve.points.length 34453 : divisions; 34454 34455 var pts = curve.getPoints( resolution ); 34456 34457 for ( var j = 0; j < pts.length; j++ ) { 34458 34459 var point = pts[ j ]; 34460 34461 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates 34462 34463 points.push( point ); 34464 last = point; 34465 34466 } 34467 34468 } 34469 34470 if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) { 34471 34472 points.push( points[ 0 ] ); 34473 34474 } 34475 34476 return points; 34477 34478 }, 34479 34480 /************************************************************** 34481 * Create Geometries Helpers 34482 **************************************************************/ 34483 34484 /// Generate geometry from path points (for Line or Points objects) 34485 34486 createPointsGeometry: function ( divisions ) { 34487 34488 var pts = this.getPoints( divisions ); 34489 return this.createGeometry( pts ); 34490 34491 }, 34492 34493 // Generate geometry from equidistant sampling along the path 34494 34495 createSpacedPointsGeometry: function ( divisions ) { 34496 34497 var pts = this.getSpacedPoints( divisions ); 34498 return this.createGeometry( pts ); 34499 34500 }, 34501 34502 createGeometry: function ( points ) { 34503 34504 var geometry = new Geometry(); 34505 34506 for ( var i = 0, l = points.length; i < l; i ++ ) { 34507 34508 var point = points[ i ]; 34509 geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); 34510 34511 } 34512 34513 return geometry; 34514 34515 } 34516 34517 } ); 34518 34519 function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 34520 34521 this.aX = aX; 34522 this.aY = aY; 34523 34524 this.xRadius = xRadius; 34525 this.yRadius = yRadius; 34526 34527 this.aStartAngle = aStartAngle; 34528 this.aEndAngle = aEndAngle; 34529 34530 this.aClockwise = aClockwise; 34531 34532 this.aRotation = aRotation || 0; 34533 34534 } 34535 34536 EllipseCurve.prototype = Object.create( Curve.prototype ); 34537 EllipseCurve.prototype.constructor = EllipseCurve; 34538 34539 EllipseCurve.prototype.isEllipseCurve = true; 34540 34541 EllipseCurve.prototype.getPoint = function ( t ) { 34542 34543 var twoPi = Math.PI * 2; 34544 var deltaAngle = this.aEndAngle - this.aStartAngle; 34545 var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; 34546 34547 // ensures that deltaAngle is 0 .. 2 PI 34548 while ( deltaAngle < 0 ) deltaAngle += twoPi; 34549 while ( deltaAngle > twoPi ) deltaAngle -= twoPi; 34550 34551 if ( deltaAngle < Number.EPSILON ) { 34552 34553 if ( samePoints ) { 34554 34555 deltaAngle = 0; 34556 34557 } else { 34558 34559 deltaAngle = twoPi; 34560 34561 } 34562 34563 } 34564 34565 if ( this.aClockwise === true && ! samePoints ) { 34566 34567 if ( deltaAngle === twoPi ) { 34568 34569 deltaAngle = - twoPi; 34570 34571 } else { 34572 34573 deltaAngle = deltaAngle - twoPi; 34574 34575 } 34576 34577 } 34578 34579 var angle = this.aStartAngle + t * deltaAngle; 34580 var x = this.aX + this.xRadius * Math.cos( angle ); 34581 var y = this.aY + this.yRadius * Math.sin( angle ); 34582 34583 if ( this.aRotation !== 0 ) { 34584 34585 var cos = Math.cos( this.aRotation ); 34586 var sin = Math.sin( this.aRotation ); 34587 34588 var tx = x - this.aX; 34589 var ty = y - this.aY; 34590 34591 // Rotate the point about the center of the ellipse. 34592 x = tx * cos - ty * sin + this.aX; 34593 y = tx * sin + ty * cos + this.aY; 34594 34595 } 34596 34597 return new Vector2( x, y ); 34598 34599 }; 34600 34601 function SplineCurve( points /* array of Vector2 */ ) { 34602 34603 this.points = ( points === undefined ) ? [] : points; 34604 34605 } 34606 34607 SplineCurve.prototype = Object.create( Curve.prototype ); 34608 SplineCurve.prototype.constructor = SplineCurve; 34609 34610 SplineCurve.prototype.isSplineCurve = true; 34611 34612 SplineCurve.prototype.getPoint = function ( t ) { 34613 34614 var points = this.points; 34615 var point = ( points.length - 1 ) * t; 34616 34617 var intPoint = Math.floor( point ); 34618 var weight = point - intPoint; 34619 34620 var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; 34621 var point1 = points[ intPoint ]; 34622 var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; 34623 var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; 34624 34625 return new Vector2( 34626 CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ), 34627 CatmullRom( weight, point0.y, point1.y, point2.y, point3.y ) 34628 ); 34629 34630 }; 34631 34632 function CubicBezierCurve( v0, v1, v2, v3 ) { 34633 34634 this.v0 = v0; 34635 this.v1 = v1; 34636 this.v2 = v2; 34637 this.v3 = v3; 34638 34639 } 34640 34641 CubicBezierCurve.prototype = Object.create( Curve.prototype ); 34642 CubicBezierCurve.prototype.constructor = CubicBezierCurve; 34643 34644 CubicBezierCurve.prototype.getPoint = function ( t ) { 34645 34646 var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 34647 34648 return new Vector2( 34649 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 34650 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) 34651 ); 34652 34653 }; 34654 34655 function QuadraticBezierCurve( v0, v1, v2 ) { 34656 34657 this.v0 = v0; 34658 this.v1 = v1; 34659 this.v2 = v2; 34660 34661 } 34662 34663 QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); 34664 QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; 34665 34666 QuadraticBezierCurve.prototype.getPoint = function ( t ) { 34667 34668 var v0 = this.v0, v1 = this.v1, v2 = this.v2; 34669 34670 return new Vector2( 34671 QuadraticBezier( t, v0.x, v1.x, v2.x ), 34672 QuadraticBezier( t, v0.y, v1.y, v2.y ) 34673 ); 34674 34675 }; 34676 34677 var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), { 34678 34679 fromPoints: function ( vectors ) { 34680 34681 this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); 34682 34683 for ( var i = 1, l = vectors.length; i < l; i ++ ) { 34684 34685 this.lineTo( vectors[ i ].x, vectors[ i ].y ); 34686 34687 } 34688 34689 }, 34690 34691 moveTo: function ( x, y ) { 34692 34693 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? 34694 34695 }, 34696 34697 lineTo: function ( x, y ) { 34698 34699 var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); 34700 this.curves.push( curve ); 34701 34702 this.currentPoint.set( x, y ); 34703 34704 }, 34705 34706 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { 34707 34708 var curve = new QuadraticBezierCurve( 34709 this.currentPoint.clone(), 34710 new Vector2( aCPx, aCPy ), 34711 new Vector2( aX, aY ) 34712 ); 34713 34714 this.curves.push( curve ); 34715 34716 this.currentPoint.set( aX, aY ); 34717 34718 }, 34719 34720 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 34721 34722 var curve = new CubicBezierCurve( 34723 this.currentPoint.clone(), 34724 new Vector2( aCP1x, aCP1y ), 34725 new Vector2( aCP2x, aCP2y ), 34726 new Vector2( aX, aY ) 34727 ); 34728 34729 this.curves.push( curve ); 34730 34731 this.currentPoint.set( aX, aY ); 34732 34733 }, 34734 34735 splineThru: function ( pts /*Array of Vector*/ ) { 34736 34737 var npts = [ this.currentPoint.clone() ].concat( pts ); 34738 34739 var curve = new SplineCurve( npts ); 34740 this.curves.push( curve ); 34741 34742 this.currentPoint.copy( pts[ pts.length - 1 ] ); 34743 34744 }, 34745 34746 arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 34747 34748 var x0 = this.currentPoint.x; 34749 var y0 = this.currentPoint.y; 34750 34751 this.absarc( aX + x0, aY + y0, aRadius, 34752 aStartAngle, aEndAngle, aClockwise ); 34753 34754 }, 34755 34756 absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 34757 34758 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 34759 34760 }, 34761 34762 ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 34763 34764 var x0 = this.currentPoint.x; 34765 var y0 = this.currentPoint.y; 34766 34767 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 34768 34769 }, 34770 34771 absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 34772 34773 var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 34774 34775 if ( this.curves.length > 0 ) { 34776 34777 // if a previous curve is present, attempt to join 34778 var firstPoint = curve.getPoint( 0 ); 34779 34780 if ( ! firstPoint.equals( this.currentPoint ) ) { 34781 34782 this.lineTo( firstPoint.x, firstPoint.y ); 34783 34784 } 34785 34786 } 34787 34788 this.curves.push( curve ); 34789 34790 var lastPoint = curve.getPoint( 1 ); 34791 this.currentPoint.copy( lastPoint ); 34792 34793 } 34794 34795 } ); 34796 34797 /** 34798 * @author zz85 / http://www.lab4games.net/zz85/blog 34799 * Creates free form 2d path using series of points, lines or curves. 34800 **/ 34801 34802 function Path( points ) { 34803 34804 CurvePath.call( this ); 34805 this.currentPoint = new Vector2(); 34806 34807 if ( points ) { 34808 34809 this.fromPoints( points ); 34810 34811 } 34812 34813 } 34814 34815 Path.prototype = PathPrototype; 34816 PathPrototype.constructor = Path; 34817 34818 /** 34819 * @author zz85 / http://www.lab4games.net/zz85/blog 34820 * Defines a 2d shape plane using paths. 34821 **/ 34822 34823 // STEP 1 Create a path. 34824 // STEP 2 Turn path into shape. 34825 // STEP 3 ExtrudeGeometry takes in Shape/Shapes 34826 // STEP 3a - Extract points from each shape, turn to vertices 34827 // STEP 3b - Triangulate each shape, add faces. 34828 34829 function Shape() { 34830 34831 Path.apply( this, arguments ); 34832 34833 this.holes = []; 34834 34835 } 34836 34837 Shape.prototype = Object.assign( Object.create( PathPrototype ), { 34838 34839 constructor: Shape, 34840 34841 getPointsHoles: function ( divisions ) { 34842 34843 var holesPts = []; 34844 34845 for ( var i = 0, l = this.holes.length; i < l; i ++ ) { 34846 34847 holesPts[ i ] = this.holes[ i ].getPoints( divisions ); 34848 34849 } 34850 34851 return holesPts; 34852 34853 }, 34854 34855 // Get points of shape and holes (keypoints based on segments parameter) 34856 34857 extractAllPoints: function ( divisions ) { 34858 34859 return { 34860 34861 shape: this.getPoints( divisions ), 34862 holes: this.getPointsHoles( divisions ) 34863 34864 }; 34865 34866 }, 34867 34868 extractPoints: function ( divisions ) { 34869 34870 return this.extractAllPoints( divisions ); 34871 34872 } 34873 34874 } ); 34875 34876 /** 34877 * @author zz85 / http://www.lab4games.net/zz85/blog 34878 * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" 34879 **/ 34880 34881 function ShapePath() { 34882 34883 this.subPaths = []; 34884 this.currentPath = null; 34885 34886 } 34887 34888 ShapePath.prototype = { 34889 34890 moveTo: function ( x, y ) { 34891 34892 this.currentPath = new Path(); 34893 this.subPaths.push( this.currentPath ); 34894 this.currentPath.moveTo( x, y ); 34895 34896 }, 34897 34898 lineTo: function ( x, y ) { 34899 34900 this.currentPath.lineTo( x, y ); 34901 34902 }, 34903 34904 quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { 34905 34906 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); 34907 34908 }, 34909 34910 bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 34911 34912 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); 34913 34914 }, 34915 34916 splineThru: function ( pts ) { 34917 34918 this.currentPath.splineThru( pts ); 34919 34920 }, 34921 34922 toShapes: function ( isCCW, noHoles ) { 34923 34924 function toShapesNoHoles( inSubpaths ) { 34925 34926 var shapes = []; 34927 34928 for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { 34929 34930 var tmpPath = inSubpaths[ i ]; 34931 34932 var tmpShape = new Shape(); 34933 tmpShape.curves = tmpPath.curves; 34934 34935 shapes.push( tmpShape ); 34936 34937 } 34938 34939 return shapes; 34940 34941 } 34942 34943 function isPointInsidePolygon( inPt, inPolygon ) { 34944 34945 var polyLen = inPolygon.length; 34946 34947 // inPt on polygon contour => immediate success or 34948 // toggling of inside/outside at every single! intersection point of an edge 34949 // with the horizontal line through inPt, left of inPt 34950 // not counting lowerY endpoints of edges and whole edges on that line 34951 var inside = false; 34952 for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { 34953 34954 var edgeLowPt = inPolygon[ p ]; 34955 var edgeHighPt = inPolygon[ q ]; 34956 34957 var edgeDx = edgeHighPt.x - edgeLowPt.x; 34958 var edgeDy = edgeHighPt.y - edgeLowPt.y; 34959 34960 if ( Math.abs( edgeDy ) > Number.EPSILON ) { 34961 34962 // not parallel 34963 if ( edgeDy < 0 ) { 34964 34965 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; 34966 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; 34967 34968 } 34969 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; 34970 34971 if ( inPt.y === edgeLowPt.y ) { 34972 34973 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? 34974 // continue; // no intersection or edgeLowPt => doesn't count !!! 34975 34976 } else { 34977 34978 var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); 34979 if ( perpEdge === 0 ) return true; // inPt is on contour ? 34980 if ( perpEdge < 0 ) continue; 34981 inside = ! inside; // true intersection left of inPt 34982 34983 } 34984 34985 } else { 34986 34987 // parallel or collinear 34988 if ( inPt.y !== edgeLowPt.y ) continue; // parallel 34989 // edge lies on the same horizontal line as inPt 34990 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || 34991 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! 34992 // continue; 34993 34994 } 34995 34996 } 34997 34998 return inside; 34999 35000 } 35001 35002 var isClockWise = ShapeUtils.isClockWise; 35003 35004 var subPaths = this.subPaths; 35005 if ( subPaths.length === 0 ) return []; 35006 35007 if ( noHoles === true ) return toShapesNoHoles( subPaths ); 35008 35009 35010 var solid, tmpPath, tmpShape, shapes = []; 35011 35012 if ( subPaths.length === 1 ) { 35013 35014 tmpPath = subPaths[ 0 ]; 35015 tmpShape = new Shape(); 35016 tmpShape.curves = tmpPath.curves; 35017 shapes.push( tmpShape ); 35018 return shapes; 35019 35020 } 35021 35022 var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); 35023 holesFirst = isCCW ? ! holesFirst : holesFirst; 35024 35025 // console.log("Holes first", holesFirst); 35026 35027 var betterShapeHoles = []; 35028 var newShapes = []; 35029 var newShapeHoles = []; 35030 var mainIdx = 0; 35031 var tmpPoints; 35032 35033 newShapes[ mainIdx ] = undefined; 35034 newShapeHoles[ mainIdx ] = []; 35035 35036 for ( var i = 0, l = subPaths.length; i < l; i ++ ) { 35037 35038 tmpPath = subPaths[ i ]; 35039 tmpPoints = tmpPath.getPoints(); 35040 solid = isClockWise( tmpPoints ); 35041 solid = isCCW ? ! solid : solid; 35042 35043 if ( solid ) { 35044 35045 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; 35046 35047 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; 35048 newShapes[ mainIdx ].s.curves = tmpPath.curves; 35049 35050 if ( holesFirst ) mainIdx ++; 35051 newShapeHoles[ mainIdx ] = []; 35052 35053 //console.log('cw', i); 35054 35055 } else { 35056 35057 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); 35058 35059 //console.log('ccw', i); 35060 35061 } 35062 35063 } 35064 35065 // only Holes? -> probably all Shapes with wrong orientation 35066 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); 35067 35068 35069 if ( newShapes.length > 1 ) { 35070 35071 var ambiguous = false; 35072 var toChange = []; 35073 35074 for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 35075 35076 betterShapeHoles[ sIdx ] = []; 35077 35078 } 35079 35080 for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 35081 35082 var sho = newShapeHoles[ sIdx ]; 35083 35084 for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { 35085 35086 var ho = sho[ hIdx ]; 35087 var hole_unassigned = true; 35088 35089 for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { 35090 35091 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { 35092 35093 if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); 35094 if ( hole_unassigned ) { 35095 35096 hole_unassigned = false; 35097 betterShapeHoles[ s2Idx ].push( ho ); 35098 35099 } else { 35100 35101 ambiguous = true; 35102 35103 } 35104 35105 } 35106 35107 } 35108 if ( hole_unassigned ) { 35109 35110 betterShapeHoles[ sIdx ].push( ho ); 35111 35112 } 35113 35114 } 35115 35116 } 35117 // console.log("ambiguous: ", ambiguous); 35118 if ( toChange.length > 0 ) { 35119 35120 // console.log("to change: ", toChange); 35121 if ( ! ambiguous ) newShapeHoles = betterShapeHoles; 35122 35123 } 35124 35125 } 35126 35127 var tmpHoles; 35128 35129 for ( var i = 0, il = newShapes.length; i < il; i ++ ) { 35130 35131 tmpShape = newShapes[ i ].s; 35132 shapes.push( tmpShape ); 35133 tmpHoles = newShapeHoles[ i ]; 35134 35135 for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { 35136 35137 tmpShape.holes.push( tmpHoles[ j ].h ); 35138 35139 } 35140 35141 } 35142 35143 //console.log("shape", shapes); 35144 35145 return shapes; 35146 35147 } 35148 35149 }; 35150 35151 /** 35152 * @author zz85 / http://www.lab4games.net/zz85/blog 35153 * @author mrdoob / http://mrdoob.com/ 35154 */ 35155 35156 function Font( data ) { 35157 35158 this.data = data; 35159 35160 } 35161 35162 Object.assign( Font.prototype, { 35163 35164 isFont: true, 35165 35166 generateShapes: function ( text, size, divisions ) { 35167 35168 function createPaths( text ) { 35169 35170 var chars = String( text ).split( '' ); 35171 var scale = size / data.resolution; 35172 var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; 35173 35174 var offsetX = 0, offsetY = 0; 35175 35176 var paths = []; 35177 35178 for ( var i = 0; i < chars.length; i ++ ) { 35179 35180 var char = chars[ i ]; 35181 35182 if ( char === '\n' ) { 35183 35184 offsetX = 0; 35185 offsetY -= line_height; 35186 35187 } else { 35188 35189 var ret = createPath( char, scale, offsetX, offsetY ); 35190 offsetX += ret.offsetX; 35191 paths.push( ret.path ); 35192 35193 } 35194 35195 } 35196 35197 return paths; 35198 35199 } 35200 35201 function createPath( c, scale, offsetX, offsetY ) { 35202 35203 var glyph = data.glyphs[ c ] || data.glyphs[ '?' ]; 35204 35205 if ( ! glyph ) return; 35206 35207 var path = new ShapePath(); 35208 35209 var pts = []; 35210 var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste; 35211 35212 if ( glyph.o ) { 35213 35214 var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); 35215 35216 for ( var i = 0, l = outline.length; i < l; ) { 35217 35218 var action = outline[ i ++ ]; 35219 35220 switch ( action ) { 35221 35222 case 'm': // moveTo 35223 35224 x = outline[ i ++ ] * scale + offsetX; 35225 y = outline[ i ++ ] * scale + offsetY; 35226 35227 path.moveTo( x, y ); 35228 35229 break; 35230 35231 case 'l': // lineTo 35232 35233 x = outline[ i ++ ] * scale + offsetX; 35234 y = outline[ i ++ ] * scale + offsetY; 35235 35236 path.lineTo( x, y ); 35237 35238 break; 35239 35240 case 'q': // quadraticCurveTo 35241 35242 cpx = outline[ i ++ ] * scale + offsetX; 35243 cpy = outline[ i ++ ] * scale + offsetY; 35244 cpx1 = outline[ i ++ ] * scale + offsetX; 35245 cpy1 = outline[ i ++ ] * scale + offsetY; 35246 35247 path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); 35248 35249 laste = pts[ pts.length - 1 ]; 35250 35251 if ( laste ) { 35252 35253 cpx0 = laste.x; 35254 cpy0 = laste.y; 35255 35256 for ( var i2 = 1; i2 <= divisions; i2 ++ ) { 35257 35258 var t = i2 / divisions; 35259 QuadraticBezier( t, cpx0, cpx1, cpx ); 35260 QuadraticBezier( t, cpy0, cpy1, cpy ); 35261 35262 } 35263 35264 } 35265 35266 break; 35267 35268 case 'b': // bezierCurveTo 35269 35270 cpx = outline[ i ++ ] * scale + offsetX; 35271 cpy = outline[ i ++ ] * scale + offsetY; 35272 cpx1 = outline[ i ++ ] * scale + offsetX; 35273 cpy1 = outline[ i ++ ] * scale + offsetY; 35274 cpx2 = outline[ i ++ ] * scale + offsetX; 35275 cpy2 = outline[ i ++ ] * scale + offsetY; 35276 35277 path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); 35278 35279 laste = pts[ pts.length - 1 ]; 35280 35281 if ( laste ) { 35282 35283 cpx0 = laste.x; 35284 cpy0 = laste.y; 35285 35286 for ( var i2 = 1; i2 <= divisions; i2 ++ ) { 35287 35288 var t = i2 / divisions; 35289 CubicBezier( t, cpx0, cpx1, cpx2, cpx ); 35290 CubicBezier( t, cpy0, cpy1, cpy2, cpy ); 35291 35292 } 35293 35294 } 35295 35296 break; 35297 35298 } 35299 35300 } 35301 35302 } 35303 35304 return { offsetX: glyph.ha * scale, path: path }; 35305 35306 } 35307 35308 // 35309 35310 if ( size === undefined ) size = 100; 35311 if ( divisions === undefined ) divisions = 4; 35312 35313 var data = this.data; 35314 35315 var paths = createPaths( text ); 35316 var shapes = []; 35317 35318 for ( var p = 0, pl = paths.length; p < pl; p ++ ) { 35319 35320 Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); 35321 35322 } 35323 35324 return shapes; 35325 35326 } 35327 35328 } ); 35329 35330 /** 35331 * @author mrdoob / http://mrdoob.com/ 35332 */ 35333 35334 function FontLoader( manager ) { 35335 35336 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 35337 35338 } 35339 35340 Object.assign( FontLoader.prototype, { 35341 35342 load: function ( url, onLoad, onProgress, onError ) { 35343 35344 var scope = this; 35345 35346 var loader = new FileLoader( this.manager ); 35347 loader.load( url, function ( text ) { 35348 35349 var json; 35350 35351 try { 35352 35353 json = JSON.parse( text ); 35354 35355 } catch ( e ) { 35356 35357 console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); 35358 json = JSON.parse( text.substring( 65, text.length - 2 ) ); 35359 35360 } 35361 35362 var font = scope.parse( json ); 35363 35364 if ( onLoad ) onLoad( font ); 35365 35366 }, onProgress, onError ); 35367 35368 }, 35369 35370 parse: function ( json ) { 35371 35372 return new Font( json ); 35373 35374 } 35375 35376 } ); 35377 35378 var context; 35379 35380 var AudioContext = { 35381 35382 getContext: function () { 35383 35384 if ( context === undefined ) { 35385 35386 context = new ( window.AudioContext || window.webkitAudioContext )(); 35387 35388 } 35389 35390 return context; 35391 35392 }, 35393 35394 setContext: function ( value ) { 35395 35396 context = value; 35397 35398 } 35399 35400 }; 35401 35402 /** 35403 * @author Reece Aaron Lecrivain / http://reecenotes.com/ 35404 */ 35405 35406 function AudioLoader( manager ) { 35407 35408 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 35409 35410 } 35411 35412 Object.assign( AudioLoader.prototype, { 35413 35414 load: function ( url, onLoad, onProgress, onError ) { 35415 35416 var loader = new FileLoader( this.manager ); 35417 loader.setResponseType( 'arraybuffer' ); 35418 loader.load( url, function ( buffer ) { 35419 35420 var context = AudioContext.getContext(); 35421 35422 context.decodeAudioData( buffer, function ( audioBuffer ) { 35423 35424 onLoad( audioBuffer ); 35425 35426 } ); 35427 35428 }, onProgress, onError ); 35429 35430 } 35431 35432 } ); 35433 35434 /** 35435 * @author abelnation / http://github.com/abelnation 35436 */ 35437 35438 function RectAreaLight ( color, intensity, width, height ) { 35439 35440 Light.call( this, color, intensity ); 35441 35442 this.type = 'RectAreaLight'; 35443 35444 this.position.set( 0, 1, 0 ); 35445 this.updateMatrix(); 35446 35447 this.width = ( width !== undefined ) ? width : 10; 35448 this.height = ( height !== undefined ) ? height : 10; 35449 35450 // TODO (abelnation): distance/decay 35451 35452 // TODO (abelnation): update method for RectAreaLight to update transform to lookat target 35453 35454 // TODO (abelnation): shadows 35455 // this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) ); 35456 35457 } 35458 35459 // TODO (abelnation): RectAreaLight update when light shape is changed 35460 RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { 35461 35462 constructor: RectAreaLight, 35463 35464 isRectAreaLight: true, 35465 35466 copy: function ( source ) { 35467 35468 Light.prototype.copy.call( this, source ); 35469 35470 this.width = source.width; 35471 this.height = source.height; 35472 35473 // this.shadow = source.shadow.clone(); 35474 35475 return this; 35476 35477 } 35478 35479 } ); 35480 35481 /** 35482 * @author mrdoob / http://mrdoob.com/ 35483 */ 35484 35485 function StereoCamera() { 35486 35487 this.type = 'StereoCamera'; 35488 35489 this.aspect = 1; 35490 35491 this.eyeSep = 0.064; 35492 35493 this.cameraL = new PerspectiveCamera(); 35494 this.cameraL.layers.enable( 1 ); 35495 this.cameraL.matrixAutoUpdate = false; 35496 35497 this.cameraR = new PerspectiveCamera(); 35498 this.cameraR.layers.enable( 2 ); 35499 this.cameraR.matrixAutoUpdate = false; 35500 35501 } 35502 35503 Object.assign( StereoCamera.prototype, { 35504 35505 update: ( function () { 35506 35507 var instance, focus, fov, aspect, near, far, zoom; 35508 35509 var eyeRight = new Matrix4(); 35510 var eyeLeft = new Matrix4(); 35511 35512 return function update( camera ) { 35513 35514 var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov || 35515 aspect !== camera.aspect * this.aspect || near !== camera.near || 35516 far !== camera.far || zoom !== camera.zoom; 35517 35518 if ( needsUpdate ) { 35519 35520 instance = this; 35521 focus = camera.focus; 35522 fov = camera.fov; 35523 aspect = camera.aspect * this.aspect; 35524 near = camera.near; 35525 far = camera.far; 35526 zoom = camera.zoom; 35527 35528 // Off-axis stereoscopic effect based on 35529 // http://paulbourke.net/stereographics/stereorender/ 35530 35531 var projectionMatrix = camera.projectionMatrix.clone(); 35532 var eyeSep = this.eyeSep / 2; 35533 var eyeSepOnProjection = eyeSep * near / focus; 35534 var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom; 35535 var xmin, xmax; 35536 35537 // translate xOffset 35538 35539 eyeLeft.elements[ 12 ] = - eyeSep; 35540 eyeRight.elements[ 12 ] = eyeSep; 35541 35542 // for left eye 35543 35544 xmin = - ymax * aspect + eyeSepOnProjection; 35545 xmax = ymax * aspect + eyeSepOnProjection; 35546 35547 projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); 35548 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 35549 35550 this.cameraL.projectionMatrix.copy( projectionMatrix ); 35551 35552 // for right eye 35553 35554 xmin = - ymax * aspect - eyeSepOnProjection; 35555 xmax = ymax * aspect - eyeSepOnProjection; 35556 35557 projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); 35558 projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 35559 35560 this.cameraR.projectionMatrix.copy( projectionMatrix ); 35561 35562 } 35563 35564 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); 35565 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); 35566 35567 }; 35568 35569 } )() 35570 35571 } ); 35572 35573 /** 35574 * Camera for rendering cube maps 35575 * - renders scene into axis-aligned cube 35576 * 35577 * @author alteredq / http://alteredqualia.com/ 35578 */ 35579 35580 function CubeCamera( near, far, cubeResolution ) { 35581 35582 Object3D.call( this ); 35583 35584 this.type = 'CubeCamera'; 35585 35586 var fov = 90, aspect = 1; 35587 35588 var cameraPX = new PerspectiveCamera( fov, aspect, near, far ); 35589 cameraPX.up.set( 0, - 1, 0 ); 35590 cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); 35591 this.add( cameraPX ); 35592 35593 var cameraNX = new PerspectiveCamera( fov, aspect, near, far ); 35594 cameraNX.up.set( 0, - 1, 0 ); 35595 cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); 35596 this.add( cameraNX ); 35597 35598 var cameraPY = new PerspectiveCamera( fov, aspect, near, far ); 35599 cameraPY.up.set( 0, 0, 1 ); 35600 cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); 35601 this.add( cameraPY ); 35602 35603 var cameraNY = new PerspectiveCamera( fov, aspect, near, far ); 35604 cameraNY.up.set( 0, 0, - 1 ); 35605 cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); 35606 this.add( cameraNY ); 35607 35608 var cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); 35609 cameraPZ.up.set( 0, - 1, 0 ); 35610 cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); 35611 this.add( cameraPZ ); 35612 35613 var cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); 35614 cameraNZ.up.set( 0, - 1, 0 ); 35615 cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); 35616 this.add( cameraNZ ); 35617 35618 var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; 35619 35620 this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); 35621 35622 this.updateCubeMap = function ( renderer, scene ) { 35623 35624 if ( this.parent === null ) this.updateMatrixWorld(); 35625 35626 var renderTarget = this.renderTarget; 35627 var generateMipmaps = renderTarget.texture.generateMipmaps; 35628 35629 renderTarget.texture.generateMipmaps = false; 35630 35631 renderTarget.activeCubeFace = 0; 35632 renderer.render( scene, cameraPX, renderTarget ); 35633 35634 renderTarget.activeCubeFace = 1; 35635 renderer.render( scene, cameraNX, renderTarget ); 35636 35637 renderTarget.activeCubeFace = 2; 35638 renderer.render( scene, cameraPY, renderTarget ); 35639 35640 renderTarget.activeCubeFace = 3; 35641 renderer.render( scene, cameraNY, renderTarget ); 35642 35643 renderTarget.activeCubeFace = 4; 35644 renderer.render( scene, cameraPZ, renderTarget ); 35645 35646 renderTarget.texture.generateMipmaps = generateMipmaps; 35647 35648 renderTarget.activeCubeFace = 5; 35649 renderer.render( scene, cameraNZ, renderTarget ); 35650 35651 renderer.setRenderTarget( null ); 35652 35653 }; 35654 35655 } 35656 35657 CubeCamera.prototype = Object.create( Object3D.prototype ); 35658 CubeCamera.prototype.constructor = CubeCamera; 35659 35660 /** 35661 * @author mrdoob / http://mrdoob.com/ 35662 */ 35663 35664 function AudioListener() { 35665 35666 Object3D.call( this ); 35667 35668 this.type = 'AudioListener'; 35669 35670 this.context = AudioContext.getContext(); 35671 35672 this.gain = this.context.createGain(); 35673 this.gain.connect( this.context.destination ); 35674 35675 this.filter = null; 35676 35677 } 35678 35679 AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { 35680 35681 constructor: AudioListener, 35682 35683 getInput: function () { 35684 35685 return this.gain; 35686 35687 }, 35688 35689 removeFilter: function ( ) { 35690 35691 if ( this.filter !== null ) { 35692 35693 this.gain.disconnect( this.filter ); 35694 this.filter.disconnect( this.context.destination ); 35695 this.gain.connect( this.context.destination ); 35696 this.filter = null; 35697 35698 } 35699 35700 }, 35701 35702 getFilter: function () { 35703 35704 return this.filter; 35705 35706 }, 35707 35708 setFilter: function ( value ) { 35709 35710 if ( this.filter !== null ) { 35711 35712 this.gain.disconnect( this.filter ); 35713 this.filter.disconnect( this.context.destination ); 35714 35715 } else { 35716 35717 this.gain.disconnect( this.context.destination ); 35718 35719 } 35720 35721 this.filter = value; 35722 this.gain.connect( this.filter ); 35723 this.filter.connect( this.context.destination ); 35724 35725 }, 35726 35727 getMasterVolume: function () { 35728 35729 return this.gain.gain.value; 35730 35731 }, 35732 35733 setMasterVolume: function ( value ) { 35734 35735 this.gain.gain.value = value; 35736 35737 }, 35738 35739 updateMatrixWorld: ( function () { 35740 35741 var position = new Vector3(); 35742 var quaternion = new Quaternion(); 35743 var scale = new Vector3(); 35744 35745 var orientation = new Vector3(); 35746 35747 return function updateMatrixWorld( force ) { 35748 35749 Object3D.prototype.updateMatrixWorld.call( this, force ); 35750 35751 var listener = this.context.listener; 35752 var up = this.up; 35753 35754 this.matrixWorld.decompose( position, quaternion, scale ); 35755 35756 orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); 35757 35758 if ( listener.positionX ) { 35759 35760 listener.positionX.setValueAtTime( position.x, this.context.currentTime ); 35761 listener.positionY.setValueAtTime( position.y, this.context.currentTime ); 35762 listener.positionZ.setValueAtTime( position.z, this.context.currentTime ); 35763 listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime ); 35764 listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime ); 35765 listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime ); 35766 listener.upX.setValueAtTime( up.x, this.context.currentTime ); 35767 listener.upY.setValueAtTime( up.y, this.context.currentTime ); 35768 listener.upZ.setValueAtTime( up.z, this.context.currentTime ); 35769 35770 } else { 35771 35772 listener.setPosition( position.x, position.y, position.z ); 35773 listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); 35774 35775 } 35776 35777 }; 35778 35779 } )() 35780 35781 } ); 35782 35783 /** 35784 * @author mrdoob / http://mrdoob.com/ 35785 * @author Reece Aaron Lecrivain / http://reecenotes.com/ 35786 */ 35787 35788 function Audio( listener ) { 35789 35790 Object3D.call( this ); 35791 35792 this.type = 'Audio'; 35793 35794 this.context = listener.context; 35795 35796 this.gain = this.context.createGain(); 35797 this.gain.connect( listener.getInput() ); 35798 35799 this.autoplay = false; 35800 35801 this.buffer = null; 35802 this.loop = false; 35803 this.startTime = 0; 35804 this.playbackRate = 1; 35805 this.isPlaying = false; 35806 this.hasPlaybackControl = true; 35807 this.sourceType = 'empty'; 35808 35809 this.filters = []; 35810 35811 } 35812 35813 Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { 35814 35815 constructor: Audio, 35816 35817 getOutput: function () { 35818 35819 return this.gain; 35820 35821 }, 35822 35823 setNodeSource: function ( audioNode ) { 35824 35825 this.hasPlaybackControl = false; 35826 this.sourceType = 'audioNode'; 35827 this.source = audioNode; 35828 this.connect(); 35829 35830 return this; 35831 35832 }, 35833 35834 setBuffer: function ( audioBuffer ) { 35835 35836 this.buffer = audioBuffer; 35837 this.sourceType = 'buffer'; 35838 35839 if ( this.autoplay ) this.play(); 35840 35841 return this; 35842 35843 }, 35844 35845 play: function () { 35846 35847 if ( this.isPlaying === true ) { 35848 35849 console.warn( 'THREE.Audio: Audio is already playing.' ); 35850 return; 35851 35852 } 35853 35854 if ( this.hasPlaybackControl === false ) { 35855 35856 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 35857 return; 35858 35859 } 35860 35861 var source = this.context.createBufferSource(); 35862 35863 source.buffer = this.buffer; 35864 source.loop = this.loop; 35865 source.onended = this.onEnded.bind( this ); 35866 source.playbackRate.setValueAtTime( this.playbackRate, this.startTime ); 35867 source.start( 0, this.startTime ); 35868 35869 this.isPlaying = true; 35870 35871 this.source = source; 35872 35873 return this.connect(); 35874 35875 }, 35876 35877 pause: function () { 35878 35879 if ( this.hasPlaybackControl === false ) { 35880 35881 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 35882 return; 35883 35884 } 35885 35886 this.source.stop(); 35887 this.startTime = this.context.currentTime; 35888 this.isPlaying = false; 35889 35890 return this; 35891 35892 }, 35893 35894 stop: function () { 35895 35896 if ( this.hasPlaybackControl === false ) { 35897 35898 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 35899 return; 35900 35901 } 35902 35903 this.source.stop(); 35904 this.startTime = 0; 35905 this.isPlaying = false; 35906 35907 return this; 35908 35909 }, 35910 35911 connect: function () { 35912 35913 if ( this.filters.length > 0 ) { 35914 35915 this.source.connect( this.filters[ 0 ] ); 35916 35917 for ( var i = 1, l = this.filters.length; i < l; i ++ ) { 35918 35919 this.filters[ i - 1 ].connect( this.filters[ i ] ); 35920 35921 } 35922 35923 this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); 35924 35925 } else { 35926 35927 this.source.connect( this.getOutput() ); 35928 35929 } 35930 35931 return this; 35932 35933 }, 35934 35935 disconnect: function () { 35936 35937 if ( this.filters.length > 0 ) { 35938 35939 this.source.disconnect( this.filters[ 0 ] ); 35940 35941 for ( var i = 1, l = this.filters.length; i < l; i ++ ) { 35942 35943 this.filters[ i - 1 ].disconnect( this.filters[ i ] ); 35944 35945 } 35946 35947 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); 35948 35949 } else { 35950 35951 this.source.disconnect( this.getOutput() ); 35952 35953 } 35954 35955 return this; 35956 35957 }, 35958 35959 getFilters: function () { 35960 35961 return this.filters; 35962 35963 }, 35964 35965 setFilters: function ( value ) { 35966 35967 if ( ! value ) value = []; 35968 35969 if ( this.isPlaying === true ) { 35970 35971 this.disconnect(); 35972 this.filters = value; 35973 this.connect(); 35974 35975 } else { 35976 35977 this.filters = value; 35978 35979 } 35980 35981 return this; 35982 35983 }, 35984 35985 getFilter: function () { 35986 35987 return this.getFilters()[ 0 ]; 35988 35989 }, 35990 35991 setFilter: function ( filter ) { 35992 35993 return this.setFilters( filter ? [ filter ] : [] ); 35994 35995 }, 35996 35997 setPlaybackRate: function ( value ) { 35998 35999 if ( this.hasPlaybackControl === false ) { 36000 36001 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 36002 return; 36003 36004 } 36005 36006 this.playbackRate = value; 36007 36008 if ( this.isPlaying === true ) { 36009 36010 this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime ); 36011 36012 } 36013 36014 return this; 36015 36016 }, 36017 36018 getPlaybackRate: function () { 36019 36020 return this.playbackRate; 36021 36022 }, 36023 36024 onEnded: function () { 36025 36026 this.isPlaying = false; 36027 36028 }, 36029 36030 getLoop: function () { 36031 36032 if ( this.hasPlaybackControl === false ) { 36033 36034 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 36035 return false; 36036 36037 } 36038 36039 return this.loop; 36040 36041 }, 36042 36043 setLoop: function ( value ) { 36044 36045 if ( this.hasPlaybackControl === false ) { 36046 36047 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 36048 return; 36049 36050 } 36051 36052 this.loop = value; 36053 36054 if ( this.isPlaying === true ) { 36055 36056 this.source.loop = this.loop; 36057 36058 } 36059 36060 return this; 36061 36062 }, 36063 36064 getVolume: function () { 36065 36066 return this.gain.gain.value; 36067 36068 }, 36069 36070 36071 setVolume: function ( value ) { 36072 36073 this.gain.gain.value = value; 36074 36075 return this; 36076 36077 } 36078 36079 } ); 36080 36081 /** 36082 * @author mrdoob / http://mrdoob.com/ 36083 */ 36084 36085 function PositionalAudio( listener ) { 36086 36087 Audio.call( this, listener ); 36088 36089 this.panner = this.context.createPanner(); 36090 this.panner.connect( this.gain ); 36091 36092 } 36093 36094 PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { 36095 36096 constructor: PositionalAudio, 36097 36098 getOutput: function () { 36099 36100 return this.panner; 36101 36102 }, 36103 36104 getRefDistance: function () { 36105 36106 return this.panner.refDistance; 36107 36108 }, 36109 36110 setRefDistance: function ( value ) { 36111 36112 this.panner.refDistance = value; 36113 36114 }, 36115 36116 getRolloffFactor: function () { 36117 36118 return this.panner.rolloffFactor; 36119 36120 }, 36121 36122 setRolloffFactor: function ( value ) { 36123 36124 this.panner.rolloffFactor = value; 36125 36126 }, 36127 36128 getDistanceModel: function () { 36129 36130 return this.panner.distanceModel; 36131 36132 }, 36133 36134 setDistanceModel: function ( value ) { 36135 36136 this.panner.distanceModel = value; 36137 36138 }, 36139 36140 getMaxDistance: function () { 36141 36142 return this.panner.maxDistance; 36143 36144 }, 36145 36146 setMaxDistance: function ( value ) { 36147 36148 this.panner.maxDistance = value; 36149 36150 }, 36151 36152 updateMatrixWorld: ( function () { 36153 36154 var position = new Vector3(); 36155 36156 return function updateMatrixWorld( force ) { 36157 36158 Object3D.prototype.updateMatrixWorld.call( this, force ); 36159 36160 position.setFromMatrixPosition( this.matrixWorld ); 36161 36162 this.panner.setPosition( position.x, position.y, position.z ); 36163 36164 }; 36165 36166 } )() 36167 36168 36169 } ); 36170 36171 /** 36172 * @author mrdoob / http://mrdoob.com/ 36173 */ 36174 36175 function AudioAnalyser( audio, fftSize ) { 36176 36177 this.analyser = audio.context.createAnalyser(); 36178 this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; 36179 36180 this.data = new Uint8Array( this.analyser.frequencyBinCount ); 36181 36182 audio.getOutput().connect( this.analyser ); 36183 36184 } 36185 36186 Object.assign( AudioAnalyser.prototype, { 36187 36188 getFrequencyData: function () { 36189 36190 this.analyser.getByteFrequencyData( this.data ); 36191 36192 return this.data; 36193 36194 }, 36195 36196 getAverageFrequency: function () { 36197 36198 var value = 0, data = this.getFrequencyData(); 36199 36200 for ( var i = 0; i < data.length; i ++ ) { 36201 36202 value += data[ i ]; 36203 36204 } 36205 36206 return value / data.length; 36207 36208 } 36209 36210 } ); 36211 36212 /** 36213 * 36214 * Buffered scene graph property that allows weighted accumulation. 36215 * 36216 * 36217 * @author Ben Houston / http://clara.io/ 36218 * @author David Sarno / http://lighthaus.us/ 36219 * @author tschw 36220 */ 36221 36222 function PropertyMixer( binding, typeName, valueSize ) { 36223 36224 this.binding = binding; 36225 this.valueSize = valueSize; 36226 36227 var bufferType = Float64Array, 36228 mixFunction; 36229 36230 switch ( typeName ) { 36231 36232 case 'quaternion': 36233 mixFunction = this._slerp; 36234 break; 36235 36236 case 'string': 36237 case 'bool': 36238 bufferType = Array; 36239 mixFunction = this._select; 36240 break; 36241 36242 default: 36243 mixFunction = this._lerp; 36244 36245 } 36246 36247 this.buffer = new bufferType( valueSize * 4 ); 36248 // layout: [ incoming | accu0 | accu1 | orig ] 36249 // 36250 // interpolators can use .buffer as their .result 36251 // the data then goes to 'incoming' 36252 // 36253 // 'accu0' and 'accu1' are used frame-interleaved for 36254 // the cumulative result and are compared to detect 36255 // changes 36256 // 36257 // 'orig' stores the original state of the property 36258 36259 this._mixBufferRegion = mixFunction; 36260 36261 this.cumulativeWeight = 0; 36262 36263 this.useCount = 0; 36264 this.referenceCount = 0; 36265 36266 } 36267 36268 PropertyMixer.prototype = { 36269 36270 constructor: PropertyMixer, 36271 36272 // accumulate data in the 'incoming' region into 'accu<i>' 36273 accumulate: function( accuIndex, weight ) { 36274 36275 // note: happily accumulating nothing when weight = 0, the caller knows 36276 // the weight and shouldn't have made the call in the first place 36277 36278 var buffer = this.buffer, 36279 stride = this.valueSize, 36280 offset = accuIndex * stride + stride, 36281 36282 currentWeight = this.cumulativeWeight; 36283 36284 if ( currentWeight === 0 ) { 36285 36286 // accuN := incoming * weight 36287 36288 for ( var i = 0; i !== stride; ++ i ) { 36289 36290 buffer[ offset + i ] = buffer[ i ]; 36291 36292 } 36293 36294 currentWeight = weight; 36295 36296 } else { 36297 36298 // accuN := accuN + incoming * weight 36299 36300 currentWeight += weight; 36301 var mix = weight / currentWeight; 36302 this._mixBufferRegion( buffer, offset, 0, mix, stride ); 36303 36304 } 36305 36306 this.cumulativeWeight = currentWeight; 36307 36308 }, 36309 36310 // apply the state of 'accu<i>' to the binding when accus differ 36311 apply: function( accuIndex ) { 36312 36313 var stride = this.valueSize, 36314 buffer = this.buffer, 36315 offset = accuIndex * stride + stride, 36316 36317 weight = this.cumulativeWeight, 36318 36319 binding = this.binding; 36320 36321 this.cumulativeWeight = 0; 36322 36323 if ( weight < 1 ) { 36324 36325 // accuN := accuN + original * ( 1 - cumulativeWeight ) 36326 36327 var originalValueOffset = stride * 3; 36328 36329 this._mixBufferRegion( 36330 buffer, offset, originalValueOffset, 1 - weight, stride ); 36331 36332 } 36333 36334 for ( var i = stride, e = stride + stride; i !== e; ++ i ) { 36335 36336 if ( buffer[ i ] !== buffer[ i + stride ] ) { 36337 36338 // value has changed -> update scene graph 36339 36340 binding.setValue( buffer, offset ); 36341 break; 36342 36343 } 36344 36345 } 36346 36347 }, 36348 36349 // remember the state of the bound property and copy it to both accus 36350 saveOriginalState: function() { 36351 36352 var binding = this.binding; 36353 36354 var buffer = this.buffer, 36355 stride = this.valueSize, 36356 36357 originalValueOffset = stride * 3; 36358 36359 binding.getValue( buffer, originalValueOffset ); 36360 36361 // accu[0..1] := orig -- initially detect changes against the original 36362 for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { 36363 36364 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; 36365 36366 } 36367 36368 this.cumulativeWeight = 0; 36369 36370 }, 36371 36372 // apply the state previously taken via 'saveOriginalState' to the binding 36373 restoreOriginalState: function() { 36374 36375 var originalValueOffset = this.valueSize * 3; 36376 this.binding.setValue( this.buffer, originalValueOffset ); 36377 36378 }, 36379 36380 36381 // mix functions 36382 36383 _select: function( buffer, dstOffset, srcOffset, t, stride ) { 36384 36385 if ( t >= 0.5 ) { 36386 36387 for ( var i = 0; i !== stride; ++ i ) { 36388 36389 buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; 36390 36391 } 36392 36393 } 36394 36395 }, 36396 36397 _slerp: function( buffer, dstOffset, srcOffset, t, stride ) { 36398 36399 Quaternion.slerpFlat( buffer, dstOffset, 36400 buffer, dstOffset, buffer, srcOffset, t ); 36401 36402 }, 36403 36404 _lerp: function( buffer, dstOffset, srcOffset, t, stride ) { 36405 36406 var s = 1 - t; 36407 36408 for ( var i = 0; i !== stride; ++ i ) { 36409 36410 var j = dstOffset + i; 36411 36412 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; 36413 36414 } 36415 36416 } 36417 36418 }; 36419 36420 /** 36421 * 36422 * A reference to a real property in the scene graph. 36423 * 36424 * 36425 * @author Ben Houston / http://clara.io/ 36426 * @author David Sarno / http://lighthaus.us/ 36427 * @author tschw 36428 */ 36429 36430 function PropertyBinding( rootNode, path, parsedPath ) { 36431 36432 this.path = path; 36433 this.parsedPath = parsedPath || 36434 PropertyBinding.parseTrackName( path ); 36435 36436 this.node = PropertyBinding.findNode( 36437 rootNode, this.parsedPath.nodeName ) || rootNode; 36438 36439 this.rootNode = rootNode; 36440 36441 } 36442 36443 PropertyBinding.prototype = { 36444 36445 constructor: PropertyBinding, 36446 36447 getValue: function getValue_unbound( targetArray, offset ) { 36448 36449 this.bind(); 36450 this.getValue( targetArray, offset ); 36451 36452 // Note: This class uses a State pattern on a per-method basis: 36453 // 'bind' sets 'this.getValue' / 'setValue' and shadows the 36454 // prototype version of these methods with one that represents 36455 // the bound state. When the property is not found, the methods 36456 // become no-ops. 36457 36458 }, 36459 36460 setValue: function getValue_unbound( sourceArray, offset ) { 36461 36462 this.bind(); 36463 this.setValue( sourceArray, offset ); 36464 36465 }, 36466 36467 // create getter / setter pair for a property in the scene graph 36468 bind: function() { 36469 36470 var targetObject = this.node, 36471 parsedPath = this.parsedPath, 36472 36473 objectName = parsedPath.objectName, 36474 propertyName = parsedPath.propertyName, 36475 propertyIndex = parsedPath.propertyIndex; 36476 36477 if ( ! targetObject ) { 36478 36479 targetObject = PropertyBinding.findNode( 36480 this.rootNode, parsedPath.nodeName ) || this.rootNode; 36481 36482 this.node = targetObject; 36483 36484 } 36485 36486 // set fail state so we can just 'return' on error 36487 this.getValue = this._getValue_unavailable; 36488 this.setValue = this._setValue_unavailable; 36489 36490 // ensure there is a value node 36491 if ( ! targetObject ) { 36492 36493 console.error( " trying to update node for track: " + this.path + " but it wasn't found." ); 36494 return; 36495 36496 } 36497 36498 if ( objectName ) { 36499 36500 var objectIndex = parsedPath.objectIndex; 36501 36502 // special cases were we need to reach deeper into the hierarchy to get the face materials.... 36503 switch ( objectName ) { 36504 36505 case 'materials': 36506 36507 if ( ! targetObject.material ) { 36508 36509 console.error( ' can not bind to material as node does not have a material', this ); 36510 return; 36511 36512 } 36513 36514 if ( ! targetObject.material.materials ) { 36515 36516 console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); 36517 return; 36518 36519 } 36520 36521 targetObject = targetObject.material.materials; 36522 36523 break; 36524 36525 case 'bones': 36526 36527 if ( ! targetObject.skeleton ) { 36528 36529 console.error( ' can not bind to bones as node does not have a skeleton', this ); 36530 return; 36531 36532 } 36533 36534 // potential future optimization: skip this if propertyIndex is already an integer 36535 // and convert the integer string to a true integer. 36536 36537 targetObject = targetObject.skeleton.bones; 36538 36539 // support resolving morphTarget names into indices. 36540 for ( var i = 0; i < targetObject.length; i ++ ) { 36541 36542 if ( targetObject[ i ].name === objectIndex ) { 36543 36544 objectIndex = i; 36545 break; 36546 36547 } 36548 36549 } 36550 36551 break; 36552 36553 default: 36554 36555 if ( targetObject[ objectName ] === undefined ) { 36556 36557 console.error( ' can not bind to objectName of node, undefined', this ); 36558 return; 36559 36560 } 36561 36562 targetObject = targetObject[ objectName ]; 36563 36564 } 36565 36566 36567 if ( objectIndex !== undefined ) { 36568 36569 if ( targetObject[ objectIndex ] === undefined ) { 36570 36571 console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); 36572 return; 36573 36574 } 36575 36576 targetObject = targetObject[ objectIndex ]; 36577 36578 } 36579 36580 } 36581 36582 // resolve property 36583 var nodeProperty = targetObject[ propertyName ]; 36584 36585 if ( nodeProperty === undefined ) { 36586 36587 var nodeName = parsedPath.nodeName; 36588 36589 console.error( " trying to update property for track: " + nodeName + 36590 '.' + propertyName + " but it wasn't found.", targetObject ); 36591 return; 36592 36593 } 36594 36595 // determine versioning scheme 36596 var versioning = this.Versioning.None; 36597 36598 if ( targetObject.needsUpdate !== undefined ) { // material 36599 36600 versioning = this.Versioning.NeedsUpdate; 36601 this.targetObject = targetObject; 36602 36603 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform 36604 36605 versioning = this.Versioning.MatrixWorldNeedsUpdate; 36606 this.targetObject = targetObject; 36607 36608 } 36609 36610 // determine how the property gets bound 36611 var bindingType = this.BindingType.Direct; 36612 36613 if ( propertyIndex !== undefined ) { 36614 // access a sub element of the property array (only primitives are supported right now) 36615 36616 if ( propertyName === "morphTargetInfluences" ) { 36617 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. 36618 36619 // support resolving morphTarget names into indices. 36620 if ( ! targetObject.geometry ) { 36621 36622 console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); 36623 return; 36624 36625 } 36626 36627 if ( ! targetObject.geometry.morphTargets ) { 36628 36629 console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); 36630 return; 36631 36632 } 36633 36634 for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { 36635 36636 if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { 36637 36638 propertyIndex = i; 36639 break; 36640 36641 } 36642 36643 } 36644 36645 } 36646 36647 bindingType = this.BindingType.ArrayElement; 36648 36649 this.resolvedProperty = nodeProperty; 36650 this.propertyIndex = propertyIndex; 36651 36652 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { 36653 // must use copy for Object3D.Euler/Quaternion 36654 36655 bindingType = this.BindingType.HasFromToArray; 36656 36657 this.resolvedProperty = nodeProperty; 36658 36659 } else if ( nodeProperty.length !== undefined ) { 36660 36661 bindingType = this.BindingType.EntireArray; 36662 36663 this.resolvedProperty = nodeProperty; 36664 36665 } else { 36666 36667 this.propertyName = propertyName; 36668 36669 } 36670 36671 // select getter / setter 36672 this.getValue = this.GetterByBindingType[ bindingType ]; 36673 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; 36674 36675 }, 36676 36677 unbind: function() { 36678 36679 this.node = null; 36680 36681 // back to the prototype version of getValue / setValue 36682 // note: avoiding to mutate the shape of 'this' via 'delete' 36683 this.getValue = this._getValue_unbound; 36684 this.setValue = this._setValue_unbound; 36685 36686 } 36687 36688 }; 36689 36690 Object.assign( PropertyBinding.prototype, { // prototype, continued 36691 36692 // these are used to "bind" a nonexistent property 36693 _getValue_unavailable: function() {}, 36694 _setValue_unavailable: function() {}, 36695 36696 // initial state of these methods that calls 'bind' 36697 _getValue_unbound: PropertyBinding.prototype.getValue, 36698 _setValue_unbound: PropertyBinding.prototype.setValue, 36699 36700 BindingType: { 36701 Direct: 0, 36702 EntireArray: 1, 36703 ArrayElement: 2, 36704 HasFromToArray: 3 36705 }, 36706 36707 Versioning: { 36708 None: 0, 36709 NeedsUpdate: 1, 36710 MatrixWorldNeedsUpdate: 2 36711 }, 36712 36713 GetterByBindingType: [ 36714 36715 function getValue_direct( buffer, offset ) { 36716 36717 buffer[ offset ] = this.node[ this.propertyName ]; 36718 36719 }, 36720 36721 function getValue_array( buffer, offset ) { 36722 36723 var source = this.resolvedProperty; 36724 36725 for ( var i = 0, n = source.length; i !== n; ++ i ) { 36726 36727 buffer[ offset ++ ] = source[ i ]; 36728 36729 } 36730 36731 }, 36732 36733 function getValue_arrayElement( buffer, offset ) { 36734 36735 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; 36736 36737 }, 36738 36739 function getValue_toArray( buffer, offset ) { 36740 36741 this.resolvedProperty.toArray( buffer, offset ); 36742 36743 } 36744 36745 ], 36746 36747 SetterByBindingTypeAndVersioning: [ 36748 36749 [ 36750 // Direct 36751 36752 function setValue_direct( buffer, offset ) { 36753 36754 this.node[ this.propertyName ] = buffer[ offset ]; 36755 36756 }, 36757 36758 function setValue_direct_setNeedsUpdate( buffer, offset ) { 36759 36760 this.node[ this.propertyName ] = buffer[ offset ]; 36761 this.targetObject.needsUpdate = true; 36762 36763 }, 36764 36765 function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { 36766 36767 this.node[ this.propertyName ] = buffer[ offset ]; 36768 this.targetObject.matrixWorldNeedsUpdate = true; 36769 36770 } 36771 36772 ], [ 36773 36774 // EntireArray 36775 36776 function setValue_array( buffer, offset ) { 36777 36778 var dest = this.resolvedProperty; 36779 36780 for ( var i = 0, n = dest.length; i !== n; ++ i ) { 36781 36782 dest[ i ] = buffer[ offset ++ ]; 36783 36784 } 36785 36786 }, 36787 36788 function setValue_array_setNeedsUpdate( buffer, offset ) { 36789 36790 var dest = this.resolvedProperty; 36791 36792 for ( var i = 0, n = dest.length; i !== n; ++ i ) { 36793 36794 dest[ i ] = buffer[ offset ++ ]; 36795 36796 } 36797 36798 this.targetObject.needsUpdate = true; 36799 36800 }, 36801 36802 function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { 36803 36804 var dest = this.resolvedProperty; 36805 36806 for ( var i = 0, n = dest.length; i !== n; ++ i ) { 36807 36808 dest[ i ] = buffer[ offset ++ ]; 36809 36810 } 36811 36812 this.targetObject.matrixWorldNeedsUpdate = true; 36813 36814 } 36815 36816 ], [ 36817 36818 // ArrayElement 36819 36820 function setValue_arrayElement( buffer, offset ) { 36821 36822 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 36823 36824 }, 36825 36826 function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { 36827 36828 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 36829 this.targetObject.needsUpdate = true; 36830 36831 }, 36832 36833 function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { 36834 36835 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 36836 this.targetObject.matrixWorldNeedsUpdate = true; 36837 36838 } 36839 36840 ], [ 36841 36842 // HasToFromArray 36843 36844 function setValue_fromArray( buffer, offset ) { 36845 36846 this.resolvedProperty.fromArray( buffer, offset ); 36847 36848 }, 36849 36850 function setValue_fromArray_setNeedsUpdate( buffer, offset ) { 36851 36852 this.resolvedProperty.fromArray( buffer, offset ); 36853 this.targetObject.needsUpdate = true; 36854 36855 }, 36856 36857 function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { 36858 36859 this.resolvedProperty.fromArray( buffer, offset ); 36860 this.targetObject.matrixWorldNeedsUpdate = true; 36861 36862 } 36863 36864 ] 36865 36866 ] 36867 36868 } ); 36869 36870 PropertyBinding.Composite = 36871 function( targetGroup, path, optionalParsedPath ) { 36872 36873 var parsedPath = optionalParsedPath || 36874 PropertyBinding.parseTrackName( path ); 36875 36876 this._targetGroup = targetGroup; 36877 this._bindings = targetGroup.subscribe_( path, parsedPath ); 36878 36879 }; 36880 36881 PropertyBinding.Composite.prototype = { 36882 36883 constructor: PropertyBinding.Composite, 36884 36885 getValue: function( array, offset ) { 36886 36887 this.bind(); // bind all binding 36888 36889 var firstValidIndex = this._targetGroup.nCachedObjects_, 36890 binding = this._bindings[ firstValidIndex ]; 36891 36892 // and only call .getValue on the first 36893 if ( binding !== undefined ) binding.getValue( array, offset ); 36894 36895 }, 36896 36897 setValue: function( array, offset ) { 36898 36899 var bindings = this._bindings; 36900 36901 for ( var i = this._targetGroup.nCachedObjects_, 36902 n = bindings.length; i !== n; ++ i ) { 36903 36904 bindings[ i ].setValue( array, offset ); 36905 36906 } 36907 36908 }, 36909 36910 bind: function() { 36911 36912 var bindings = this._bindings; 36913 36914 for ( var i = this._targetGroup.nCachedObjects_, 36915 n = bindings.length; i !== n; ++ i ) { 36916 36917 bindings[ i ].bind(); 36918 36919 } 36920 36921 }, 36922 36923 unbind: function() { 36924 36925 var bindings = this._bindings; 36926 36927 for ( var i = this._targetGroup.nCachedObjects_, 36928 n = bindings.length; i !== n; ++ i ) { 36929 36930 bindings[ i ].unbind(); 36931 36932 } 36933 36934 } 36935 36936 }; 36937 36938 PropertyBinding.create = function( root, path, parsedPath ) { 36939 36940 if ( ! ( root && root.isAnimationObjectGroup ) ) { 36941 36942 return new PropertyBinding( root, path, parsedPath ); 36943 36944 } else { 36945 36946 return new PropertyBinding.Composite( root, path, parsedPath ); 36947 36948 } 36949 36950 }; 36951 36952 PropertyBinding.parseTrackName = function( trackName ) { 36953 36954 // matches strings in the form of: 36955 // nodeName.property 36956 // nodeName.property[accessor] 36957 // nodeName.material.property[accessor] 36958 // uuid.property[accessor] 36959 // uuid.objectName[objectIndex].propertyName[propertyIndex] 36960 // parentName/nodeName.property 36961 // parentName/parentName/nodeName.property[index] 36962 // .bone[Armature.DEF_cog].position 36963 // scene:helium_balloon_model:helium_balloon_model.position 36964 // created and tested via https://regex101.com/#javascript 36965 36966 var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/; 36967 var matches = re.exec( trackName ); 36968 36969 if ( ! matches ) { 36970 36971 throw new Error( "cannot parse trackName at all: " + trackName ); 36972 36973 } 36974 36975 var results = { 36976 // directoryName: matches[ 1 ], // (tschw) currently unused 36977 nodeName: matches[ 2 ], // allowed to be null, specified root node. 36978 objectName: matches[ 3 ], 36979 objectIndex: matches[ 4 ], 36980 propertyName: matches[ 5 ], 36981 propertyIndex: matches[ 6 ] // allowed to be null, specifies that the whole property is set. 36982 }; 36983 36984 if ( results.propertyName === null || results.propertyName.length === 0 ) { 36985 36986 throw new Error( "can not parse propertyName from trackName: " + trackName ); 36987 36988 } 36989 36990 return results; 36991 36992 }; 36993 36994 PropertyBinding.findNode = function( root, nodeName ) { 36995 36996 if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { 36997 36998 return root; 36999 37000 } 37001 37002 // search into skeleton bones. 37003 if ( root.skeleton ) { 37004 37005 var searchSkeleton = function( skeleton ) { 37006 37007 for( var i = 0; i < skeleton.bones.length; i ++ ) { 37008 37009 var bone = skeleton.bones[ i ]; 37010 37011 if ( bone.name === nodeName ) { 37012 37013 return bone; 37014 37015 } 37016 } 37017 37018 return null; 37019 37020 }; 37021 37022 var bone = searchSkeleton( root.skeleton ); 37023 37024 if ( bone ) { 37025 37026 return bone; 37027 37028 } 37029 } 37030 37031 // search into node subtree. 37032 if ( root.children ) { 37033 37034 var searchNodeSubtree = function( children ) { 37035 37036 for( var i = 0; i < children.length; i ++ ) { 37037 37038 var childNode = children[ i ]; 37039 37040 if ( childNode.name === nodeName || childNode.uuid === nodeName ) { 37041 37042 return childNode; 37043 37044 } 37045 37046 var result = searchNodeSubtree( childNode.children ); 37047 37048 if ( result ) return result; 37049 37050 } 37051 37052 return null; 37053 37054 }; 37055 37056 var subTreeNode = searchNodeSubtree( root.children ); 37057 37058 if ( subTreeNode ) { 37059 37060 return subTreeNode; 37061 37062 } 37063 37064 } 37065 37066 return null; 37067 37068 }; 37069 37070 /** 37071 * 37072 * A group of objects that receives a shared animation state. 37073 * 37074 * Usage: 37075 * 37076 * - Add objects you would otherwise pass as 'root' to the 37077 * constructor or the .clipAction method of AnimationMixer. 37078 * 37079 * - Instead pass this object as 'root'. 37080 * 37081 * - You can also add and remove objects later when the mixer 37082 * is running. 37083 * 37084 * Note: 37085 * 37086 * Objects of this class appear as one object to the mixer, 37087 * so cache control of the individual objects must be done 37088 * on the group. 37089 * 37090 * Limitation: 37091 * 37092 * - The animated properties must be compatible among the 37093 * all objects in the group. 37094 * 37095 * - A single property can either be controlled through a 37096 * target group or directly, but not both. 37097 * 37098 * @author tschw 37099 */ 37100 37101 function AnimationObjectGroup( var_args ) { 37102 37103 this.uuid = _Math.generateUUID(); 37104 37105 // cached objects followed by the active ones 37106 this._objects = Array.prototype.slice.call( arguments ); 37107 37108 this.nCachedObjects_ = 0; // threshold 37109 // note: read by PropertyBinding.Composite 37110 37111 var indices = {}; 37112 this._indicesByUUID = indices; // for bookkeeping 37113 37114 for ( var i = 0, n = arguments.length; i !== n; ++ i ) { 37115 37116 indices[ arguments[ i ].uuid ] = i; 37117 37118 } 37119 37120 this._paths = []; // inside: string 37121 this._parsedPaths = []; // inside: { we don't care, here } 37122 this._bindings = []; // inside: Array< PropertyBinding > 37123 this._bindingsIndicesByPath = {}; // inside: indices in these arrays 37124 37125 var scope = this; 37126 37127 this.stats = { 37128 37129 objects: { 37130 get total() { return scope._objects.length; }, 37131 get inUse() { return this.total - scope.nCachedObjects_; } 37132 }, 37133 37134 get bindingsPerObject() { return scope._bindings.length; } 37135 37136 }; 37137 37138 } 37139 37140 AnimationObjectGroup.prototype = { 37141 37142 constructor: AnimationObjectGroup, 37143 37144 isAnimationObjectGroup: true, 37145 37146 add: function( var_args ) { 37147 37148 var objects = this._objects, 37149 nObjects = objects.length, 37150 nCachedObjects = this.nCachedObjects_, 37151 indicesByUUID = this._indicesByUUID, 37152 paths = this._paths, 37153 parsedPaths = this._parsedPaths, 37154 bindings = this._bindings, 37155 nBindings = bindings.length; 37156 37157 for ( var i = 0, n = arguments.length; i !== n; ++ i ) { 37158 37159 var object = arguments[ i ], 37160 uuid = object.uuid, 37161 index = indicesByUUID[ uuid ], 37162 knownObject = undefined; 37163 37164 if ( index === undefined ) { 37165 37166 // unknown object -> add it to the ACTIVE region 37167 37168 index = nObjects ++; 37169 indicesByUUID[ uuid ] = index; 37170 objects.push( object ); 37171 37172 // accounting is done, now do the same for all bindings 37173 37174 for ( var j = 0, m = nBindings; j !== m; ++ j ) { 37175 37176 bindings[ j ].push( 37177 new PropertyBinding( 37178 object, paths[ j ], parsedPaths[ j ] ) ); 37179 37180 } 37181 37182 } else if ( index < nCachedObjects ) { 37183 37184 knownObject = objects[ index ]; 37185 37186 // move existing object to the ACTIVE region 37187 37188 var firstActiveIndex = -- nCachedObjects, 37189 lastCachedObject = objects[ firstActiveIndex ]; 37190 37191 indicesByUUID[ lastCachedObject.uuid ] = index; 37192 objects[ index ] = lastCachedObject; 37193 37194 indicesByUUID[ uuid ] = firstActiveIndex; 37195 objects[ firstActiveIndex ] = object; 37196 37197 // accounting is done, now do the same for all bindings 37198 37199 for ( var j = 0, m = nBindings; j !== m; ++ j ) { 37200 37201 var bindingsForPath = bindings[ j ], 37202 lastCached = bindingsForPath[ firstActiveIndex ], 37203 binding = bindingsForPath[ index ]; 37204 37205 bindingsForPath[ index ] = lastCached; 37206 37207 if ( binding === undefined ) { 37208 37209 // since we do not bother to create new bindings 37210 // for objects that are cached, the binding may 37211 // or may not exist 37212 37213 binding = new PropertyBinding( 37214 object, paths[ j ], parsedPaths[ j ] ); 37215 37216 } 37217 37218 bindingsForPath[ firstActiveIndex ] = binding; 37219 37220 } 37221 37222 } else if ( objects[ index ] !== knownObject) { 37223 37224 console.error( "Different objects with the same UUID " + 37225 "detected. Clean the caches or recreate your " + 37226 "infrastructure when reloading scenes..." ); 37227 37228 } // else the object is already where we want it to be 37229 37230 } // for arguments 37231 37232 this.nCachedObjects_ = nCachedObjects; 37233 37234 }, 37235 37236 remove: function( var_args ) { 37237 37238 var objects = this._objects, 37239 nCachedObjects = this.nCachedObjects_, 37240 indicesByUUID = this._indicesByUUID, 37241 bindings = this._bindings, 37242 nBindings = bindings.length; 37243 37244 for ( var i = 0, n = arguments.length; i !== n; ++ i ) { 37245 37246 var object = arguments[ i ], 37247 uuid = object.uuid, 37248 index = indicesByUUID[ uuid ]; 37249 37250 if ( index !== undefined && index >= nCachedObjects ) { 37251 37252 // move existing object into the CACHED region 37253 37254 var lastCachedIndex = nCachedObjects ++, 37255 firstActiveObject = objects[ lastCachedIndex ]; 37256 37257 indicesByUUID[ firstActiveObject.uuid ] = index; 37258 objects[ index ] = firstActiveObject; 37259 37260 indicesByUUID[ uuid ] = lastCachedIndex; 37261 objects[ lastCachedIndex ] = object; 37262 37263 // accounting is done, now do the same for all bindings 37264 37265 for ( var j = 0, m = nBindings; j !== m; ++ j ) { 37266 37267 var bindingsForPath = bindings[ j ], 37268 firstActive = bindingsForPath[ lastCachedIndex ], 37269 binding = bindingsForPath[ index ]; 37270 37271 bindingsForPath[ index ] = firstActive; 37272 bindingsForPath[ lastCachedIndex ] = binding; 37273 37274 } 37275 37276 } 37277 37278 } // for arguments 37279 37280 this.nCachedObjects_ = nCachedObjects; 37281 37282 }, 37283 37284 // remove & forget 37285 uncache: function( var_args ) { 37286 37287 var objects = this._objects, 37288 nObjects = objects.length, 37289 nCachedObjects = this.nCachedObjects_, 37290 indicesByUUID = this._indicesByUUID, 37291 bindings = this._bindings, 37292 nBindings = bindings.length; 37293 37294 for ( var i = 0, n = arguments.length; i !== n; ++ i ) { 37295 37296 var object = arguments[ i ], 37297 uuid = object.uuid, 37298 index = indicesByUUID[ uuid ]; 37299 37300 if ( index !== undefined ) { 37301 37302 delete indicesByUUID[ uuid ]; 37303 37304 if ( index < nCachedObjects ) { 37305 37306 // object is cached, shrink the CACHED region 37307 37308 var firstActiveIndex = -- nCachedObjects, 37309 lastCachedObject = objects[ firstActiveIndex ], 37310 lastIndex = -- nObjects, 37311 lastObject = objects[ lastIndex ]; 37312 37313 // last cached object takes this object's place 37314 indicesByUUID[ lastCachedObject.uuid ] = index; 37315 objects[ index ] = lastCachedObject; 37316 37317 // last object goes to the activated slot and pop 37318 indicesByUUID[ lastObject.uuid ] = firstActiveIndex; 37319 objects[ firstActiveIndex ] = lastObject; 37320 objects.pop(); 37321 37322 // accounting is done, now do the same for all bindings 37323 37324 for ( var j = 0, m = nBindings; j !== m; ++ j ) { 37325 37326 var bindingsForPath = bindings[ j ], 37327 lastCached = bindingsForPath[ firstActiveIndex ], 37328 last = bindingsForPath[ lastIndex ]; 37329 37330 bindingsForPath[ index ] = lastCached; 37331 bindingsForPath[ firstActiveIndex ] = last; 37332 bindingsForPath.pop(); 37333 37334 } 37335 37336 } else { 37337 37338 // object is active, just swap with the last and pop 37339 37340 var lastIndex = -- nObjects, 37341 lastObject = objects[ lastIndex ]; 37342 37343 indicesByUUID[ lastObject.uuid ] = index; 37344 objects[ index ] = lastObject; 37345 objects.pop(); 37346 37347 // accounting is done, now do the same for all bindings 37348 37349 for ( var j = 0, m = nBindings; j !== m; ++ j ) { 37350 37351 var bindingsForPath = bindings[ j ]; 37352 37353 bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; 37354 bindingsForPath.pop(); 37355 37356 } 37357 37358 } // cached or active 37359 37360 } // if object is known 37361 37362 } // for arguments 37363 37364 this.nCachedObjects_ = nCachedObjects; 37365 37366 }, 37367 37368 // Internal interface used by befriended PropertyBinding.Composite: 37369 37370 subscribe_: function( path, parsedPath ) { 37371 // returns an array of bindings for the given path that is changed 37372 // according to the contained objects in the group 37373 37374 var indicesByPath = this._bindingsIndicesByPath, 37375 index = indicesByPath[ path ], 37376 bindings = this._bindings; 37377 37378 if ( index !== undefined ) return bindings[ index ]; 37379 37380 var paths = this._paths, 37381 parsedPaths = this._parsedPaths, 37382 objects = this._objects, 37383 nObjects = objects.length, 37384 nCachedObjects = this.nCachedObjects_, 37385 bindingsForPath = new Array( nObjects ); 37386 37387 index = bindings.length; 37388 37389 indicesByPath[ path ] = index; 37390 37391 paths.push( path ); 37392 parsedPaths.push( parsedPath ); 37393 bindings.push( bindingsForPath ); 37394 37395 for ( var i = nCachedObjects, 37396 n = objects.length; i !== n; ++ i ) { 37397 37398 var object = objects[ i ]; 37399 37400 bindingsForPath[ i ] = 37401 new PropertyBinding( object, path, parsedPath ); 37402 37403 } 37404 37405 return bindingsForPath; 37406 37407 }, 37408 37409 unsubscribe_: function( path ) { 37410 // tells the group to forget about a property path and no longer 37411 // update the array previously obtained with 'subscribe_' 37412 37413 var indicesByPath = this._bindingsIndicesByPath, 37414 index = indicesByPath[ path ]; 37415 37416 if ( index !== undefined ) { 37417 37418 var paths = this._paths, 37419 parsedPaths = this._parsedPaths, 37420 bindings = this._bindings, 37421 lastBindingsIndex = bindings.length - 1, 37422 lastBindings = bindings[ lastBindingsIndex ], 37423 lastBindingsPath = path[ lastBindingsIndex ]; 37424 37425 indicesByPath[ lastBindingsPath ] = index; 37426 37427 bindings[ index ] = lastBindings; 37428 bindings.pop(); 37429 37430 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; 37431 parsedPaths.pop(); 37432 37433 paths[ index ] = paths[ lastBindingsIndex ]; 37434 paths.pop(); 37435 37436 } 37437 37438 } 37439 37440 }; 37441 37442 /** 37443 * 37444 * Action provided by AnimationMixer for scheduling clip playback on specific 37445 * objects. 37446 * 37447 * @author Ben Houston / http://clara.io/ 37448 * @author David Sarno / http://lighthaus.us/ 37449 * @author tschw 37450 * 37451 */ 37452 37453 function AnimationAction( mixer, clip, localRoot ) { 37454 37455 this._mixer = mixer; 37456 this._clip = clip; 37457 this._localRoot = localRoot || null; 37458 37459 var tracks = clip.tracks, 37460 nTracks = tracks.length, 37461 interpolants = new Array( nTracks ); 37462 37463 var interpolantSettings = { 37464 endingStart: ZeroCurvatureEnding, 37465 endingEnd: ZeroCurvatureEnding 37466 }; 37467 37468 for ( var i = 0; i !== nTracks; ++ i ) { 37469 37470 var interpolant = tracks[ i ].createInterpolant( null ); 37471 interpolants[ i ] = interpolant; 37472 interpolant.settings = interpolantSettings; 37473 37474 } 37475 37476 this._interpolantSettings = interpolantSettings; 37477 37478 this._interpolants = interpolants; // bound by the mixer 37479 37480 // inside: PropertyMixer (managed by the mixer) 37481 this._propertyBindings = new Array( nTracks ); 37482 37483 this._cacheIndex = null; // for the memory manager 37484 this._byClipCacheIndex = null; // for the memory manager 37485 37486 this._timeScaleInterpolant = null; 37487 this._weightInterpolant = null; 37488 37489 this.loop = LoopRepeat; 37490 this._loopCount = -1; 37491 37492 // global mixer time when the action is to be started 37493 // it's set back to 'null' upon start of the action 37494 this._startTime = null; 37495 37496 // scaled local time of the action 37497 // gets clamped or wrapped to 0..clip.duration according to loop 37498 this.time = 0; 37499 37500 this.timeScale = 1; 37501 this._effectiveTimeScale = 1; 37502 37503 this.weight = 1; 37504 this._effectiveWeight = 1; 37505 37506 this.repetitions = Infinity; // no. of repetitions when looping 37507 37508 this.paused = false; // false -> zero effective time scale 37509 this.enabled = true; // true -> zero effective weight 37510 37511 this.clampWhenFinished = false; // keep feeding the last frame? 37512 37513 this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate 37514 this.zeroSlopeAtEnd = true; // clips for start, loop and end 37515 37516 } 37517 37518 AnimationAction.prototype = { 37519 37520 constructor: AnimationAction, 37521 37522 // State & Scheduling 37523 37524 play: function() { 37525 37526 this._mixer._activateAction( this ); 37527 37528 return this; 37529 37530 }, 37531 37532 stop: function() { 37533 37534 this._mixer._deactivateAction( this ); 37535 37536 return this.reset(); 37537 37538 }, 37539 37540 reset: function() { 37541 37542 this.paused = false; 37543 this.enabled = true; 37544 37545 this.time = 0; // restart clip 37546 this._loopCount = -1; // forget previous loops 37547 this._startTime = null; // forget scheduling 37548 37549 return this.stopFading().stopWarping(); 37550 37551 }, 37552 37553 isRunning: function() { 37554 37555 return this.enabled && ! this.paused && this.timeScale !== 0 && 37556 this._startTime === null && this._mixer._isActiveAction( this ); 37557 37558 }, 37559 37560 // return true when play has been called 37561 isScheduled: function() { 37562 37563 return this._mixer._isActiveAction( this ); 37564 37565 }, 37566 37567 startAt: function( time ) { 37568 37569 this._startTime = time; 37570 37571 return this; 37572 37573 }, 37574 37575 setLoop: function( mode, repetitions ) { 37576 37577 this.loop = mode; 37578 this.repetitions = repetitions; 37579 37580 return this; 37581 37582 }, 37583 37584 // Weight 37585 37586 // set the weight stopping any scheduled fading 37587 // although .enabled = false yields an effective weight of zero, this 37588 // method does *not* change .enabled, because it would be confusing 37589 setEffectiveWeight: function( weight ) { 37590 37591 this.weight = weight; 37592 37593 // note: same logic as when updated at runtime 37594 this._effectiveWeight = this.enabled ? weight : 0; 37595 37596 return this.stopFading(); 37597 37598 }, 37599 37600 // return the weight considering fading and .enabled 37601 getEffectiveWeight: function() { 37602 37603 return this._effectiveWeight; 37604 37605 }, 37606 37607 fadeIn: function( duration ) { 37608 37609 return this._scheduleFading( duration, 0, 1 ); 37610 37611 }, 37612 37613 fadeOut: function( duration ) { 37614 37615 return this._scheduleFading( duration, 1, 0 ); 37616 37617 }, 37618 37619 crossFadeFrom: function( fadeOutAction, duration, warp ) { 37620 37621 fadeOutAction.fadeOut( duration ); 37622 this.fadeIn( duration ); 37623 37624 if( warp ) { 37625 37626 var fadeInDuration = this._clip.duration, 37627 fadeOutDuration = fadeOutAction._clip.duration, 37628 37629 startEndRatio = fadeOutDuration / fadeInDuration, 37630 endStartRatio = fadeInDuration / fadeOutDuration; 37631 37632 fadeOutAction.warp( 1.0, startEndRatio, duration ); 37633 this.warp( endStartRatio, 1.0, duration ); 37634 37635 } 37636 37637 return this; 37638 37639 }, 37640 37641 crossFadeTo: function( fadeInAction, duration, warp ) { 37642 37643 return fadeInAction.crossFadeFrom( this, duration, warp ); 37644 37645 }, 37646 37647 stopFading: function() { 37648 37649 var weightInterpolant = this._weightInterpolant; 37650 37651 if ( weightInterpolant !== null ) { 37652 37653 this._weightInterpolant = null; 37654 this._mixer._takeBackControlInterpolant( weightInterpolant ); 37655 37656 } 37657 37658 return this; 37659 37660 }, 37661 37662 // Time Scale Control 37663 37664 // set the weight stopping any scheduled warping 37665 // although .paused = true yields an effective time scale of zero, this 37666 // method does *not* change .paused, because it would be confusing 37667 setEffectiveTimeScale: function( timeScale ) { 37668 37669 this.timeScale = timeScale; 37670 this._effectiveTimeScale = this.paused ? 0 :timeScale; 37671 37672 return this.stopWarping(); 37673 37674 }, 37675 37676 // return the time scale considering warping and .paused 37677 getEffectiveTimeScale: function() { 37678 37679 return this._effectiveTimeScale; 37680 37681 }, 37682 37683 setDuration: function( duration ) { 37684 37685 this.timeScale = this._clip.duration / duration; 37686 37687 return this.stopWarping(); 37688 37689 }, 37690 37691 syncWith: function( action ) { 37692 37693 this.time = action.time; 37694 this.timeScale = action.timeScale; 37695 37696 return this.stopWarping(); 37697 37698 }, 37699 37700 halt: function( duration ) { 37701 37702 return this.warp( this._effectiveTimeScale, 0, duration ); 37703 37704 }, 37705 37706 warp: function( startTimeScale, endTimeScale, duration ) { 37707 37708 var mixer = this._mixer, now = mixer.time, 37709 interpolant = this._timeScaleInterpolant, 37710 37711 timeScale = this.timeScale; 37712 37713 if ( interpolant === null ) { 37714 37715 interpolant = mixer._lendControlInterpolant(); 37716 this._timeScaleInterpolant = interpolant; 37717 37718 } 37719 37720 var times = interpolant.parameterPositions, 37721 values = interpolant.sampleValues; 37722 37723 times[ 0 ] = now; 37724 times[ 1 ] = now + duration; 37725 37726 values[ 0 ] = startTimeScale / timeScale; 37727 values[ 1 ] = endTimeScale / timeScale; 37728 37729 return this; 37730 37731 }, 37732 37733 stopWarping: function() { 37734 37735 var timeScaleInterpolant = this._timeScaleInterpolant; 37736 37737 if ( timeScaleInterpolant !== null ) { 37738 37739 this._timeScaleInterpolant = null; 37740 this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); 37741 37742 } 37743 37744 return this; 37745 37746 }, 37747 37748 // Object Accessors 37749 37750 getMixer: function() { 37751 37752 return this._mixer; 37753 37754 }, 37755 37756 getClip: function() { 37757 37758 return this._clip; 37759 37760 }, 37761 37762 getRoot: function() { 37763 37764 return this._localRoot || this._mixer._root; 37765 37766 }, 37767 37768 // Interna 37769 37770 _update: function( time, deltaTime, timeDirection, accuIndex ) { 37771 // called by the mixer 37772 37773 var startTime = this._startTime; 37774 37775 if ( startTime !== null ) { 37776 37777 // check for scheduled start of action 37778 37779 var timeRunning = ( time - startTime ) * timeDirection; 37780 if ( timeRunning < 0 || timeDirection === 0 ) { 37781 37782 return; // yet to come / don't decide when delta = 0 37783 37784 } 37785 37786 // start 37787 37788 this._startTime = null; // unschedule 37789 deltaTime = timeDirection * timeRunning; 37790 37791 } 37792 37793 // apply time scale and advance time 37794 37795 deltaTime *= this._updateTimeScale( time ); 37796 var clipTime = this._updateTime( deltaTime ); 37797 37798 // note: _updateTime may disable the action resulting in 37799 // an effective weight of 0 37800 37801 var weight = this._updateWeight( time ); 37802 37803 if ( weight > 0 ) { 37804 37805 var interpolants = this._interpolants; 37806 var propertyMixers = this._propertyBindings; 37807 37808 for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { 37809 37810 interpolants[ j ].evaluate( clipTime ); 37811 propertyMixers[ j ].accumulate( accuIndex, weight ); 37812 37813 } 37814 37815 } 37816 37817 }, 37818 37819 _updateWeight: function( time ) { 37820 37821 var weight = 0; 37822 37823 if ( this.enabled ) { 37824 37825 weight = this.weight; 37826 var interpolant = this._weightInterpolant; 37827 37828 if ( interpolant !== null ) { 37829 37830 var interpolantValue = interpolant.evaluate( time )[ 0 ]; 37831 37832 weight *= interpolantValue; 37833 37834 if ( time > interpolant.parameterPositions[ 1 ] ) { 37835 37836 this.stopFading(); 37837 37838 if ( interpolantValue === 0 ) { 37839 37840 // faded out, disable 37841 this.enabled = false; 37842 37843 } 37844 37845 } 37846 37847 } 37848 37849 } 37850 37851 this._effectiveWeight = weight; 37852 return weight; 37853 37854 }, 37855 37856 _updateTimeScale: function( time ) { 37857 37858 var timeScale = 0; 37859 37860 if ( ! this.paused ) { 37861 37862 timeScale = this.timeScale; 37863 37864 var interpolant = this._timeScaleInterpolant; 37865 37866 if ( interpolant !== null ) { 37867 37868 var interpolantValue = interpolant.evaluate( time )[ 0 ]; 37869 37870 timeScale *= interpolantValue; 37871 37872 if ( time > interpolant.parameterPositions[ 1 ] ) { 37873 37874 this.stopWarping(); 37875 37876 if ( timeScale === 0 ) { 37877 37878 // motion has halted, pause 37879 this.paused = true; 37880 37881 } else { 37882 37883 // warp done - apply final time scale 37884 this.timeScale = timeScale; 37885 37886 } 37887 37888 } 37889 37890 } 37891 37892 } 37893 37894 this._effectiveTimeScale = timeScale; 37895 return timeScale; 37896 37897 }, 37898 37899 _updateTime: function( deltaTime ) { 37900 37901 var time = this.time + deltaTime; 37902 37903 if ( deltaTime === 0 ) return time; 37904 37905 var duration = this._clip.duration, 37906 37907 loop = this.loop, 37908 loopCount = this._loopCount; 37909 37910 if ( loop === LoopOnce ) { 37911 37912 if ( loopCount === -1 ) { 37913 // just started 37914 37915 this._loopCount = 0; 37916 this._setEndings( true, true, false ); 37917 37918 } 37919 37920 handle_stop: { 37921 37922 if ( time >= duration ) { 37923 37924 time = duration; 37925 37926 } else if ( time < 0 ) { 37927 37928 time = 0; 37929 37930 } else break handle_stop; 37931 37932 if ( this.clampWhenFinished ) this.paused = true; 37933 else this.enabled = false; 37934 37935 this._mixer.dispatchEvent( { 37936 type: 'finished', action: this, 37937 direction: deltaTime < 0 ? -1 : 1 37938 } ); 37939 37940 } 37941 37942 } else { // repetitive Repeat or PingPong 37943 37944 var pingPong = ( loop === LoopPingPong ); 37945 37946 if ( loopCount === -1 ) { 37947 // just started 37948 37949 if ( deltaTime >= 0 ) { 37950 37951 loopCount = 0; 37952 37953 this._setEndings( 37954 true, this.repetitions === 0, pingPong ); 37955 37956 } else { 37957 37958 // when looping in reverse direction, the initial 37959 // transition through zero counts as a repetition, 37960 // so leave loopCount at -1 37961 37962 this._setEndings( 37963 this.repetitions === 0, true, pingPong ); 37964 37965 } 37966 37967 } 37968 37969 if ( time >= duration || time < 0 ) { 37970 // wrap around 37971 37972 var loopDelta = Math.floor( time / duration ); // signed 37973 time -= duration * loopDelta; 37974 37975 loopCount += Math.abs( loopDelta ); 37976 37977 var pending = this.repetitions - loopCount; 37978 37979 if ( pending < 0 ) { 37980 // have to stop (switch state, clamp time, fire event) 37981 37982 if ( this.clampWhenFinished ) this.paused = true; 37983 else this.enabled = false; 37984 37985 time = deltaTime > 0 ? duration : 0; 37986 37987 this._mixer.dispatchEvent( { 37988 type: 'finished', action: this, 37989 direction: deltaTime > 0 ? 1 : -1 37990 } ); 37991 37992 } else { 37993 // keep running 37994 37995 if ( pending === 0 ) { 37996 // entering the last round 37997 37998 var atStart = deltaTime < 0; 37999 this._setEndings( atStart, ! atStart, pingPong ); 38000 38001 } else { 38002 38003 this._setEndings( false, false, pingPong ); 38004 38005 } 38006 38007 this._loopCount = loopCount; 38008 38009 this._mixer.dispatchEvent( { 38010 type: 'loop', action: this, loopDelta: loopDelta 38011 } ); 38012 38013 } 38014 38015 } 38016 38017 if ( pingPong && ( loopCount & 1 ) === 1 ) { 38018 // invert time for the "pong round" 38019 38020 this.time = time; 38021 return duration - time; 38022 38023 } 38024 38025 } 38026 38027 this.time = time; 38028 return time; 38029 38030 }, 38031 38032 _setEndings: function( atStart, atEnd, pingPong ) { 38033 38034 var settings = this._interpolantSettings; 38035 38036 if ( pingPong ) { 38037 38038 settings.endingStart = ZeroSlopeEnding; 38039 settings.endingEnd = ZeroSlopeEnding; 38040 38041 } else { 38042 38043 // assuming for LoopOnce atStart == atEnd == true 38044 38045 if ( atStart ) { 38046 38047 settings.endingStart = this.zeroSlopeAtStart ? 38048 ZeroSlopeEnding : ZeroCurvatureEnding; 38049 38050 } else { 38051 38052 settings.endingStart = WrapAroundEnding; 38053 38054 } 38055 38056 if ( atEnd ) { 38057 38058 settings.endingEnd = this.zeroSlopeAtEnd ? 38059 ZeroSlopeEnding : ZeroCurvatureEnding; 38060 38061 } else { 38062 38063 settings.endingEnd = WrapAroundEnding; 38064 38065 } 38066 38067 } 38068 38069 }, 38070 38071 _scheduleFading: function( duration, weightNow, weightThen ) { 38072 38073 var mixer = this._mixer, now = mixer.time, 38074 interpolant = this._weightInterpolant; 38075 38076 if ( interpolant === null ) { 38077 38078 interpolant = mixer._lendControlInterpolant(); 38079 this._weightInterpolant = interpolant; 38080 38081 } 38082 38083 var times = interpolant.parameterPositions, 38084 values = interpolant.sampleValues; 38085 38086 times[ 0 ] = now; values[ 0 ] = weightNow; 38087 times[ 1 ] = now + duration; values[ 1 ] = weightThen; 38088 38089 return this; 38090 38091 } 38092 38093 }; 38094 38095 /** 38096 * 38097 * Player for AnimationClips. 38098 * 38099 * 38100 * @author Ben Houston / http://clara.io/ 38101 * @author David Sarno / http://lighthaus.us/ 38102 * @author tschw 38103 */ 38104 38105 function AnimationMixer( root ) { 38106 38107 this._root = root; 38108 this._initMemoryManager(); 38109 this._accuIndex = 0; 38110 38111 this.time = 0; 38112 38113 this.timeScale = 1.0; 38114 38115 } 38116 38117 AnimationMixer.prototype = { 38118 38119 constructor: AnimationMixer, 38120 38121 // return an action for a clip optionally using a custom root target 38122 // object (this method allocates a lot of dynamic memory in case a 38123 // previously unknown clip/root combination is specified) 38124 clipAction: function ( clip, optionalRoot ) { 38125 38126 var root = optionalRoot || this._root, 38127 rootUuid = root.uuid, 38128 38129 clipObject = typeof clip === 'string' ? 38130 AnimationClip.findByName( root, clip ) : clip, 38131 38132 clipUuid = clipObject !== null ? clipObject.uuid : clip, 38133 38134 actionsForClip = this._actionsByClip[ clipUuid ], 38135 prototypeAction = null; 38136 38137 if ( actionsForClip !== undefined ) { 38138 38139 var existingAction = 38140 actionsForClip.actionByRoot[ rootUuid ]; 38141 38142 if ( existingAction !== undefined ) { 38143 38144 return existingAction; 38145 38146 } 38147 38148 // we know the clip, so we don't have to parse all 38149 // the bindings again but can just copy 38150 prototypeAction = actionsForClip.knownActions[ 0 ]; 38151 38152 // also, take the clip from the prototype action 38153 if ( clipObject === null ) 38154 clipObject = prototypeAction._clip; 38155 38156 } 38157 38158 // clip must be known when specified via string 38159 if ( clipObject === null ) return null; 38160 38161 // allocate all resources required to run it 38162 var newAction = new AnimationAction( this, clipObject, optionalRoot ); 38163 38164 this._bindAction( newAction, prototypeAction ); 38165 38166 // and make the action known to the memory manager 38167 this._addInactiveAction( newAction, clipUuid, rootUuid ); 38168 38169 return newAction; 38170 38171 }, 38172 38173 // get an existing action 38174 existingAction: function ( clip, optionalRoot ) { 38175 38176 var root = optionalRoot || this._root, 38177 rootUuid = root.uuid, 38178 38179 clipObject = typeof clip === 'string' ? 38180 AnimationClip.findByName( root, clip ) : clip, 38181 38182 clipUuid = clipObject ? clipObject.uuid : clip, 38183 38184 actionsForClip = this._actionsByClip[ clipUuid ]; 38185 38186 if ( actionsForClip !== undefined ) { 38187 38188 return actionsForClip.actionByRoot[ rootUuid ] || null; 38189 38190 } 38191 38192 return null; 38193 38194 }, 38195 38196 // deactivates all previously scheduled actions 38197 stopAllAction: function () { 38198 38199 var actions = this._actions, 38200 nActions = this._nActiveActions, 38201 bindings = this._bindings, 38202 nBindings = this._nActiveBindings; 38203 38204 this._nActiveActions = 0; 38205 this._nActiveBindings = 0; 38206 38207 for ( var i = 0; i !== nActions; ++ i ) { 38208 38209 actions[ i ].reset(); 38210 38211 } 38212 38213 for ( var i = 0; i !== nBindings; ++ i ) { 38214 38215 bindings[ i ].useCount = 0; 38216 38217 } 38218 38219 return this; 38220 38221 }, 38222 38223 // advance the time and update apply the animation 38224 update: function ( deltaTime ) { 38225 38226 deltaTime *= this.timeScale; 38227 38228 var actions = this._actions, 38229 nActions = this._nActiveActions, 38230 38231 time = this.time += deltaTime, 38232 timeDirection = Math.sign( deltaTime ), 38233 38234 accuIndex = this._accuIndex ^= 1; 38235 38236 // run active actions 38237 38238 for ( var i = 0; i !== nActions; ++ i ) { 38239 38240 var action = actions[ i ]; 38241 38242 if ( action.enabled ) { 38243 38244 action._update( time, deltaTime, timeDirection, accuIndex ); 38245 38246 } 38247 38248 } 38249 38250 // update scene graph 38251 38252 var bindings = this._bindings, 38253 nBindings = this._nActiveBindings; 38254 38255 for ( var i = 0; i !== nBindings; ++ i ) { 38256 38257 bindings[ i ].apply( accuIndex ); 38258 38259 } 38260 38261 return this; 38262 38263 }, 38264 38265 // return this mixer's root target object 38266 getRoot: function () { 38267 38268 return this._root; 38269 38270 }, 38271 38272 // free all resources specific to a particular clip 38273 uncacheClip: function ( clip ) { 38274 38275 var actions = this._actions, 38276 clipUuid = clip.uuid, 38277 actionsByClip = this._actionsByClip, 38278 actionsForClip = actionsByClip[ clipUuid ]; 38279 38280 if ( actionsForClip !== undefined ) { 38281 38282 // note: just calling _removeInactiveAction would mess up the 38283 // iteration state and also require updating the state we can 38284 // just throw away 38285 38286 var actionsToRemove = actionsForClip.knownActions; 38287 38288 for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { 38289 38290 var action = actionsToRemove[ i ]; 38291 38292 this._deactivateAction( action ); 38293 38294 var cacheIndex = action._cacheIndex, 38295 lastInactiveAction = actions[ actions.length - 1 ]; 38296 38297 action._cacheIndex = null; 38298 action._byClipCacheIndex = null; 38299 38300 lastInactiveAction._cacheIndex = cacheIndex; 38301 actions[ cacheIndex ] = lastInactiveAction; 38302 actions.pop(); 38303 38304 this._removeInactiveBindingsForAction( action ); 38305 38306 } 38307 38308 delete actionsByClip[ clipUuid ]; 38309 38310 } 38311 38312 }, 38313 38314 // free all resources specific to a particular root target object 38315 uncacheRoot: function ( root ) { 38316 38317 var rootUuid = root.uuid, 38318 actionsByClip = this._actionsByClip; 38319 38320 for ( var clipUuid in actionsByClip ) { 38321 38322 var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, 38323 action = actionByRoot[ rootUuid ]; 38324 38325 if ( action !== undefined ) { 38326 38327 this._deactivateAction( action ); 38328 this._removeInactiveAction( action ); 38329 38330 } 38331 38332 } 38333 38334 var bindingsByRoot = this._bindingsByRootAndName, 38335 bindingByName = bindingsByRoot[ rootUuid ]; 38336 38337 if ( bindingByName !== undefined ) { 38338 38339 for ( var trackName in bindingByName ) { 38340 38341 var binding = bindingByName[ trackName ]; 38342 binding.restoreOriginalState(); 38343 this._removeInactiveBinding( binding ); 38344 38345 } 38346 38347 } 38348 38349 }, 38350 38351 // remove a targeted clip from the cache 38352 uncacheAction: function ( clip, optionalRoot ) { 38353 38354 var action = this.existingAction( clip, optionalRoot ); 38355 38356 if ( action !== null ) { 38357 38358 this._deactivateAction( action ); 38359 this._removeInactiveAction( action ); 38360 38361 } 38362 38363 } 38364 38365 }; 38366 38367 // Implementation details: 38368 38369 Object.assign( AnimationMixer.prototype, { 38370 38371 _bindAction: function ( action, prototypeAction ) { 38372 38373 var root = action._localRoot || this._root, 38374 tracks = action._clip.tracks, 38375 nTracks = tracks.length, 38376 bindings = action._propertyBindings, 38377 interpolants = action._interpolants, 38378 rootUuid = root.uuid, 38379 bindingsByRoot = this._bindingsByRootAndName, 38380 bindingsByName = bindingsByRoot[ rootUuid ]; 38381 38382 if ( bindingsByName === undefined ) { 38383 38384 bindingsByName = {}; 38385 bindingsByRoot[ rootUuid ] = bindingsByName; 38386 38387 } 38388 38389 for ( var i = 0; i !== nTracks; ++ i ) { 38390 38391 var track = tracks[ i ], 38392 trackName = track.name, 38393 binding = bindingsByName[ trackName ]; 38394 38395 if ( binding !== undefined ) { 38396 38397 bindings[ i ] = binding; 38398 38399 } else { 38400 38401 binding = bindings[ i ]; 38402 38403 if ( binding !== undefined ) { 38404 38405 // existing binding, make sure the cache knows 38406 38407 if ( binding._cacheIndex === null ) { 38408 38409 ++ binding.referenceCount; 38410 this._addInactiveBinding( binding, rootUuid, trackName ); 38411 38412 } 38413 38414 continue; 38415 38416 } 38417 38418 var path = prototypeAction && prototypeAction. 38419 _propertyBindings[ i ].binding.parsedPath; 38420 38421 binding = new PropertyMixer( 38422 PropertyBinding.create( root, trackName, path ), 38423 track.ValueTypeName, track.getValueSize() ); 38424 38425 ++ binding.referenceCount; 38426 this._addInactiveBinding( binding, rootUuid, trackName ); 38427 38428 bindings[ i ] = binding; 38429 38430 } 38431 38432 interpolants[ i ].resultBuffer = binding.buffer; 38433 38434 } 38435 38436 }, 38437 38438 _activateAction: function ( action ) { 38439 38440 if ( ! this._isActiveAction( action ) ) { 38441 38442 if ( action._cacheIndex === null ) { 38443 38444 // this action has been forgotten by the cache, but the user 38445 // appears to be still using it -> rebind 38446 38447 var rootUuid = ( action._localRoot || this._root ).uuid, 38448 clipUuid = action._clip.uuid, 38449 actionsForClip = this._actionsByClip[ clipUuid ]; 38450 38451 this._bindAction( action, 38452 actionsForClip && actionsForClip.knownActions[ 0 ] ); 38453 38454 this._addInactiveAction( action, clipUuid, rootUuid ); 38455 38456 } 38457 38458 var bindings = action._propertyBindings; 38459 38460 // increment reference counts / sort out state 38461 for ( var i = 0, n = bindings.length; i !== n; ++ i ) { 38462 38463 var binding = bindings[ i ]; 38464 38465 if ( binding.useCount ++ === 0 ) { 38466 38467 this._lendBinding( binding ); 38468 binding.saveOriginalState(); 38469 38470 } 38471 38472 } 38473 38474 this._lendAction( action ); 38475 38476 } 38477 38478 }, 38479 38480 _deactivateAction: function ( action ) { 38481 38482 if ( this._isActiveAction( action ) ) { 38483 38484 var bindings = action._propertyBindings; 38485 38486 // decrement reference counts / sort out state 38487 for ( var i = 0, n = bindings.length; i !== n; ++ i ) { 38488 38489 var binding = bindings[ i ]; 38490 38491 if ( -- binding.useCount === 0 ) { 38492 38493 binding.restoreOriginalState(); 38494 this._takeBackBinding( binding ); 38495 38496 } 38497 38498 } 38499 38500 this._takeBackAction( action ); 38501 38502 } 38503 38504 }, 38505 38506 // Memory manager 38507 38508 _initMemoryManager: function () { 38509 38510 this._actions = []; // 'nActiveActions' followed by inactive ones 38511 this._nActiveActions = 0; 38512 38513 this._actionsByClip = {}; 38514 // inside: 38515 // { 38516 // knownActions: Array< AnimationAction > - used as prototypes 38517 // actionByRoot: AnimationAction - lookup 38518 // } 38519 38520 38521 this._bindings = []; // 'nActiveBindings' followed by inactive ones 38522 this._nActiveBindings = 0; 38523 38524 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > 38525 38526 38527 this._controlInterpolants = []; // same game as above 38528 this._nActiveControlInterpolants = 0; 38529 38530 var scope = this; 38531 38532 this.stats = { 38533 38534 actions: { 38535 get total() { return scope._actions.length; }, 38536 get inUse() { return scope._nActiveActions; } 38537 }, 38538 bindings: { 38539 get total() { return scope._bindings.length; }, 38540 get inUse() { return scope._nActiveBindings; } 38541 }, 38542 controlInterpolants: { 38543 get total() { return scope._controlInterpolants.length; }, 38544 get inUse() { return scope._nActiveControlInterpolants; } 38545 } 38546 38547 }; 38548 38549 }, 38550 38551 // Memory management for AnimationAction objects 38552 38553 _isActiveAction: function ( action ) { 38554 38555 var index = action._cacheIndex; 38556 return index !== null && index < this._nActiveActions; 38557 38558 }, 38559 38560 _addInactiveAction: function ( action, clipUuid, rootUuid ) { 38561 38562 var actions = this._actions, 38563 actionsByClip = this._actionsByClip, 38564 actionsForClip = actionsByClip[ clipUuid ]; 38565 38566 if ( actionsForClip === undefined ) { 38567 38568 actionsForClip = { 38569 38570 knownActions: [ action ], 38571 actionByRoot: {} 38572 38573 }; 38574 38575 action._byClipCacheIndex = 0; 38576 38577 actionsByClip[ clipUuid ] = actionsForClip; 38578 38579 } else { 38580 38581 var knownActions = actionsForClip.knownActions; 38582 38583 action._byClipCacheIndex = knownActions.length; 38584 knownActions.push( action ); 38585 38586 } 38587 38588 action._cacheIndex = actions.length; 38589 actions.push( action ); 38590 38591 actionsForClip.actionByRoot[ rootUuid ] = action; 38592 38593 }, 38594 38595 _removeInactiveAction: function ( action ) { 38596 38597 var actions = this._actions, 38598 lastInactiveAction = actions[ actions.length - 1 ], 38599 cacheIndex = action._cacheIndex; 38600 38601 lastInactiveAction._cacheIndex = cacheIndex; 38602 actions[ cacheIndex ] = lastInactiveAction; 38603 actions.pop(); 38604 38605 action._cacheIndex = null; 38606 38607 38608 var clipUuid = action._clip.uuid, 38609 actionsByClip = this._actionsByClip, 38610 actionsForClip = actionsByClip[ clipUuid ], 38611 knownActionsForClip = actionsForClip.knownActions, 38612 38613 lastKnownAction = 38614 knownActionsForClip[ knownActionsForClip.length - 1 ], 38615 38616 byClipCacheIndex = action._byClipCacheIndex; 38617 38618 lastKnownAction._byClipCacheIndex = byClipCacheIndex; 38619 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; 38620 knownActionsForClip.pop(); 38621 38622 action._byClipCacheIndex = null; 38623 38624 38625 var actionByRoot = actionsForClip.actionByRoot, 38626 rootUuid = ( actions._localRoot || this._root ).uuid; 38627 38628 delete actionByRoot[ rootUuid ]; 38629 38630 if ( knownActionsForClip.length === 0 ) { 38631 38632 delete actionsByClip[ clipUuid ]; 38633 38634 } 38635 38636 this._removeInactiveBindingsForAction( action ); 38637 38638 }, 38639 38640 _removeInactiveBindingsForAction: function ( action ) { 38641 38642 var bindings = action._propertyBindings; 38643 for ( var i = 0, n = bindings.length; i !== n; ++ i ) { 38644 38645 var binding = bindings[ i ]; 38646 38647 if ( -- binding.referenceCount === 0 ) { 38648 38649 this._removeInactiveBinding( binding ); 38650 38651 } 38652 38653 } 38654 38655 }, 38656 38657 _lendAction: function ( action ) { 38658 38659 // [ active actions | inactive actions ] 38660 // [ active actions >| inactive actions ] 38661 // s a 38662 // <-swap-> 38663 // a s 38664 38665 var actions = this._actions, 38666 prevIndex = action._cacheIndex, 38667 38668 lastActiveIndex = this._nActiveActions ++, 38669 38670 firstInactiveAction = actions[ lastActiveIndex ]; 38671 38672 action._cacheIndex = lastActiveIndex; 38673 actions[ lastActiveIndex ] = action; 38674 38675 firstInactiveAction._cacheIndex = prevIndex; 38676 actions[ prevIndex ] = firstInactiveAction; 38677 38678 }, 38679 38680 _takeBackAction: function ( action ) { 38681 38682 // [ active actions | inactive actions ] 38683 // [ active actions |< inactive actions ] 38684 // a s 38685 // <-swap-> 38686 // s a 38687 38688 var actions = this._actions, 38689 prevIndex = action._cacheIndex, 38690 38691 firstInactiveIndex = -- this._nActiveActions, 38692 38693 lastActiveAction = actions[ firstInactiveIndex ]; 38694 38695 action._cacheIndex = firstInactiveIndex; 38696 actions[ firstInactiveIndex ] = action; 38697 38698 lastActiveAction._cacheIndex = prevIndex; 38699 actions[ prevIndex ] = lastActiveAction; 38700 38701 }, 38702 38703 // Memory management for PropertyMixer objects 38704 38705 _addInactiveBinding: function ( binding, rootUuid, trackName ) { 38706 38707 var bindingsByRoot = this._bindingsByRootAndName, 38708 bindingByName = bindingsByRoot[ rootUuid ], 38709 38710 bindings = this._bindings; 38711 38712 if ( bindingByName === undefined ) { 38713 38714 bindingByName = {}; 38715 bindingsByRoot[ rootUuid ] = bindingByName; 38716 38717 } 38718 38719 bindingByName[ trackName ] = binding; 38720 38721 binding._cacheIndex = bindings.length; 38722 bindings.push( binding ); 38723 38724 }, 38725 38726 _removeInactiveBinding: function ( binding ) { 38727 38728 var bindings = this._bindings, 38729 propBinding = binding.binding, 38730 rootUuid = propBinding.rootNode.uuid, 38731 trackName = propBinding.path, 38732 bindingsByRoot = this._bindingsByRootAndName, 38733 bindingByName = bindingsByRoot[ rootUuid ], 38734 38735 lastInactiveBinding = bindings[ bindings.length - 1 ], 38736 cacheIndex = binding._cacheIndex; 38737 38738 lastInactiveBinding._cacheIndex = cacheIndex; 38739 bindings[ cacheIndex ] = lastInactiveBinding; 38740 bindings.pop(); 38741 38742 delete bindingByName[ trackName ]; 38743 38744 remove_empty_map: { 38745 38746 for ( var _ in bindingByName ) break remove_empty_map; 38747 38748 delete bindingsByRoot[ rootUuid ]; 38749 38750 } 38751 38752 }, 38753 38754 _lendBinding: function ( binding ) { 38755 38756 var bindings = this._bindings, 38757 prevIndex = binding._cacheIndex, 38758 38759 lastActiveIndex = this._nActiveBindings ++, 38760 38761 firstInactiveBinding = bindings[ lastActiveIndex ]; 38762 38763 binding._cacheIndex = lastActiveIndex; 38764 bindings[ lastActiveIndex ] = binding; 38765 38766 firstInactiveBinding._cacheIndex = prevIndex; 38767 bindings[ prevIndex ] = firstInactiveBinding; 38768 38769 }, 38770 38771 _takeBackBinding: function ( binding ) { 38772 38773 var bindings = this._bindings, 38774 prevIndex = binding._cacheIndex, 38775 38776 firstInactiveIndex = -- this._nActiveBindings, 38777 38778 lastActiveBinding = bindings[ firstInactiveIndex ]; 38779 38780 binding._cacheIndex = firstInactiveIndex; 38781 bindings[ firstInactiveIndex ] = binding; 38782 38783 lastActiveBinding._cacheIndex = prevIndex; 38784 bindings[ prevIndex ] = lastActiveBinding; 38785 38786 }, 38787 38788 38789 // Memory management of Interpolants for weight and time scale 38790 38791 _lendControlInterpolant: function () { 38792 38793 var interpolants = this._controlInterpolants, 38794 lastActiveIndex = this._nActiveControlInterpolants ++, 38795 interpolant = interpolants[ lastActiveIndex ]; 38796 38797 if ( interpolant === undefined ) { 38798 38799 interpolant = new LinearInterpolant( 38800 new Float32Array( 2 ), new Float32Array( 2 ), 38801 1, this._controlInterpolantsResultBuffer ); 38802 38803 interpolant.__cacheIndex = lastActiveIndex; 38804 interpolants[ lastActiveIndex ] = interpolant; 38805 38806 } 38807 38808 return interpolant; 38809 38810 }, 38811 38812 _takeBackControlInterpolant: function ( interpolant ) { 38813 38814 var interpolants = this._controlInterpolants, 38815 prevIndex = interpolant.__cacheIndex, 38816 38817 firstInactiveIndex = -- this._nActiveControlInterpolants, 38818 38819 lastActiveInterpolant = interpolants[ firstInactiveIndex ]; 38820 38821 interpolant.__cacheIndex = firstInactiveIndex; 38822 interpolants[ firstInactiveIndex ] = interpolant; 38823 38824 lastActiveInterpolant.__cacheIndex = prevIndex; 38825 interpolants[ prevIndex ] = lastActiveInterpolant; 38826 38827 }, 38828 38829 _controlInterpolantsResultBuffer: new Float32Array( 1 ) 38830 38831 } ); 38832 38833 Object.assign( AnimationMixer.prototype, EventDispatcher.prototype ); 38834 38835 /** 38836 * @author mrdoob / http://mrdoob.com/ 38837 */ 38838 38839 function Uniform( value ) { 38840 38841 if ( typeof value === 'string' ) { 38842 38843 console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); 38844 value = arguments[ 1 ]; 38845 38846 } 38847 38848 this.value = value; 38849 38850 } 38851 38852 Uniform.prototype.clone = function () { 38853 38854 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); 38855 38856 }; 38857 38858 /** 38859 * @author benaadams / https://twitter.com/ben_a_adams 38860 */ 38861 38862 function InstancedBufferGeometry() { 38863 38864 BufferGeometry.call( this ); 38865 38866 this.type = 'InstancedBufferGeometry'; 38867 this.maxInstancedCount = undefined; 38868 38869 } 38870 38871 InstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); 38872 InstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry; 38873 38874 InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true; 38875 38876 InstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) { 38877 38878 this.groups.push( { 38879 38880 start: start, 38881 count: count, 38882 materialIndex: materialIndex 38883 38884 } ); 38885 38886 }; 38887 38888 InstancedBufferGeometry.prototype.copy = function ( source ) { 38889 38890 var index = source.index; 38891 38892 if ( index !== null ) { 38893 38894 this.setIndex( index.clone() ); 38895 38896 } 38897 38898 var attributes = source.attributes; 38899 38900 for ( var name in attributes ) { 38901 38902 var attribute = attributes[ name ]; 38903 this.addAttribute( name, attribute.clone() ); 38904 38905 } 38906 38907 var groups = source.groups; 38908 38909 for ( var i = 0, l = groups.length; i < l; i ++ ) { 38910 38911 var group = groups[ i ]; 38912 this.addGroup( group.start, group.count, group.materialIndex ); 38913 38914 } 38915 38916 return this; 38917 38918 }; 38919 38920 /** 38921 * @author benaadams / https://twitter.com/ben_a_adams 38922 */ 38923 38924 function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { 38925 38926 this.uuid = _Math.generateUUID(); 38927 38928 this.data = interleavedBuffer; 38929 this.itemSize = itemSize; 38930 this.offset = offset; 38931 38932 this.normalized = normalized === true; 38933 38934 } 38935 38936 38937 InterleavedBufferAttribute.prototype = { 38938 38939 constructor: InterleavedBufferAttribute, 38940 38941 isInterleavedBufferAttribute: true, 38942 38943 get count() { 38944 38945 return this.data.count; 38946 38947 }, 38948 38949 get array() { 38950 38951 return this.data.array; 38952 38953 }, 38954 38955 setX: function ( index, x ) { 38956 38957 this.data.array[ index * this.data.stride + this.offset ] = x; 38958 38959 return this; 38960 38961 }, 38962 38963 setY: function ( index, y ) { 38964 38965 this.data.array[ index * this.data.stride + this.offset + 1 ] = y; 38966 38967 return this; 38968 38969 }, 38970 38971 setZ: function ( index, z ) { 38972 38973 this.data.array[ index * this.data.stride + this.offset + 2 ] = z; 38974 38975 return this; 38976 38977 }, 38978 38979 setW: function ( index, w ) { 38980 38981 this.data.array[ index * this.data.stride + this.offset + 3 ] = w; 38982 38983 return this; 38984 38985 }, 38986 38987 getX: function ( index ) { 38988 38989 return this.data.array[ index * this.data.stride + this.offset ]; 38990 38991 }, 38992 38993 getY: function ( index ) { 38994 38995 return this.data.array[ index * this.data.stride + this.offset + 1 ]; 38996 38997 }, 38998 38999 getZ: function ( index ) { 39000 39001 return this.data.array[ index * this.data.stride + this.offset + 2 ]; 39002 39003 }, 39004 39005 getW: function ( index ) { 39006 39007 return this.data.array[ index * this.data.stride + this.offset + 3 ]; 39008 39009 }, 39010 39011 setXY: function ( index, x, y ) { 39012 39013 index = index * this.data.stride + this.offset; 39014 39015 this.data.array[ index + 0 ] = x; 39016 this.data.array[ index + 1 ] = y; 39017 39018 return this; 39019 39020 }, 39021 39022 setXYZ: function ( index, x, y, z ) { 39023 39024 index = index * this.data.stride + this.offset; 39025 39026 this.data.array[ index + 0 ] = x; 39027 this.data.array[ index + 1 ] = y; 39028 this.data.array[ index + 2 ] = z; 39029 39030 return this; 39031 39032 }, 39033 39034 setXYZW: function ( index, x, y, z, w ) { 39035 39036 index = index * this.data.stride + this.offset; 39037 39038 this.data.array[ index + 0 ] = x; 39039 this.data.array[ index + 1 ] = y; 39040 this.data.array[ index + 2 ] = z; 39041 this.data.array[ index + 3 ] = w; 39042 39043 return this; 39044 39045 } 39046 39047 }; 39048 39049 /** 39050 * @author benaadams / https://twitter.com/ben_a_adams 39051 */ 39052 39053 function InterleavedBuffer( array, stride ) { 39054 39055 this.uuid = _Math.generateUUID(); 39056 39057 this.array = array; 39058 this.stride = stride; 39059 this.count = array !== undefined ? array.length / stride : 0; 39060 39061 this.dynamic = false; 39062 this.updateRange = { offset: 0, count: - 1 }; 39063 39064 this.onUploadCallback = function () {}; 39065 39066 this.version = 0; 39067 39068 } 39069 39070 InterleavedBuffer.prototype = { 39071 39072 constructor: InterleavedBuffer, 39073 39074 isInterleavedBuffer: true, 39075 39076 set needsUpdate( value ) { 39077 39078 if ( value === true ) this.version ++; 39079 39080 }, 39081 39082 setArray: function ( array ) { 39083 39084 if ( Array.isArray( array ) ) { 39085 39086 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 39087 39088 } 39089 39090 this.count = array !== undefined ? array.length / this.stride : 0; 39091 this.array = array; 39092 39093 }, 39094 39095 setDynamic: function ( value ) { 39096 39097 this.dynamic = value; 39098 39099 return this; 39100 39101 }, 39102 39103 copy: function ( source ) { 39104 39105 this.array = new source.array.constructor( source.array ); 39106 this.count = source.count; 39107 this.stride = source.stride; 39108 this.dynamic = source.dynamic; 39109 39110 return this; 39111 39112 }, 39113 39114 copyAt: function ( index1, attribute, index2 ) { 39115 39116 index1 *= this.stride; 39117 index2 *= attribute.stride; 39118 39119 for ( var i = 0, l = this.stride; i < l; i ++ ) { 39120 39121 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 39122 39123 } 39124 39125 return this; 39126 39127 }, 39128 39129 set: function ( value, offset ) { 39130 39131 if ( offset === undefined ) offset = 0; 39132 39133 this.array.set( value, offset ); 39134 39135 return this; 39136 39137 }, 39138 39139 clone: function () { 39140 39141 return new this.constructor().copy( this ); 39142 39143 }, 39144 39145 onUpload: function ( callback ) { 39146 39147 this.onUploadCallback = callback; 39148 39149 return this; 39150 39151 } 39152 39153 }; 39154 39155 /** 39156 * @author benaadams / https://twitter.com/ben_a_adams 39157 */ 39158 39159 function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { 39160 39161 InterleavedBuffer.call( this, array, stride ); 39162 39163 this.meshPerAttribute = meshPerAttribute || 1; 39164 39165 } 39166 39167 InstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype ); 39168 InstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer; 39169 39170 InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true; 39171 39172 InstancedInterleavedBuffer.prototype.copy = function ( source ) { 39173 39174 InterleavedBuffer.prototype.copy.call( this, source ); 39175 39176 this.meshPerAttribute = source.meshPerAttribute; 39177 39178 return this; 39179 39180 }; 39181 39182 /** 39183 * @author benaadams / https://twitter.com/ben_a_adams 39184 */ 39185 39186 function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) { 39187 39188 BufferAttribute.call( this, array, itemSize ); 39189 39190 this.meshPerAttribute = meshPerAttribute || 1; 39191 39192 } 39193 39194 InstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); 39195 InstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute; 39196 39197 InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true; 39198 39199 InstancedBufferAttribute.prototype.copy = function ( source ) { 39200 39201 BufferAttribute.prototype.copy.call( this, source ); 39202 39203 this.meshPerAttribute = source.meshPerAttribute; 39204 39205 return this; 39206 39207 }; 39208 39209 /** 39210 * @author mrdoob / http://mrdoob.com/ 39211 * @author bhouston / http://clara.io/ 39212 * @author stephomi / http://stephaneginier.com/ 39213 */ 39214 39215 function Raycaster( origin, direction, near, far ) { 39216 39217 this.ray = new Ray( origin, direction ); 39218 // direction is assumed to be normalized (for accurate distance calculations) 39219 39220 this.near = near || 0; 39221 this.far = far || Infinity; 39222 39223 this.params = { 39224 Mesh: {}, 39225 Line: {}, 39226 LOD: {}, 39227 Points: { threshold: 1 }, 39228 Sprite: {} 39229 }; 39230 39231 Object.defineProperties( this.params, { 39232 PointCloud: { 39233 get: function () { 39234 console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); 39235 return this.Points; 39236 } 39237 } 39238 } ); 39239 39240 } 39241 39242 function ascSort( a, b ) { 39243 39244 return a.distance - b.distance; 39245 39246 } 39247 39248 function intersectObject( object, raycaster, intersects, recursive ) { 39249 39250 if ( object.visible === false ) return; 39251 39252 object.raycast( raycaster, intersects ); 39253 39254 if ( recursive === true ) { 39255 39256 var children = object.children; 39257 39258 for ( var i = 0, l = children.length; i < l; i ++ ) { 39259 39260 intersectObject( children[ i ], raycaster, intersects, true ); 39261 39262 } 39263 39264 } 39265 39266 } 39267 39268 // 39269 39270 Raycaster.prototype = { 39271 39272 constructor: Raycaster, 39273 39274 linePrecision: 1, 39275 39276 set: function ( origin, direction ) { 39277 39278 // direction is assumed to be normalized (for accurate distance calculations) 39279 39280 this.ray.set( origin, direction ); 39281 39282 }, 39283 39284 setFromCamera: function ( coords, camera ) { 39285 39286 if ( (camera && camera.isPerspectiveCamera) ) { 39287 39288 this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); 39289 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); 39290 39291 } else if ( (camera && camera.isOrthographicCamera) ) { 39292 39293 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera 39294 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); 39295 39296 } else { 39297 39298 console.error( 'THREE.Raycaster: Unsupported camera type.' ); 39299 39300 } 39301 39302 }, 39303 39304 intersectObject: function ( object, recursive ) { 39305 39306 var intersects = []; 39307 39308 intersectObject( object, this, intersects, recursive ); 39309 39310 intersects.sort( ascSort ); 39311 39312 return intersects; 39313 39314 }, 39315 39316 intersectObjects: function ( objects, recursive ) { 39317 39318 var intersects = []; 39319 39320 if ( Array.isArray( objects ) === false ) { 39321 39322 console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); 39323 return intersects; 39324 39325 } 39326 39327 for ( var i = 0, l = objects.length; i < l; i ++ ) { 39328 39329 intersectObject( objects[ i ], this, intersects, recursive ); 39330 39331 } 39332 39333 intersects.sort( ascSort ); 39334 39335 return intersects; 39336 39337 } 39338 39339 }; 39340 39341 /** 39342 * @author alteredq / http://alteredqualia.com/ 39343 */ 39344 39345 function Clock( autoStart ) { 39346 39347 this.autoStart = ( autoStart !== undefined ) ? autoStart : true; 39348 39349 this.startTime = 0; 39350 this.oldTime = 0; 39351 this.elapsedTime = 0; 39352 39353 this.running = false; 39354 39355 } 39356 39357 Clock.prototype = { 39358 39359 constructor: Clock, 39360 39361 start: function () { 39362 39363 this.startTime = ( performance || Date ).now(); 39364 39365 this.oldTime = this.startTime; 39366 this.elapsedTime = 0; 39367 this.running = true; 39368 39369 }, 39370 39371 stop: function () { 39372 39373 this.getElapsedTime(); 39374 this.running = false; 39375 39376 }, 39377 39378 getElapsedTime: function () { 39379 39380 this.getDelta(); 39381 return this.elapsedTime; 39382 39383 }, 39384 39385 getDelta: function () { 39386 39387 var diff = 0; 39388 39389 if ( this.autoStart && ! this.running ) { 39390 39391 this.start(); 39392 39393 } 39394 39395 if ( this.running ) { 39396 39397 var newTime = ( performance || Date ).now(); 39398 39399 diff = ( newTime - this.oldTime ) / 1000; 39400 this.oldTime = newTime; 39401 39402 this.elapsedTime += diff; 39403 39404 } 39405 39406 return diff; 39407 39408 } 39409 39410 }; 39411 39412 /** 39413 * @author bhouston / http://clara.io 39414 * @author WestLangley / http://github.com/WestLangley 39415 * 39416 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system 39417 * 39418 * The poles (phi) are at the positive and negative y axis. 39419 * The equator starts at positive z. 39420 */ 39421 39422 function Spherical( radius, phi, theta ) { 39423 39424 this.radius = ( radius !== undefined ) ? radius : 1.0; 39425 this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole 39426 this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere 39427 39428 return this; 39429 39430 } 39431 39432 Spherical.prototype = { 39433 39434 constructor: Spherical, 39435 39436 set: function ( radius, phi, theta ) { 39437 39438 this.radius = radius; 39439 this.phi = phi; 39440 this.theta = theta; 39441 39442 return this; 39443 39444 }, 39445 39446 clone: function () { 39447 39448 return new this.constructor().copy( this ); 39449 39450 }, 39451 39452 copy: function ( other ) { 39453 39454 this.radius = other.radius; 39455 this.phi = other.phi; 39456 this.theta = other.theta; 39457 39458 return this; 39459 39460 }, 39461 39462 // restrict phi to be betwee EPS and PI-EPS 39463 makeSafe: function() { 39464 39465 var EPS = 0.000001; 39466 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); 39467 39468 return this; 39469 39470 }, 39471 39472 setFromVector3: function( vec3 ) { 39473 39474 this.radius = vec3.length(); 39475 39476 if ( this.radius === 0 ) { 39477 39478 this.theta = 0; 39479 this.phi = 0; 39480 39481 } else { 39482 39483 this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis 39484 this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle 39485 39486 } 39487 39488 return this; 39489 39490 } 39491 39492 }; 39493 39494 /** 39495 * @author Mugen87 / https://github.com/Mugen87 39496 * 39497 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system 39498 * 39499 */ 39500 39501 function Cylindrical( radius, theta, y ) { 39502 39503 this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane 39504 this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis 39505 this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane 39506 39507 return this; 39508 39509 } 39510 39511 Cylindrical.prototype = { 39512 39513 constructor: Cylindrical, 39514 39515 set: function ( radius, theta, y ) { 39516 39517 this.radius = radius; 39518 this.theta = theta; 39519 this.y = y; 39520 39521 return this; 39522 39523 }, 39524 39525 clone: function () { 39526 39527 return new this.constructor().copy( this ); 39528 39529 }, 39530 39531 copy: function ( other ) { 39532 39533 this.radius = other.radius; 39534 this.theta = other.theta; 39535 this.y = other.y; 39536 39537 return this; 39538 39539 }, 39540 39541 setFromVector3: function( vec3 ) { 39542 39543 this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z ); 39544 this.theta = Math.atan2( vec3.x, vec3.z ); 39545 this.y = vec3.y; 39546 39547 return this; 39548 39549 } 39550 39551 }; 39552 39553 /** 39554 * @author alteredq / http://alteredqualia.com/ 39555 */ 39556 39557 function MorphBlendMesh( geometry, material ) { 39558 39559 Mesh.call( this, geometry, material ); 39560 39561 this.animationsMap = {}; 39562 this.animationsList = []; 39563 39564 // prepare default animation 39565 // (all frames played together in 1 second) 39566 39567 var numFrames = this.geometry.morphTargets.length; 39568 39569 var name = "__default"; 39570 39571 var startFrame = 0; 39572 var endFrame = numFrames - 1; 39573 39574 var fps = numFrames / 1; 39575 39576 this.createAnimation( name, startFrame, endFrame, fps ); 39577 this.setAnimationWeight( name, 1 ); 39578 39579 } 39580 39581 MorphBlendMesh.prototype = Object.create( Mesh.prototype ); 39582 MorphBlendMesh.prototype.constructor = MorphBlendMesh; 39583 39584 MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { 39585 39586 var animation = { 39587 39588 start: start, 39589 end: end, 39590 39591 length: end - start + 1, 39592 39593 fps: fps, 39594 duration: ( end - start ) / fps, 39595 39596 lastFrame: 0, 39597 currentFrame: 0, 39598 39599 active: false, 39600 39601 time: 0, 39602 direction: 1, 39603 weight: 1, 39604 39605 directionBackwards: false, 39606 mirroredLoop: false 39607 39608 }; 39609 39610 this.animationsMap[ name ] = animation; 39611 this.animationsList.push( animation ); 39612 39613 }; 39614 39615 MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { 39616 39617 var pattern = /([a-z]+)_?(\d+)/i; 39618 39619 var firstAnimation, frameRanges = {}; 39620 39621 var geometry = this.geometry; 39622 39623 for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { 39624 39625 var morph = geometry.morphTargets[ i ]; 39626 var chunks = morph.name.match( pattern ); 39627 39628 if ( chunks && chunks.length > 1 ) { 39629 39630 var name = chunks[ 1 ]; 39631 39632 if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; 39633 39634 var range = frameRanges[ name ]; 39635 39636 if ( i < range.start ) range.start = i; 39637 if ( i > range.end ) range.end = i; 39638 39639 if ( ! firstAnimation ) firstAnimation = name; 39640 39641 } 39642 39643 } 39644 39645 for ( var name in frameRanges ) { 39646 39647 var range = frameRanges[ name ]; 39648 this.createAnimation( name, range.start, range.end, fps ); 39649 39650 } 39651 39652 this.firstAnimation = firstAnimation; 39653 39654 }; 39655 39656 MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { 39657 39658 var animation = this.animationsMap[ name ]; 39659 39660 if ( animation ) { 39661 39662 animation.direction = 1; 39663 animation.directionBackwards = false; 39664 39665 } 39666 39667 }; 39668 39669 MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { 39670 39671 var animation = this.animationsMap[ name ]; 39672 39673 if ( animation ) { 39674 39675 animation.direction = - 1; 39676 animation.directionBackwards = true; 39677 39678 } 39679 39680 }; 39681 39682 MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { 39683 39684 var animation = this.animationsMap[ name ]; 39685 39686 if ( animation ) { 39687 39688 animation.fps = fps; 39689 animation.duration = ( animation.end - animation.start ) / animation.fps; 39690 39691 } 39692 39693 }; 39694 39695 MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { 39696 39697 var animation = this.animationsMap[ name ]; 39698 39699 if ( animation ) { 39700 39701 animation.duration = duration; 39702 animation.fps = ( animation.end - animation.start ) / animation.duration; 39703 39704 } 39705 39706 }; 39707 39708 MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { 39709 39710 var animation = this.animationsMap[ name ]; 39711 39712 if ( animation ) { 39713 39714 animation.weight = weight; 39715 39716 } 39717 39718 }; 39719 39720 MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { 39721 39722 var animation = this.animationsMap[ name ]; 39723 39724 if ( animation ) { 39725 39726 animation.time = time; 39727 39728 } 39729 39730 }; 39731 39732 MorphBlendMesh.prototype.getAnimationTime = function ( name ) { 39733 39734 var time = 0; 39735 39736 var animation = this.animationsMap[ name ]; 39737 39738 if ( animation ) { 39739 39740 time = animation.time; 39741 39742 } 39743 39744 return time; 39745 39746 }; 39747 39748 MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { 39749 39750 var duration = - 1; 39751 39752 var animation = this.animationsMap[ name ]; 39753 39754 if ( animation ) { 39755 39756 duration = animation.duration; 39757 39758 } 39759 39760 return duration; 39761 39762 }; 39763 39764 MorphBlendMesh.prototype.playAnimation = function ( name ) { 39765 39766 var animation = this.animationsMap[ name ]; 39767 39768 if ( animation ) { 39769 39770 animation.time = 0; 39771 animation.active = true; 39772 39773 } else { 39774 39775 console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); 39776 39777 } 39778 39779 }; 39780 39781 MorphBlendMesh.prototype.stopAnimation = function ( name ) { 39782 39783 var animation = this.animationsMap[ name ]; 39784 39785 if ( animation ) { 39786 39787 animation.active = false; 39788 39789 } 39790 39791 }; 39792 39793 MorphBlendMesh.prototype.update = function ( delta ) { 39794 39795 for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { 39796 39797 var animation = this.animationsList[ i ]; 39798 39799 if ( ! animation.active ) continue; 39800 39801 var frameTime = animation.duration / animation.length; 39802 39803 animation.time += animation.direction * delta; 39804 39805 if ( animation.mirroredLoop ) { 39806 39807 if ( animation.time > animation.duration || animation.time < 0 ) { 39808 39809 animation.direction *= - 1; 39810 39811 if ( animation.time > animation.duration ) { 39812 39813 animation.time = animation.duration; 39814 animation.directionBackwards = true; 39815 39816 } 39817 39818 if ( animation.time < 0 ) { 39819 39820 animation.time = 0; 39821 animation.directionBackwards = false; 39822 39823 } 39824 39825 } 39826 39827 } else { 39828 39829 animation.time = animation.time % animation.duration; 39830 39831 if ( animation.time < 0 ) animation.time += animation.duration; 39832 39833 } 39834 39835 var keyframe = animation.start + _Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); 39836 var weight = animation.weight; 39837 39838 if ( keyframe !== animation.currentFrame ) { 39839 39840 this.morphTargetInfluences[ animation.lastFrame ] = 0; 39841 this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; 39842 39843 this.morphTargetInfluences[ keyframe ] = 0; 39844 39845 animation.lastFrame = animation.currentFrame; 39846 animation.currentFrame = keyframe; 39847 39848 } 39849 39850 var mix = ( animation.time % frameTime ) / frameTime; 39851 39852 if ( animation.directionBackwards ) mix = 1 - mix; 39853 39854 if ( animation.currentFrame !== animation.lastFrame ) { 39855 39856 this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; 39857 this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; 39858 39859 } else { 39860 39861 this.morphTargetInfluences[ animation.currentFrame ] = weight; 39862 39863 } 39864 39865 } 39866 39867 }; 39868 39869 /** 39870 * @author alteredq / http://alteredqualia.com/ 39871 */ 39872 39873 function ImmediateRenderObject( material ) { 39874 39875 Object3D.call( this ); 39876 39877 this.material = material; 39878 this.render = function ( renderCallback ) {}; 39879 39880 } 39881 39882 ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); 39883 ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; 39884 39885 ImmediateRenderObject.prototype.isImmediateRenderObject = true; 39886 39887 /** 39888 * @author mrdoob / http://mrdoob.com/ 39889 * @author WestLangley / http://github.com/WestLangley 39890 */ 39891 39892 function VertexNormalsHelper( object, size, hex, linewidth ) { 39893 39894 this.object = object; 39895 39896 this.size = ( size !== undefined ) ? size : 1; 39897 39898 var color = ( hex !== undefined ) ? hex : 0xff0000; 39899 39900 var width = ( linewidth !== undefined ) ? linewidth : 1; 39901 39902 // 39903 39904 var nNormals = 0; 39905 39906 var objGeometry = this.object.geometry; 39907 39908 if ( objGeometry && objGeometry.isGeometry ) { 39909 39910 nNormals = objGeometry.faces.length * 3; 39911 39912 } else if ( objGeometry && objGeometry.isBufferGeometry ) { 39913 39914 nNormals = objGeometry.attributes.normal.count; 39915 39916 } 39917 39918 // 39919 39920 var geometry = new BufferGeometry(); 39921 39922 var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); 39923 39924 geometry.addAttribute( 'position', positions ); 39925 39926 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); 39927 39928 // 39929 39930 this.matrixAutoUpdate = false; 39931 39932 this.update(); 39933 39934 } 39935 39936 VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); 39937 VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; 39938 39939 VertexNormalsHelper.prototype.update = ( function () { 39940 39941 var v1 = new Vector3(); 39942 var v2 = new Vector3(); 39943 var normalMatrix = new Matrix3(); 39944 39945 return function update() { 39946 39947 var keys = [ 'a', 'b', 'c' ]; 39948 39949 this.object.updateMatrixWorld( true ); 39950 39951 normalMatrix.getNormalMatrix( this.object.matrixWorld ); 39952 39953 var matrixWorld = this.object.matrixWorld; 39954 39955 var position = this.geometry.attributes.position; 39956 39957 // 39958 39959 var objGeometry = this.object.geometry; 39960 39961 if ( objGeometry && objGeometry.isGeometry ) { 39962 39963 var vertices = objGeometry.vertices; 39964 39965 var faces = objGeometry.faces; 39966 39967 var idx = 0; 39968 39969 for ( var i = 0, l = faces.length; i < l; i ++ ) { 39970 39971 var face = faces[ i ]; 39972 39973 for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { 39974 39975 var vertex = vertices[ face[ keys[ j ] ] ]; 39976 39977 var normal = face.vertexNormals[ j ]; 39978 39979 v1.copy( vertex ).applyMatrix4( matrixWorld ); 39980 39981 v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); 39982 39983 position.setXYZ( idx, v1.x, v1.y, v1.z ); 39984 39985 idx = idx + 1; 39986 39987 position.setXYZ( idx, v2.x, v2.y, v2.z ); 39988 39989 idx = idx + 1; 39990 39991 } 39992 39993 } 39994 39995 } else if ( objGeometry && objGeometry.isBufferGeometry ) { 39996 39997 var objPos = objGeometry.attributes.position; 39998 39999 var objNorm = objGeometry.attributes.normal; 40000 40001 var idx = 0; 40002 40003 // for simplicity, ignore index and drawcalls, and render every normal 40004 40005 for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { 40006 40007 v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); 40008 40009 v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); 40010 40011 v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); 40012 40013 position.setXYZ( idx, v1.x, v1.y, v1.z ); 40014 40015 idx = idx + 1; 40016 40017 position.setXYZ( idx, v2.x, v2.y, v2.z ); 40018 40019 idx = idx + 1; 40020 40021 } 40022 40023 } 40024 40025 position.needsUpdate = true; 40026 40027 return this; 40028 40029 }; 40030 40031 }() ); 40032 40033 /** 40034 * @author alteredq / http://alteredqualia.com/ 40035 * @author mrdoob / http://mrdoob.com/ 40036 * @author WestLangley / http://github.com/WestLangley 40037 */ 40038 40039 function SpotLightHelper( light ) { 40040 40041 Object3D.call( this ); 40042 40043 this.light = light; 40044 this.light.updateMatrixWorld(); 40045 40046 this.matrix = light.matrixWorld; 40047 this.matrixAutoUpdate = false; 40048 40049 var geometry = new BufferGeometry(); 40050 40051 var positions = [ 40052 0, 0, 0, 0, 0, 1, 40053 0, 0, 0, 1, 0, 1, 40054 0, 0, 0, - 1, 0, 1, 40055 0, 0, 0, 0, 1, 1, 40056 0, 0, 0, 0, - 1, 1 40057 ]; 40058 40059 for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { 40060 40061 var p1 = ( i / l ) * Math.PI * 2; 40062 var p2 = ( j / l ) * Math.PI * 2; 40063 40064 positions.push( 40065 Math.cos( p1 ), Math.sin( p1 ), 1, 40066 Math.cos( p2 ), Math.sin( p2 ), 1 40067 ); 40068 40069 } 40070 40071 geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 40072 40073 var material = new LineBasicMaterial( { fog: false } ); 40074 40075 this.cone = new LineSegments( geometry, material ); 40076 this.add( this.cone ); 40077 40078 this.update(); 40079 40080 } 40081 40082 SpotLightHelper.prototype = Object.create( Object3D.prototype ); 40083 SpotLightHelper.prototype.constructor = SpotLightHelper; 40084 40085 SpotLightHelper.prototype.dispose = function () { 40086 40087 this.cone.geometry.dispose(); 40088 this.cone.material.dispose(); 40089 40090 }; 40091 40092 SpotLightHelper.prototype.update = function () { 40093 40094 var vector = new Vector3(); 40095 var vector2 = new Vector3(); 40096 40097 return function update() { 40098 40099 var coneLength = this.light.distance ? this.light.distance : 1000; 40100 var coneWidth = coneLength * Math.tan( this.light.angle ); 40101 40102 this.cone.scale.set( coneWidth, coneWidth, coneLength ); 40103 40104 vector.setFromMatrixPosition( this.light.matrixWorld ); 40105 vector2.setFromMatrixPosition( this.light.target.matrixWorld ); 40106 40107 this.cone.lookAt( vector2.sub( vector ) ); 40108 40109 this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40110 40111 }; 40112 40113 }(); 40114 40115 /** 40116 * @author Sean Griffin / http://twitter.com/sgrif 40117 * @author Michael Guerrero / http://realitymeltdown.com 40118 * @author mrdoob / http://mrdoob.com/ 40119 * @author ikerr / http://verold.com 40120 * @author Mugen87 / https://github.com/Mugen87 40121 */ 40122 40123 function SkeletonHelper( object ) { 40124 40125 this.bones = this.getBoneList( object ); 40126 40127 var geometry = new BufferGeometry(); 40128 40129 var vertices = []; 40130 var colors = []; 40131 40132 var color1 = new Color( 0, 0, 1 ); 40133 var color2 = new Color( 0, 1, 0 ); 40134 40135 for ( var i = 0; i < this.bones.length; i ++ ) { 40136 40137 var bone = this.bones[ i ]; 40138 40139 if ( bone.parent && bone.parent.isBone ) { 40140 40141 vertices.push( 0, 0, 0 ); 40142 vertices.push( 0, 0, 0 ); 40143 colors.push( color1.r, color1.g, color1.b ); 40144 colors.push( color2.r, color2.g, color2.b ); 40145 40146 } 40147 40148 } 40149 40150 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40151 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 40152 40153 var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); 40154 40155 LineSegments.call( this, geometry, material ); 40156 40157 this.root = object; 40158 40159 this.matrix = object.matrixWorld; 40160 this.matrixAutoUpdate = false; 40161 40162 this.update(); 40163 40164 } 40165 40166 40167 SkeletonHelper.prototype = Object.create( LineSegments.prototype ); 40168 SkeletonHelper.prototype.constructor = SkeletonHelper; 40169 40170 SkeletonHelper.prototype.getBoneList = function( object ) { 40171 40172 var boneList = []; 40173 40174 if ( object && object.isBone ) { 40175 40176 boneList.push( object ); 40177 40178 } 40179 40180 for ( var i = 0; i < object.children.length; i ++ ) { 40181 40182 boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); 40183 40184 } 40185 40186 return boneList; 40187 40188 }; 40189 40190 SkeletonHelper.prototype.update = function () { 40191 40192 var vector = new Vector3(); 40193 40194 var boneMatrix = new Matrix4(); 40195 var matrixWorldInv = new Matrix4(); 40196 40197 return function update() { 40198 40199 var geometry = this.geometry; 40200 var position = geometry.getAttribute( 'position' ); 40201 40202 matrixWorldInv.getInverse( this.root.matrixWorld ); 40203 40204 for ( var i = 0, j = 0; i < this.bones.length; i ++ ) { 40205 40206 var bone = this.bones[ i ]; 40207 40208 if ( bone.parent && bone.parent.isBone ) { 40209 40210 boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); 40211 vector.setFromMatrixPosition( boneMatrix ); 40212 position.setXYZ( j, vector.x, vector.y, vector.z ); 40213 40214 boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); 40215 vector.setFromMatrixPosition( boneMatrix ); 40216 position.setXYZ( j + 1, vector.x, vector.y, vector.z ); 40217 40218 j += 2; 40219 40220 } 40221 40222 } 40223 40224 geometry.getAttribute( 'position' ).needsUpdate = true; 40225 40226 }; 40227 40228 }(); 40229 40230 /** 40231 * @author alteredq / http://alteredqualia.com/ 40232 * @author mrdoob / http://mrdoob.com/ 40233 */ 40234 40235 function PointLightHelper( light, sphereSize ) { 40236 40237 this.light = light; 40238 this.light.updateMatrixWorld(); 40239 40240 var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); 40241 var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); 40242 material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40243 40244 Mesh.call( this, geometry, material ); 40245 40246 this.matrix = this.light.matrixWorld; 40247 this.matrixAutoUpdate = false; 40248 40249 /* 40250 var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); 40251 var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); 40252 40253 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); 40254 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); 40255 40256 var d = light.distance; 40257 40258 if ( d === 0.0 ) { 40259 40260 this.lightDistance.visible = false; 40261 40262 } else { 40263 40264 this.lightDistance.scale.set( d, d, d ); 40265 40266 } 40267 40268 this.add( this.lightDistance ); 40269 */ 40270 40271 } 40272 40273 PointLightHelper.prototype = Object.create( Mesh.prototype ); 40274 PointLightHelper.prototype.constructor = PointLightHelper; 40275 40276 PointLightHelper.prototype.dispose = function () { 40277 40278 this.geometry.dispose(); 40279 this.material.dispose(); 40280 40281 }; 40282 40283 PointLightHelper.prototype.update = function () { 40284 40285 this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40286 40287 /* 40288 var d = this.light.distance; 40289 40290 if ( d === 0.0 ) { 40291 40292 this.lightDistance.visible = false; 40293 40294 } else { 40295 40296 this.lightDistance.visible = true; 40297 this.lightDistance.scale.set( d, d, d ); 40298 40299 } 40300 */ 40301 40302 }; 40303 40304 /** 40305 * @author abelnation / http://github.com/abelnation 40306 * @author Mugen87 / http://github.com/Mugen87 40307 */ 40308 40309 function RectAreaLightHelper( light ) { 40310 40311 Object3D.call( this ); 40312 40313 this.light = light; 40314 this.light.updateMatrixWorld(); 40315 40316 var materialFront = new MeshBasicMaterial( { 40317 color: light.color, 40318 fog: false 40319 } ); 40320 40321 var materialBack = new MeshBasicMaterial( { 40322 color: light.color, 40323 fog: false, 40324 wireframe: true 40325 } ); 40326 40327 var geometry = new BufferGeometry(); 40328 40329 geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 6 * 3 ), 3 ) ); 40330 40331 // shows the "front" of the light, e.g. where light comes from 40332 40333 this.add( new Mesh( geometry, materialFront ) ); 40334 40335 // shows the "back" of the light, which does not emit light 40336 40337 this.add( new Mesh( geometry, materialBack ) ); 40338 40339 this.update(); 40340 40341 } 40342 40343 RectAreaLightHelper.prototype = Object.create( Object3D.prototype ); 40344 RectAreaLightHelper.prototype.constructor = RectAreaLightHelper; 40345 40346 RectAreaLightHelper.prototype.dispose = function () { 40347 40348 this.children[ 0 ].geometry.dispose(); 40349 this.children[ 0 ].material.dispose(); 40350 this.children[ 1 ].geometry.dispose(); 40351 this.children[ 1 ].material.dispose(); 40352 40353 }; 40354 40355 RectAreaLightHelper.prototype.update = function () { 40356 40357 var vector1 = new Vector3(); 40358 var vector2 = new Vector3(); 40359 40360 return function update() { 40361 40362 var mesh1 = this.children[ 0 ]; 40363 var mesh2 = this.children[ 1 ]; 40364 40365 if ( this.light.target ) { 40366 40367 vector1.setFromMatrixPosition( this.light.matrixWorld ); 40368 vector2.setFromMatrixPosition( this.light.target.matrixWorld ); 40369 40370 var lookVec = vector2.clone().sub( vector1 ); 40371 mesh1.lookAt( lookVec ); 40372 mesh2.lookAt( lookVec ); 40373 40374 } 40375 40376 // update materials 40377 40378 mesh1.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40379 mesh2.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40380 40381 // calculate new dimensions of the helper 40382 40383 var hx = this.light.width * 0.5; 40384 var hy = this.light.height * 0.5; 40385 40386 // because the buffer attribute is shared over both geometries, we only have to update once 40387 40388 var position = mesh1.geometry.getAttribute( 'position' ); 40389 var array = position.array; 40390 40391 // first face 40392 40393 array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0; 40394 array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0; 40395 array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0; 40396 40397 // second face 40398 40399 array[ 9 ] = - hx; array[ 10 ] = hy; array[ 11 ] = 0; 40400 array[ 12 ] = - hx; array[ 13 ] = - hy; array[ 14 ] = 0; 40401 array[ 15 ] = hx; array[ 16 ] = - hy; array[ 17 ] = 0; 40402 40403 position.needsUpdate = true; 40404 40405 }; 40406 40407 }(); 40408 40409 /** 40410 * @author alteredq / http://alteredqualia.com/ 40411 * @author mrdoob / http://mrdoob.com/ 40412 * @author Mugen87 / https://github.com/Mugen87 40413 */ 40414 40415 function HemisphereLightHelper( light, size ) { 40416 40417 Object3D.call( this ); 40418 40419 this.light = light; 40420 this.light.updateMatrixWorld(); 40421 40422 this.matrix = light.matrixWorld; 40423 this.matrixAutoUpdate = false; 40424 40425 var geometry = new OctahedronBufferGeometry( size ); 40426 geometry.rotateY( Math.PI * 0.5 ); 40427 40428 var material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } ); 40429 40430 var position = geometry.getAttribute( 'position' ); 40431 var colors = new Float32Array( position.count * 3 ); 40432 40433 geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); 40434 40435 this.add( new Mesh( geometry, material ) ); 40436 40437 this.update(); 40438 40439 } 40440 40441 HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); 40442 HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; 40443 40444 HemisphereLightHelper.prototype.dispose = function () { 40445 40446 this.children[ 0 ].geometry.dispose(); 40447 this.children[ 0 ].material.dispose(); 40448 40449 }; 40450 40451 HemisphereLightHelper.prototype.update = function () { 40452 40453 var vector = new Vector3(); 40454 40455 var color1 = new Color(); 40456 var color2 = new Color(); 40457 40458 return function update() { 40459 40460 var mesh = this.children[ 0 ]; 40461 40462 var colors = mesh.geometry.getAttribute( 'color' ); 40463 40464 color1.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40465 color2.copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); 40466 40467 for ( var i = 0, l = colors.count; i < l; i ++ ) { 40468 40469 var color = ( i < ( l / 2 ) ) ? color1 : color2; 40470 40471 colors.setXYZ( i, color.r, color.g, color.b ); 40472 40473 } 40474 40475 mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); 40476 40477 colors.needsUpdate = true; 40478 40479 }; 40480 40481 }(); 40482 40483 /** 40484 * @author mrdoob / http://mrdoob.com/ 40485 */ 40486 40487 function GridHelper( size, divisions, color1, color2 ) { 40488 40489 size = size || 10; 40490 divisions = divisions || 10; 40491 color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); 40492 color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); 40493 40494 var center = divisions / 2; 40495 var step = size / divisions; 40496 var halfSize = size / 2; 40497 40498 var vertices = [], colors = []; 40499 40500 for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { 40501 40502 vertices.push( - halfSize, 0, k, halfSize, 0, k ); 40503 vertices.push( k, 0, - halfSize, k, 0, halfSize ); 40504 40505 var color = i === center ? color1 : color2; 40506 40507 color.toArray( colors, j ); j += 3; 40508 color.toArray( colors, j ); j += 3; 40509 color.toArray( colors, j ); j += 3; 40510 color.toArray( colors, j ); j += 3; 40511 40512 } 40513 40514 var geometry = new BufferGeometry(); 40515 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40516 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 40517 40518 var material = new LineBasicMaterial( { vertexColors: VertexColors } ); 40519 40520 LineSegments.call( this, geometry, material ); 40521 40522 } 40523 40524 GridHelper.prototype = Object.create( LineSegments.prototype ); 40525 GridHelper.prototype.constructor = GridHelper; 40526 40527 /** 40528 * @author mrdoob / http://mrdoob.com/ 40529 * @author Mugen87 / http://github.com/Mugen87 40530 * @author Hectate / http://www.github.com/Hectate 40531 */ 40532 40533 function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { 40534 40535 radius = radius || 10; 40536 radials = radials || 16; 40537 circles = circles || 8; 40538 divisions = divisions || 64; 40539 color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); 40540 color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); 40541 40542 var vertices = []; 40543 var colors = []; 40544 40545 var x, z; 40546 var v, i, j, r, color; 40547 40548 // create the radials 40549 40550 for ( i = 0; i <= radials; i ++ ) { 40551 40552 v = ( i / radials ) * ( Math.PI * 2 ); 40553 40554 x = Math.sin( v ) * radius; 40555 z = Math.cos( v ) * radius; 40556 40557 vertices.push( 0, 0, 0 ); 40558 vertices.push( x, 0, z ); 40559 40560 color = ( i & 1 ) ? color1 : color2; 40561 40562 colors.push( color.r, color.g, color.b ); 40563 colors.push( color.r, color.g, color.b ); 40564 40565 } 40566 40567 // create the circles 40568 40569 for ( i = 0; i <= circles; i ++ ) { 40570 40571 color = ( i & 1 ) ? color1 : color2; 40572 40573 r = radius - ( radius / circles * i ); 40574 40575 for ( j = 0; j < divisions; j ++ ) { 40576 40577 // first vertex 40578 40579 v = ( j / divisions ) * ( Math.PI * 2 ); 40580 40581 x = Math.sin( v ) * r; 40582 z = Math.cos( v ) * r; 40583 40584 vertices.push( x, 0, z ); 40585 colors.push( color.r, color.g, color.b ); 40586 40587 // second vertex 40588 40589 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); 40590 40591 x = Math.sin( v ) * r; 40592 z = Math.cos( v ) * r; 40593 40594 vertices.push( x, 0, z ); 40595 colors.push( color.r, color.g, color.b ); 40596 40597 } 40598 40599 } 40600 40601 var geometry = new BufferGeometry(); 40602 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40603 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 40604 40605 var material = new LineBasicMaterial( { vertexColors: VertexColors } ); 40606 40607 LineSegments.call( this, geometry, material ); 40608 40609 } 40610 40611 PolarGridHelper.prototype = Object.create( LineSegments.prototype ); 40612 PolarGridHelper.prototype.constructor = PolarGridHelper; 40613 40614 /** 40615 * @author mrdoob / http://mrdoob.com/ 40616 * @author WestLangley / http://github.com/WestLangley 40617 */ 40618 40619 function FaceNormalsHelper( object, size, hex, linewidth ) { 40620 40621 // FaceNormalsHelper only supports THREE.Geometry 40622 40623 this.object = object; 40624 40625 this.size = ( size !== undefined ) ? size : 1; 40626 40627 var color = ( hex !== undefined ) ? hex : 0xffff00; 40628 40629 var width = ( linewidth !== undefined ) ? linewidth : 1; 40630 40631 // 40632 40633 var nNormals = 0; 40634 40635 var objGeometry = this.object.geometry; 40636 40637 if ( objGeometry && objGeometry.isGeometry ) { 40638 40639 nNormals = objGeometry.faces.length; 40640 40641 } else { 40642 40643 console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); 40644 40645 } 40646 40647 // 40648 40649 var geometry = new BufferGeometry(); 40650 40651 var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); 40652 40653 geometry.addAttribute( 'position', positions ); 40654 40655 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); 40656 40657 // 40658 40659 this.matrixAutoUpdate = false; 40660 this.update(); 40661 40662 } 40663 40664 FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); 40665 FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; 40666 40667 FaceNormalsHelper.prototype.update = ( function () { 40668 40669 var v1 = new Vector3(); 40670 var v2 = new Vector3(); 40671 var normalMatrix = new Matrix3(); 40672 40673 return function update() { 40674 40675 this.object.updateMatrixWorld( true ); 40676 40677 normalMatrix.getNormalMatrix( this.object.matrixWorld ); 40678 40679 var matrixWorld = this.object.matrixWorld; 40680 40681 var position = this.geometry.attributes.position; 40682 40683 // 40684 40685 var objGeometry = this.object.geometry; 40686 40687 var vertices = objGeometry.vertices; 40688 40689 var faces = objGeometry.faces; 40690 40691 var idx = 0; 40692 40693 for ( var i = 0, l = faces.length; i < l; i ++ ) { 40694 40695 var face = faces[ i ]; 40696 40697 var normal = face.normal; 40698 40699 v1.copy( vertices[ face.a ] ) 40700 .add( vertices[ face.b ] ) 40701 .add( vertices[ face.c ] ) 40702 .divideScalar( 3 ) 40703 .applyMatrix4( matrixWorld ); 40704 40705 v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); 40706 40707 position.setXYZ( idx, v1.x, v1.y, v1.z ); 40708 40709 idx = idx + 1; 40710 40711 position.setXYZ( idx, v2.x, v2.y, v2.z ); 40712 40713 idx = idx + 1; 40714 40715 } 40716 40717 position.needsUpdate = true; 40718 40719 return this; 40720 40721 }; 40722 40723 }() ); 40724 40725 /** 40726 * @author alteredq / http://alteredqualia.com/ 40727 * @author mrdoob / http://mrdoob.com/ 40728 * @author WestLangley / http://github.com/WestLangley 40729 */ 40730 40731 function DirectionalLightHelper( light, size ) { 40732 40733 Object3D.call( this ); 40734 40735 this.light = light; 40736 this.light.updateMatrixWorld(); 40737 40738 this.matrix = light.matrixWorld; 40739 this.matrixAutoUpdate = false; 40740 40741 if ( size === undefined ) size = 1; 40742 40743 var geometry = new BufferGeometry(); 40744 geometry.addAttribute( 'position', new Float32BufferAttribute( [ 40745 - size, size, 0, 40746 size, size, 0, 40747 size, - size, 0, 40748 - size, - size, 0, 40749 - size, size, 0 40750 ], 3 ) ); 40751 40752 var material = new LineBasicMaterial( { fog: false } ); 40753 40754 this.add( new Line( geometry, material ) ); 40755 40756 geometry = new BufferGeometry(); 40757 geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); 40758 40759 this.add( new Line( geometry, material )); 40760 40761 this.update(); 40762 40763 } 40764 40765 DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); 40766 DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; 40767 40768 DirectionalLightHelper.prototype.dispose = function () { 40769 40770 var lightPlane = this.children[ 0 ]; 40771 var targetLine = this.children[ 1 ]; 40772 40773 lightPlane.geometry.dispose(); 40774 lightPlane.material.dispose(); 40775 targetLine.geometry.dispose(); 40776 targetLine.material.dispose(); 40777 40778 }; 40779 40780 DirectionalLightHelper.prototype.update = function () { 40781 40782 var v1 = new Vector3(); 40783 var v2 = new Vector3(); 40784 var v3 = new Vector3(); 40785 40786 return function update() { 40787 40788 v1.setFromMatrixPosition( this.light.matrixWorld ); 40789 v2.setFromMatrixPosition( this.light.target.matrixWorld ); 40790 v3.subVectors( v2, v1 ); 40791 40792 var lightPlane = this.children[ 0 ]; 40793 var targetLine = this.children[ 1 ]; 40794 40795 lightPlane.lookAt( v3 ); 40796 lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); 40797 40798 targetLine.lookAt( v3 ); 40799 targetLine.scale.z = v3.length(); 40800 40801 }; 40802 40803 }(); 40804 40805 /** 40806 * @author alteredq / http://alteredqualia.com/ 40807 * @author Mugen87 / https://github.com/Mugen87 40808 * 40809 * - shows frustum, line of sight and up of the camera 40810 * - suitable for fast updates 40811 * - based on frustum visualization in lightgl.js shadowmap example 40812 * http://evanw.github.com/lightgl.js/tests/shadowmap.html 40813 */ 40814 40815 function CameraHelper( camera ) { 40816 40817 var geometry = new BufferGeometry(); 40818 var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); 40819 40820 var vertices = []; 40821 var colors = []; 40822 40823 var pointMap = {}; 40824 40825 // colors 40826 40827 var colorFrustum = new Color( 0xffaa00 ); 40828 var colorCone = new Color( 0xff0000 ); 40829 var colorUp = new Color( 0x00aaff ); 40830 var colorTarget = new Color( 0xffffff ); 40831 var colorCross = new Color( 0x333333 ); 40832 40833 // near 40834 40835 addLine( "n1", "n2", colorFrustum ); 40836 addLine( "n2", "n4", colorFrustum ); 40837 addLine( "n4", "n3", colorFrustum ); 40838 addLine( "n3", "n1", colorFrustum ); 40839 40840 // far 40841 40842 addLine( "f1", "f2", colorFrustum ); 40843 addLine( "f2", "f4", colorFrustum ); 40844 addLine( "f4", "f3", colorFrustum ); 40845 addLine( "f3", "f1", colorFrustum ); 40846 40847 // sides 40848 40849 addLine( "n1", "f1", colorFrustum ); 40850 addLine( "n2", "f2", colorFrustum ); 40851 addLine( "n3", "f3", colorFrustum ); 40852 addLine( "n4", "f4", colorFrustum ); 40853 40854 // cone 40855 40856 addLine( "p", "n1", colorCone ); 40857 addLine( "p", "n2", colorCone ); 40858 addLine( "p", "n3", colorCone ); 40859 addLine( "p", "n4", colorCone ); 40860 40861 // up 40862 40863 addLine( "u1", "u2", colorUp ); 40864 addLine( "u2", "u3", colorUp ); 40865 addLine( "u3", "u1", colorUp ); 40866 40867 // target 40868 40869 addLine( "c", "t", colorTarget ); 40870 addLine( "p", "c", colorCross ); 40871 40872 // cross 40873 40874 addLine( "cn1", "cn2", colorCross ); 40875 addLine( "cn3", "cn4", colorCross ); 40876 40877 addLine( "cf1", "cf2", colorCross ); 40878 addLine( "cf3", "cf4", colorCross ); 40879 40880 function addLine( a, b, color ) { 40881 40882 addPoint( a, color ); 40883 addPoint( b, color ); 40884 40885 } 40886 40887 function addPoint( id, color ) { 40888 40889 vertices.push( 0, 0, 0 ); 40890 colors.push( color.r, color.g, color.b ); 40891 40892 if ( pointMap[ id ] === undefined ) { 40893 40894 pointMap[ id ] = []; 40895 40896 } 40897 40898 pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); 40899 40900 } 40901 40902 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40903 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 40904 40905 LineSegments.call( this, geometry, material ); 40906 40907 this.camera = camera; 40908 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); 40909 40910 this.matrix = camera.matrixWorld; 40911 this.matrixAutoUpdate = false; 40912 40913 this.pointMap = pointMap; 40914 40915 this.update(); 40916 40917 } 40918 40919 CameraHelper.prototype = Object.create( LineSegments.prototype ); 40920 CameraHelper.prototype.constructor = CameraHelper; 40921 40922 CameraHelper.prototype.update = function () { 40923 40924 var geometry, pointMap; 40925 40926 var vector = new Vector3(); 40927 var camera = new Camera(); 40928 40929 function setPoint( point, x, y, z ) { 40930 40931 vector.set( x, y, z ).unproject( camera ); 40932 40933 var points = pointMap[ point ]; 40934 40935 if ( points !== undefined ) { 40936 40937 var position = geometry.getAttribute( 'position' ); 40938 40939 for ( var i = 0, l = points.length; i < l; i ++ ) { 40940 40941 position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); 40942 40943 } 40944 40945 } 40946 40947 } 40948 40949 return function update() { 40950 40951 geometry = this.geometry; 40952 pointMap = this.pointMap; 40953 40954 var w = 1, h = 1; 40955 40956 // we need just camera projection matrix 40957 // world matrix must be identity 40958 40959 camera.projectionMatrix.copy( this.camera.projectionMatrix ); 40960 40961 // center / target 40962 40963 setPoint( "c", 0, 0, - 1 ); 40964 setPoint( "t", 0, 0, 1 ); 40965 40966 // near 40967 40968 setPoint( "n1", - w, - h, - 1 ); 40969 setPoint( "n2", w, - h, - 1 ); 40970 setPoint( "n3", - w, h, - 1 ); 40971 setPoint( "n4", w, h, - 1 ); 40972 40973 // far 40974 40975 setPoint( "f1", - w, - h, 1 ); 40976 setPoint( "f2", w, - h, 1 ); 40977 setPoint( "f3", - w, h, 1 ); 40978 setPoint( "f4", w, h, 1 ); 40979 40980 // up 40981 40982 setPoint( "u1", w * 0.7, h * 1.1, - 1 ); 40983 setPoint( "u2", - w * 0.7, h * 1.1, - 1 ); 40984 setPoint( "u3", 0, h * 2, - 1 ); 40985 40986 // cross 40987 40988 setPoint( "cf1", - w, 0, 1 ); 40989 setPoint( "cf2", w, 0, 1 ); 40990 setPoint( "cf3", 0, - h, 1 ); 40991 setPoint( "cf4", 0, h, 1 ); 40992 40993 setPoint( "cn1", - w, 0, - 1 ); 40994 setPoint( "cn2", w, 0, - 1 ); 40995 setPoint( "cn3", 0, - h, - 1 ); 40996 setPoint( "cn4", 0, h, - 1 ); 40997 40998 geometry.getAttribute( 'position' ).needsUpdate = true; 40999 41000 }; 41001 41002 }(); 41003 41004 /** 41005 * @author mrdoob / http://mrdoob.com/ 41006 */ 41007 41008 function BoxHelper( object, color ) { 41009 41010 if ( color === undefined ) color = 0xffff00; 41011 41012 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 ] ); 41013 var positions = new Float32Array( 8 * 3 ); 41014 41015 var geometry = new BufferGeometry(); 41016 geometry.setIndex( new BufferAttribute( indices, 1 ) ); 41017 geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); 41018 41019 LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); 41020 41021 if ( object !== undefined ) { 41022 41023 this.update( object ); 41024 41025 } 41026 41027 } 41028 41029 BoxHelper.prototype = Object.create( LineSegments.prototype ); 41030 BoxHelper.prototype.constructor = BoxHelper; 41031 41032 BoxHelper.prototype.update = ( function () { 41033 41034 var box = new Box3(); 41035 41036 return function update( object ) { 41037 41038 if ( object && object.isBox3 ) { 41039 41040 box.copy( object ); 41041 41042 } else { 41043 41044 box.setFromObject( object ); 41045 41046 } 41047 41048 if ( box.isEmpty() ) return; 41049 41050 var min = box.min; 41051 var max = box.max; 41052 41053 /* 41054 5____4 41055 1/___0/| 41056 | 6__|_7 41057 2/___3/ 41058 41059 0: max.x, max.y, max.z 41060 1: min.x, max.y, max.z 41061 2: min.x, min.y, max.z 41062 3: max.x, min.y, max.z 41063 4: max.x, max.y, min.z 41064 5: min.x, max.y, min.z 41065 6: min.x, min.y, min.z 41066 7: max.x, min.y, min.z 41067 */ 41068 41069 var position = this.geometry.attributes.position; 41070 var array = position.array; 41071 41072 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; 41073 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; 41074 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; 41075 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; 41076 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; 41077 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; 41078 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; 41079 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; 41080 41081 position.needsUpdate = true; 41082 41083 this.geometry.computeBoundingSphere(); 41084 41085 }; 41086 41087 } )(); 41088 41089 /** 41090 * @author WestLangley / http://github.com/WestLangley 41091 * @author zz85 / http://github.com/zz85 41092 * @author bhouston / http://clara.io 41093 * 41094 * Creates an arrow for visualizing directions 41095 * 41096 * Parameters: 41097 * dir - Vector3 41098 * origin - Vector3 41099 * length - Number 41100 * color - color in hex value 41101 * headLength - Number 41102 * headWidth - Number 41103 */ 41104 41105 var lineGeometry; 41106 var coneGeometry; 41107 41108 function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { 41109 41110 // dir is assumed to be normalized 41111 41112 Object3D.call( this ); 41113 41114 if ( color === undefined ) color = 0xffff00; 41115 if ( length === undefined ) length = 1; 41116 if ( headLength === undefined ) headLength = 0.2 * length; 41117 if ( headWidth === undefined ) headWidth = 0.2 * headLength; 41118 41119 if ( lineGeometry === undefined ) { 41120 41121 lineGeometry = new BufferGeometry(); 41122 lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); 41123 41124 coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 ); 41125 coneGeometry.translate( 0, - 0.5, 0 ); 41126 41127 } 41128 41129 this.position.copy( origin ); 41130 41131 this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) ); 41132 this.line.matrixAutoUpdate = false; 41133 this.add( this.line ); 41134 41135 this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) ); 41136 this.cone.matrixAutoUpdate = false; 41137 this.add( this.cone ); 41138 41139 this.setDirection( dir ); 41140 this.setLength( length, headLength, headWidth ); 41141 41142 } 41143 41144 ArrowHelper.prototype = Object.create( Object3D.prototype ); 41145 ArrowHelper.prototype.constructor = ArrowHelper; 41146 41147 ArrowHelper.prototype.setDirection = ( function () { 41148 41149 var axis = new Vector3(); 41150 var radians; 41151 41152 return function setDirection( dir ) { 41153 41154 // dir is assumed to be normalized 41155 41156 if ( dir.y > 0.99999 ) { 41157 41158 this.quaternion.set( 0, 0, 0, 1 ); 41159 41160 } else if ( dir.y < - 0.99999 ) { 41161 41162 this.quaternion.set( 1, 0, 0, 0 ); 41163 41164 } else { 41165 41166 axis.set( dir.z, 0, - dir.x ).normalize(); 41167 41168 radians = Math.acos( dir.y ); 41169 41170 this.quaternion.setFromAxisAngle( axis, radians ); 41171 41172 } 41173 41174 }; 41175 41176 }() ); 41177 41178 ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { 41179 41180 if ( headLength === undefined ) headLength = 0.2 * length; 41181 if ( headWidth === undefined ) headWidth = 0.2 * headLength; 41182 41183 this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 ); 41184 this.line.updateMatrix(); 41185 41186 this.cone.scale.set( headWidth, headLength, headWidth ); 41187 this.cone.position.y = length; 41188 this.cone.updateMatrix(); 41189 41190 }; 41191 41192 ArrowHelper.prototype.setColor = function ( color ) { 41193 41194 this.line.material.color.copy( color ); 41195 this.cone.material.color.copy( color ); 41196 41197 }; 41198 41199 /** 41200 * @author sroucheray / http://sroucheray.org/ 41201 * @author mrdoob / http://mrdoob.com/ 41202 */ 41203 41204 function AxisHelper( size ) { 41205 41206 size = size || 1; 41207 41208 var vertices = [ 41209 0, 0, 0, size, 0, 0, 41210 0, 0, 0, 0, size, 0, 41211 0, 0, 0, 0, 0, size 41212 ]; 41213 41214 var colors = [ 41215 1, 0, 0, 1, 0.6, 0, 41216 0, 1, 0, 0.6, 1, 0, 41217 0, 0, 1, 0, 0.6, 1 41218 ]; 41219 41220 var geometry = new BufferGeometry(); 41221 geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 41222 geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 41223 41224 var material = new LineBasicMaterial( { vertexColors: VertexColors } ); 41225 41226 LineSegments.call( this, geometry, material ); 41227 41228 } 41229 41230 AxisHelper.prototype = Object.create( LineSegments.prototype ); 41231 AxisHelper.prototype.constructor = AxisHelper; 41232 41233 /** 41234 * @author zz85 https://github.com/zz85 41235 * 41236 * Centripetal CatmullRom Curve - which is useful for avoiding 41237 * cusps and self-intersections in non-uniform catmull rom curves. 41238 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf 41239 * 41240 * curve.type accepts centripetal(default), chordal and catmullrom 41241 * curve.tension is used for catmullrom which defaults to 0.5 41242 */ 41243 41244 41245 /* 41246 Based on an optimized c++ solution in 41247 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ 41248 - http://ideone.com/NoEbVM 41249 41250 This CubicPoly class could be used for reusing some variables and calculations, 41251 but for three.js curve use, it could be possible inlined and flatten into a single function call 41252 which can be placed in CurveUtils. 41253 */ 41254 41255 function CubicPoly() { 41256 41257 var c0 = 0, c1 = 0, c2 = 0, c3 = 0; 41258 41259 /* 41260 * Compute coefficients for a cubic polynomial 41261 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 41262 * such that 41263 * p(0) = x0, p(1) = x1 41264 * and 41265 * p'(0) = t0, p'(1) = t1. 41266 */ 41267 function init( x0, x1, t0, t1 ) { 41268 41269 c0 = x0; 41270 c1 = t0; 41271 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; 41272 c3 = 2 * x0 - 2 * x1 + t0 + t1; 41273 41274 } 41275 41276 return { 41277 41278 initCatmullRom: function ( x0, x1, x2, x3, tension ) { 41279 41280 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); 41281 41282 }, 41283 41284 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { 41285 41286 // compute tangents when parameterized in [t1,t2] 41287 var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; 41288 var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; 41289 41290 // rescale tangents for parametrization in [0,1] 41291 t1 *= dt1; 41292 t2 *= dt1; 41293 41294 init( x1, x2, t1, t2 ); 41295 41296 }, 41297 41298 calc: function ( t ) { 41299 41300 var t2 = t * t; 41301 var t3 = t2 * t; 41302 return c0 + c1 * t + c2 * t2 + c3 * t3; 41303 41304 } 41305 41306 }; 41307 41308 } 41309 41310 // 41311 41312 var tmp = new Vector3(); 41313 var px = new CubicPoly(); 41314 var py = new CubicPoly(); 41315 var pz = new CubicPoly(); 41316 41317 function CatmullRomCurve3( p /* array of Vector3 */ ) { 41318 41319 this.points = p || []; 41320 this.closed = false; 41321 41322 } 41323 41324 CatmullRomCurve3.prototype = Object.create( Curve.prototype ); 41325 CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; 41326 41327 CatmullRomCurve3.prototype.getPoint = function ( t ) { 41328 41329 var points = this.points; 41330 var l = points.length; 41331 41332 if ( l < 2 ) console.log( 'duh, you need at least 2 points' ); 41333 41334 var point = ( l - ( this.closed ? 0 : 1 ) ) * t; 41335 var intPoint = Math.floor( point ); 41336 var weight = point - intPoint; 41337 41338 if ( this.closed ) { 41339 41340 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; 41341 41342 } else if ( weight === 0 && intPoint === l - 1 ) { 41343 41344 intPoint = l - 2; 41345 weight = 1; 41346 41347 } 41348 41349 var p0, p1, p2, p3; // 4 points 41350 41351 if ( this.closed || intPoint > 0 ) { 41352 41353 p0 = points[ ( intPoint - 1 ) % l ]; 41354 41355 } else { 41356 41357 // extrapolate first point 41358 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); 41359 p0 = tmp; 41360 41361 } 41362 41363 p1 = points[ intPoint % l ]; 41364 p2 = points[ ( intPoint + 1 ) % l ]; 41365 41366 if ( this.closed || intPoint + 2 < l ) { 41367 41368 p3 = points[ ( intPoint + 2 ) % l ]; 41369 41370 } else { 41371 41372 // extrapolate last point 41373 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); 41374 p3 = tmp; 41375 41376 } 41377 41378 if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) { 41379 41380 // init Centripetal / Chordal Catmull-Rom 41381 var pow = this.type === 'chordal' ? 0.5 : 0.25; 41382 var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); 41383 var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); 41384 var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); 41385 41386 // safety check for repeated points 41387 if ( dt1 < 1e-4 ) dt1 = 1.0; 41388 if ( dt0 < 1e-4 ) dt0 = dt1; 41389 if ( dt2 < 1e-4 ) dt2 = dt1; 41390 41391 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); 41392 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); 41393 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); 41394 41395 } else if ( this.type === 'catmullrom' ) { 41396 41397 var tension = this.tension !== undefined ? this.tension : 0.5; 41398 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension ); 41399 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension ); 41400 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension ); 41401 41402 } 41403 41404 return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) ); 41405 41406 }; 41407 41408 function CubicBezierCurve3( v0, v1, v2, v3 ) { 41409 41410 this.v0 = v0; 41411 this.v1 = v1; 41412 this.v2 = v2; 41413 this.v3 = v3; 41414 41415 } 41416 41417 CubicBezierCurve3.prototype = Object.create( Curve.prototype ); 41418 CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; 41419 41420 CubicBezierCurve3.prototype.getPoint = function ( t ) { 41421 41422 var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 41423 41424 return new Vector3( 41425 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 41426 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), 41427 CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) 41428 ); 41429 41430 }; 41431 41432 function QuadraticBezierCurve3( v0, v1, v2 ) { 41433 41434 this.v0 = v0; 41435 this.v1 = v1; 41436 this.v2 = v2; 41437 41438 } 41439 41440 QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); 41441 QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; 41442 41443 QuadraticBezierCurve3.prototype.getPoint = function ( t ) { 41444 41445 var v0 = this.v0, v1 = this.v1, v2 = this.v2; 41446 41447 return new Vector3( 41448 QuadraticBezier( t, v0.x, v1.x, v2.x ), 41449 QuadraticBezier( t, v0.y, v1.y, v2.y ), 41450 QuadraticBezier( t, v0.z, v1.z, v2.z ) 41451 ); 41452 41453 }; 41454 41455 function LineCurve3( v1, v2 ) { 41456 41457 this.v1 = v1; 41458 this.v2 = v2; 41459 41460 } 41461 41462 LineCurve3.prototype = Object.create( Curve.prototype ); 41463 LineCurve3.prototype.constructor = LineCurve3; 41464 41465 LineCurve3.prototype.getPoint = function ( t ) { 41466 41467 if ( t === 1 ) { 41468 41469 return this.v2.clone(); 41470 41471 } 41472 41473 var vector = new Vector3(); 41474 41475 vector.subVectors( this.v2, this.v1 ); // diff 41476 vector.multiplyScalar( t ); 41477 vector.add( this.v1 ); 41478 41479 return vector; 41480 41481 }; 41482 41483 function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 41484 41485 EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 41486 41487 } 41488 41489 ArcCurve.prototype = Object.create( EllipseCurve.prototype ); 41490 ArcCurve.prototype.constructor = ArcCurve; 41491 41492 /** 41493 * @author alteredq / http://alteredqualia.com/ 41494 */ 41495 41496 var SceneUtils = { 41497 41498 createMultiMaterialObject: function ( geometry, materials ) { 41499 41500 var group = new Group(); 41501 41502 for ( var i = 0, l = materials.length; i < l; i ++ ) { 41503 41504 group.add( new Mesh( geometry, materials[ i ] ) ); 41505 41506 } 41507 41508 return group; 41509 41510 }, 41511 41512 detach: function ( child, parent, scene ) { 41513 41514 child.applyMatrix( parent.matrixWorld ); 41515 parent.remove( child ); 41516 scene.add( child ); 41517 41518 }, 41519 41520 attach: function ( child, scene, parent ) { 41521 41522 var matrixWorldInverse = new Matrix4(); 41523 matrixWorldInverse.getInverse( parent.matrixWorld ); 41524 child.applyMatrix( matrixWorldInverse ); 41525 41526 scene.remove( child ); 41527 parent.add( child ); 41528 41529 } 41530 41531 }; 41532 41533 /** 41534 * @author mrdoob / http://mrdoob.com/ 41535 */ 41536 41537 function Face4( a, b, c, d, normal, color, materialIndex ) { 41538 41539 console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); 41540 return new Face3( a, b, c, normal, color, materialIndex ); 41541 41542 } 41543 41544 var LineStrip = 0; 41545 41546 var LinePieces = 1; 41547 41548 function MeshFaceMaterial( materials ) { 41549 41550 console.warn( 'THREE.MeshFaceMaterial has been renamed to THREE.MultiMaterial.' ); 41551 return new MultiMaterial( materials ); 41552 41553 } 41554 41555 function PointCloud( geometry, material ) { 41556 41557 console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); 41558 return new Points( geometry, material ); 41559 41560 } 41561 41562 function Particle( material ) { 41563 41564 console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); 41565 return new Sprite( material ); 41566 41567 } 41568 41569 function ParticleSystem( geometry, material ) { 41570 41571 console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); 41572 return new Points( geometry, material ); 41573 41574 } 41575 41576 function PointCloudMaterial( parameters ) { 41577 41578 console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); 41579 return new PointsMaterial( parameters ); 41580 41581 } 41582 41583 function ParticleBasicMaterial( parameters ) { 41584 41585 console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); 41586 return new PointsMaterial( parameters ); 41587 41588 } 41589 41590 function ParticleSystemMaterial( parameters ) { 41591 41592 console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); 41593 return new PointsMaterial( parameters ); 41594 41595 } 41596 41597 function Vertex( x, y, z ) { 41598 41599 console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' ); 41600 return new Vector3( x, y, z ); 41601 41602 } 41603 41604 // 41605 41606 function DynamicBufferAttribute( array, itemSize ) { 41607 41608 console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); 41609 return new BufferAttribute( array, itemSize ).setDynamic( true ); 41610 41611 } 41612 41613 function Int8Attribute( array, itemSize ) { 41614 41615 console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); 41616 return new Int8BufferAttribute( array, itemSize ); 41617 41618 } 41619 41620 function Uint8Attribute( array, itemSize ) { 41621 41622 console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); 41623 return new Uint8BufferAttribute( array, itemSize ); 41624 41625 } 41626 41627 function Uint8ClampedAttribute( array, itemSize ) { 41628 41629 console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' ); 41630 return new Uint8ClampedBufferAttribute( array, itemSize ); 41631 41632 } 41633 41634 function Int16Attribute( array, itemSize ) { 41635 41636 console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); 41637 return new Int16BufferAttribute( array, itemSize ); 41638 41639 } 41640 41641 function Uint16Attribute( array, itemSize ) { 41642 41643 console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' ); 41644 return new Uint16BufferAttribute( array, itemSize ); 41645 41646 } 41647 41648 function Int32Attribute( array, itemSize ) { 41649 41650 console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); 41651 return new Int32BufferAttribute( array, itemSize ); 41652 41653 } 41654 41655 function Uint32Attribute( array, itemSize ) { 41656 41657 console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); 41658 return new Uint32BufferAttribute( array, itemSize ); 41659 41660 } 41661 41662 function Float32Attribute( array, itemSize ) { 41663 41664 console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); 41665 return new Float32BufferAttribute( array, itemSize ); 41666 41667 } 41668 41669 function Float64Attribute( array, itemSize ) { 41670 41671 console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); 41672 return new Float64BufferAttribute( array, itemSize ); 41673 41674 } 41675 41676 // 41677 41678 Curve.create = function ( construct, getPoint ) { 41679 41680 console.log( 'THREE.Curve.create() has been deprecated' ); 41681 41682 construct.prototype = Object.create( Curve.prototype ); 41683 construct.prototype.constructor = construct; 41684 construct.prototype.getPoint = getPoint; 41685 41686 return construct; 41687 41688 }; 41689 41690 // 41691 41692 function ClosedSplineCurve3( points ) { 41693 41694 console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); 41695 41696 CatmullRomCurve3.call( this, points ); 41697 this.type = 'catmullrom'; 41698 this.closed = true; 41699 41700 } 41701 41702 ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); 41703 41704 // 41705 41706 function SplineCurve3( points ) { 41707 41708 console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); 41709 41710 CatmullRomCurve3.call( this, points ); 41711 this.type = 'catmullrom'; 41712 41713 } 41714 41715 SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); 41716 41717 // 41718 41719 function Spline( points ) { 41720 41721 console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); 41722 41723 CatmullRomCurve3.call( this, points ); 41724 this.type = 'catmullrom'; 41725 41726 } 41727 41728 Spline.prototype = Object.create( CatmullRomCurve3.prototype ); 41729 41730 Object.assign( Spline.prototype, { 41731 41732 initFromArray: function ( a ) { 41733 41734 console.error( 'THREE.Spline: .initFromArray() has been removed.' ); 41735 41736 }, 41737 getControlPointsArray: function ( optionalTarget ) { 41738 41739 console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); 41740 41741 }, 41742 reparametrizeByArcLength: function ( samplingCoef ) { 41743 41744 console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); 41745 41746 } 41747 41748 } ); 41749 41750 // 41751 function BoundingBoxHelper( object, color ) { 41752 41753 console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); 41754 return new BoxHelper( object, color ); 41755 41756 } 41757 41758 function EdgesHelper( object, hex ) { 41759 41760 console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' ); 41761 return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); 41762 41763 } 41764 41765 GridHelper.prototype.setColors = function () { 41766 41767 console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); 41768 41769 }; 41770 41771 function WireframeHelper( object, hex ) { 41772 41773 console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' ); 41774 return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); 41775 41776 } 41777 41778 // 41779 41780 function XHRLoader( manager ) { 41781 41782 console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); 41783 return new FileLoader( manager ); 41784 41785 } 41786 41787 function BinaryTextureLoader( manager ) { 41788 41789 console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); 41790 return new DataTextureLoader( manager ); 41791 41792 } 41793 41794 // 41795 41796 Object.assign( Box2.prototype, { 41797 41798 center: function ( optionalTarget ) { 41799 41800 console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); 41801 return this.getCenter( optionalTarget ); 41802 41803 }, 41804 empty: function () { 41805 41806 console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); 41807 return this.isEmpty(); 41808 41809 }, 41810 isIntersectionBox: function ( box ) { 41811 41812 console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); 41813 return this.intersectsBox( box ); 41814 41815 }, 41816 size: function ( optionalTarget ) { 41817 41818 console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); 41819 return this.getSize( optionalTarget ); 41820 41821 } 41822 } ); 41823 41824 Object.assign( Box3.prototype, { 41825 41826 center: function ( optionalTarget ) { 41827 41828 console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); 41829 return this.getCenter( optionalTarget ); 41830 41831 }, 41832 empty: function () { 41833 41834 console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); 41835 return this.isEmpty(); 41836 41837 }, 41838 isIntersectionBox: function ( box ) { 41839 41840 console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); 41841 return this.intersectsBox( box ); 41842 41843 }, 41844 isIntersectionSphere: function ( sphere ) { 41845 41846 console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); 41847 return this.intersectsSphere( sphere ); 41848 41849 }, 41850 size: function ( optionalTarget ) { 41851 41852 console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); 41853 return this.getSize( optionalTarget ); 41854 41855 } 41856 } ); 41857 41858 Line3.prototype.center = function ( optionalTarget ) { 41859 41860 console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); 41861 return this.getCenter( optionalTarget ); 41862 41863 }; 41864 41865 _Math.random16 = function () { 41866 41867 console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' ); 41868 return Math.random(); 41869 41870 }; 41871 41872 Object.assign( Matrix3.prototype, { 41873 41874 flattenToArrayOffset: function ( array, offset ) { 41875 41876 console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); 41877 return this.toArray( array, offset ); 41878 41879 }, 41880 multiplyVector3: function ( vector ) { 41881 41882 console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); 41883 return vector.applyMatrix3( this ); 41884 41885 }, 41886 multiplyVector3Array: function ( a ) { 41887 41888 console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); 41889 return this.applyToVector3Array( a ); 41890 41891 }, 41892 applyToBuffer: function( buffer, offset, length ) { 41893 41894 console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); 41895 return this.applyToBufferAttribute( buffer ); 41896 41897 }, 41898 applyToVector3Array: function( array, offset, length ) { 41899 41900 console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); 41901 41902 } 41903 41904 } ); 41905 41906 Object.assign( Matrix4.prototype, { 41907 41908 extractPosition: function ( m ) { 41909 41910 console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); 41911 return this.copyPosition( m ); 41912 41913 }, 41914 flattenToArrayOffset: function ( array, offset ) { 41915 41916 console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); 41917 return this.toArray( array, offset ); 41918 41919 }, 41920 getPosition: function () { 41921 41922 var v1; 41923 41924 return function getPosition() { 41925 41926 if ( v1 === undefined ) v1 = new Vector3(); 41927 console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); 41928 return v1.setFromMatrixColumn( this, 3 ); 41929 41930 }; 41931 41932 }(), 41933 setRotationFromQuaternion: function ( q ) { 41934 41935 console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); 41936 return this.makeRotationFromQuaternion( q ); 41937 41938 }, 41939 multiplyVector3: function ( vector ) { 41940 41941 console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); 41942 return vector.applyMatrix4( this ); 41943 41944 }, 41945 multiplyVector4: function ( vector ) { 41946 41947 console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); 41948 return vector.applyMatrix4( this ); 41949 41950 }, 41951 multiplyVector3Array: function ( a ) { 41952 41953 console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); 41954 return this.applyToVector3Array( a ); 41955 41956 }, 41957 rotateAxis: function ( v ) { 41958 41959 console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); 41960 v.transformDirection( this ); 41961 41962 }, 41963 crossVector: function ( vector ) { 41964 41965 console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); 41966 return vector.applyMatrix4( this ); 41967 41968 }, 41969 translate: function () { 41970 41971 console.error( 'THREE.Matrix4: .translate() has been removed.' ); 41972 41973 }, 41974 rotateX: function () { 41975 41976 console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); 41977 41978 }, 41979 rotateY: function () { 41980 41981 console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); 41982 41983 }, 41984 rotateZ: function () { 41985 41986 console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); 41987 41988 }, 41989 rotateByAxis: function () { 41990 41991 console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); 41992 41993 }, 41994 applyToBuffer: function( buffer, offset, length ) { 41995 41996 console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); 41997 return this.applyToBufferAttribute( buffer ); 41998 41999 }, 42000 applyToVector3Array: function( array, offset, length ) { 42001 42002 console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); 42003 42004 }, 42005 makeFrustum: function( left, right, bottom, top, near, far ) { 42006 42007 console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' ); 42008 return this.makePerspective( left, right, top, bottom, near, far ); 42009 42010 } 42011 42012 } ); 42013 42014 Plane.prototype.isIntersectionLine = function ( line ) { 42015 42016 console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); 42017 return this.intersectsLine( line ); 42018 42019 }; 42020 42021 Quaternion.prototype.multiplyVector3 = function ( vector ) { 42022 42023 console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); 42024 return vector.applyQuaternion( this ); 42025 42026 }; 42027 42028 Object.assign( Ray.prototype, { 42029 42030 isIntersectionBox: function ( box ) { 42031 42032 console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); 42033 return this.intersectsBox( box ); 42034 42035 }, 42036 isIntersectionPlane: function ( plane ) { 42037 42038 console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); 42039 return this.intersectsPlane( plane ); 42040 42041 }, 42042 isIntersectionSphere: function ( sphere ) { 42043 42044 console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); 42045 return this.intersectsSphere( sphere ); 42046 42047 } 42048 42049 } ); 42050 42051 Object.assign( Shape.prototype, { 42052 42053 extrude: function ( options ) { 42054 42055 console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); 42056 return new ExtrudeGeometry( this, options ); 42057 42058 }, 42059 makeGeometry: function ( options ) { 42060 42061 console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); 42062 return new ShapeGeometry( this, options ); 42063 42064 } 42065 42066 } ); 42067 42068 Object.assign( Vector2.prototype, { 42069 42070 fromAttribute: function ( attribute, index, offset ) { 42071 42072 console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); 42073 return this.fromBufferAttribute( attribute, index, offset ); 42074 42075 } 42076 42077 } ); 42078 42079 Object.assign( Vector3.prototype, { 42080 42081 setEulerFromRotationMatrix: function () { 42082 42083 console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); 42084 42085 }, 42086 setEulerFromQuaternion: function () { 42087 42088 console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); 42089 42090 }, 42091 getPositionFromMatrix: function ( m ) { 42092 42093 console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); 42094 return this.setFromMatrixPosition( m ); 42095 42096 }, 42097 getScaleFromMatrix: function ( m ) { 42098 42099 console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); 42100 return this.setFromMatrixScale( m ); 42101 42102 }, 42103 getColumnFromMatrix: function ( index, matrix ) { 42104 42105 console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); 42106 return this.setFromMatrixColumn( matrix, index ); 42107 42108 }, 42109 applyProjection: function ( m ) { 42110 42111 console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); 42112 return this.applyMatrix4( m ); 42113 42114 }, 42115 fromAttribute: function ( attribute, index, offset ) { 42116 42117 console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); 42118 return this.fromBufferAttribute( attribute, index, offset ); 42119 42120 } 42121 42122 } ); 42123 42124 Object.assign( Vector4.prototype, { 42125 42126 fromAttribute: function ( attribute, index, offset ) { 42127 42128 console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); 42129 return this.fromBufferAttribute( attribute, index, offset ); 42130 42131 } 42132 42133 } ); 42134 42135 // 42136 42137 Geometry.prototype.computeTangents = function () { 42138 42139 console.warn( 'THREE.Geometry: .computeTangents() has been removed.' ); 42140 42141 }; 42142 42143 Object.assign( Object3D.prototype, { 42144 42145 getChildByName: function ( name ) { 42146 42147 console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); 42148 return this.getObjectByName( name ); 42149 42150 }, 42151 renderDepth: function () { 42152 42153 console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); 42154 42155 }, 42156 translate: function ( distance, axis ) { 42157 42158 console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); 42159 return this.translateOnAxis( axis, distance ); 42160 42161 } 42162 42163 } ); 42164 42165 Object.defineProperties( Object3D.prototype, { 42166 42167 eulerOrder: { 42168 get: function () { 42169 42170 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); 42171 return this.rotation.order; 42172 42173 }, 42174 set: function ( value ) { 42175 42176 console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); 42177 this.rotation.order = value; 42178 42179 } 42180 }, 42181 useQuaternion: { 42182 get: function () { 42183 42184 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); 42185 42186 }, 42187 set: function () { 42188 42189 console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); 42190 42191 } 42192 } 42193 42194 } ); 42195 42196 Object.defineProperties( LOD.prototype, { 42197 42198 objects: { 42199 get: function () { 42200 42201 console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); 42202 return this.levels; 42203 42204 } 42205 } 42206 42207 } ); 42208 42209 // 42210 42211 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { 42212 42213 console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + 42214 "Use .setFocalLength and .filmGauge for a photographic setup." ); 42215 42216 if ( filmGauge !== undefined ) this.filmGauge = filmGauge; 42217 this.setFocalLength( focalLength ); 42218 42219 }; 42220 42221 // 42222 42223 Object.defineProperties( Light.prototype, { 42224 onlyShadow: { 42225 set: function () { 42226 42227 console.warn( 'THREE.Light: .onlyShadow has been removed.' ); 42228 42229 } 42230 }, 42231 shadowCameraFov: { 42232 set: function ( value ) { 42233 42234 console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); 42235 this.shadow.camera.fov = value; 42236 42237 } 42238 }, 42239 shadowCameraLeft: { 42240 set: function ( value ) { 42241 42242 console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); 42243 this.shadow.camera.left = value; 42244 42245 } 42246 }, 42247 shadowCameraRight: { 42248 set: function ( value ) { 42249 42250 console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); 42251 this.shadow.camera.right = value; 42252 42253 } 42254 }, 42255 shadowCameraTop: { 42256 set: function ( value ) { 42257 42258 console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); 42259 this.shadow.camera.top = value; 42260 42261 } 42262 }, 42263 shadowCameraBottom: { 42264 set: function ( value ) { 42265 42266 console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); 42267 this.shadow.camera.bottom = value; 42268 42269 } 42270 }, 42271 shadowCameraNear: { 42272 set: function ( value ) { 42273 42274 console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); 42275 this.shadow.camera.near = value; 42276 42277 } 42278 }, 42279 shadowCameraFar: { 42280 set: function ( value ) { 42281 42282 console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); 42283 this.shadow.camera.far = value; 42284 42285 } 42286 }, 42287 shadowCameraVisible: { 42288 set: function () { 42289 42290 console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); 42291 42292 } 42293 }, 42294 shadowBias: { 42295 set: function ( value ) { 42296 42297 console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); 42298 this.shadow.bias = value; 42299 42300 } 42301 }, 42302 shadowDarkness: { 42303 set: function () { 42304 42305 console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); 42306 42307 } 42308 }, 42309 shadowMapWidth: { 42310 set: function ( value ) { 42311 42312 console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); 42313 this.shadow.mapSize.width = value; 42314 42315 } 42316 }, 42317 shadowMapHeight: { 42318 set: function ( value ) { 42319 42320 console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); 42321 this.shadow.mapSize.height = value; 42322 42323 } 42324 } 42325 } ); 42326 42327 // 42328 42329 Object.defineProperties( BufferAttribute.prototype, { 42330 42331 length: { 42332 get: function () { 42333 42334 console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); 42335 return this.array.length; 42336 42337 } 42338 } 42339 42340 } ); 42341 42342 Object.assign( BufferGeometry.prototype, { 42343 42344 addIndex: function ( index ) { 42345 42346 console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); 42347 this.setIndex( index ); 42348 42349 }, 42350 addDrawCall: function ( start, count, indexOffset ) { 42351 42352 if ( indexOffset !== undefined ) { 42353 42354 console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); 42355 42356 } 42357 console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); 42358 this.addGroup( start, count ); 42359 42360 }, 42361 clearDrawCalls: function () { 42362 42363 console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); 42364 this.clearGroups(); 42365 42366 }, 42367 computeTangents: function () { 42368 42369 console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); 42370 42371 }, 42372 computeOffsets: function () { 42373 42374 console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); 42375 42376 } 42377 42378 } ); 42379 42380 Object.defineProperties( BufferGeometry.prototype, { 42381 42382 drawcalls: { 42383 get: function () { 42384 42385 console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); 42386 return this.groups; 42387 42388 } 42389 }, 42390 offsets: { 42391 get: function () { 42392 42393 console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); 42394 return this.groups; 42395 42396 } 42397 } 42398 42399 } ); 42400 42401 // 42402 42403 Object.defineProperties( Uniform.prototype, { 42404 42405 dynamic: { 42406 set: function () { 42407 42408 console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); 42409 42410 } 42411 }, 42412 onUpdate: { 42413 value: function () { 42414 42415 console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); 42416 return this; 42417 42418 } 42419 } 42420 42421 } ); 42422 42423 // 42424 42425 Object.defineProperties( Material.prototype, { 42426 42427 wrapAround: { 42428 get: function () { 42429 42430 console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); 42431 42432 }, 42433 set: function () { 42434 42435 console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); 42436 42437 } 42438 }, 42439 wrapRGB: { 42440 get: function () { 42441 42442 console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' ); 42443 return new Color(); 42444 42445 } 42446 } 42447 42448 } ); 42449 42450 Object.defineProperties( MeshPhongMaterial.prototype, { 42451 42452 metal: { 42453 get: function () { 42454 42455 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); 42456 return false; 42457 42458 }, 42459 set: function () { 42460 42461 console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); 42462 42463 } 42464 } 42465 42466 } ); 42467 42468 Object.defineProperties( ShaderMaterial.prototype, { 42469 42470 derivatives: { 42471 get: function () { 42472 42473 console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); 42474 return this.extensions.derivatives; 42475 42476 }, 42477 set: function ( value ) { 42478 42479 console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); 42480 this.extensions.derivatives = value; 42481 42482 } 42483 } 42484 42485 } ); 42486 42487 // 42488 42489 Object.assign( WebGLRenderer.prototype, { 42490 42491 supportsFloatTextures: function () { 42492 42493 console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); 42494 return this.extensions.get( 'OES_texture_float' ); 42495 42496 }, 42497 supportsHalfFloatTextures: function () { 42498 42499 console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); 42500 return this.extensions.get( 'OES_texture_half_float' ); 42501 42502 }, 42503 supportsStandardDerivatives: function () { 42504 42505 console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); 42506 return this.extensions.get( 'OES_standard_derivatives' ); 42507 42508 }, 42509 supportsCompressedTextureS3TC: function () { 42510 42511 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); 42512 return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); 42513 42514 }, 42515 supportsCompressedTexturePVRTC: function () { 42516 42517 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); 42518 return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); 42519 42520 }, 42521 supportsBlendMinMax: function () { 42522 42523 console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); 42524 return this.extensions.get( 'EXT_blend_minmax' ); 42525 42526 }, 42527 supportsVertexTextures: function () { 42528 42529 console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); 42530 return this.capabilities.vertexTextures; 42531 42532 }, 42533 supportsInstancedArrays: function () { 42534 42535 console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); 42536 return this.extensions.get( 'ANGLE_instanced_arrays' ); 42537 42538 }, 42539 enableScissorTest: function ( boolean ) { 42540 42541 console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); 42542 this.setScissorTest( boolean ); 42543 42544 }, 42545 initMaterial: function () { 42546 42547 console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); 42548 42549 }, 42550 addPrePlugin: function () { 42551 42552 console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); 42553 42554 }, 42555 addPostPlugin: function () { 42556 42557 console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); 42558 42559 }, 42560 updateShadowMap: function () { 42561 42562 console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); 42563 42564 } 42565 42566 } ); 42567 42568 Object.defineProperties( WebGLRenderer.prototype, { 42569 42570 shadowMapEnabled: { 42571 get: function () { 42572 42573 return this.shadowMap.enabled; 42574 42575 }, 42576 set: function ( value ) { 42577 42578 console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); 42579 this.shadowMap.enabled = value; 42580 42581 } 42582 }, 42583 shadowMapType: { 42584 get: function () { 42585 42586 return this.shadowMap.type; 42587 42588 }, 42589 set: function ( value ) { 42590 42591 console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); 42592 this.shadowMap.type = value; 42593 42594 } 42595 }, 42596 shadowMapCullFace: { 42597 get: function () { 42598 42599 return this.shadowMap.cullFace; 42600 42601 }, 42602 set: function ( value ) { 42603 42604 console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' ); 42605 this.shadowMap.cullFace = value; 42606 42607 } 42608 } 42609 } ); 42610 42611 Object.defineProperties( WebGLShadowMap.prototype, { 42612 42613 cullFace: { 42614 get: function () { 42615 42616 return this.renderReverseSided ? CullFaceFront : CullFaceBack; 42617 42618 }, 42619 set: function ( cullFace ) { 42620 42621 var value = ( cullFace !== CullFaceBack ); 42622 console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." ); 42623 this.renderReverseSided = value; 42624 42625 } 42626 } 42627 42628 } ); 42629 42630 // 42631 42632 Object.defineProperties( WebGLRenderTarget.prototype, { 42633 42634 wrapS: { 42635 get: function () { 42636 42637 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); 42638 return this.texture.wrapS; 42639 42640 }, 42641 set: function ( value ) { 42642 42643 console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); 42644 this.texture.wrapS = value; 42645 42646 } 42647 }, 42648 wrapT: { 42649 get: function () { 42650 42651 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); 42652 return this.texture.wrapT; 42653 42654 }, 42655 set: function ( value ) { 42656 42657 console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); 42658 this.texture.wrapT = value; 42659 42660 } 42661 }, 42662 magFilter: { 42663 get: function () { 42664 42665 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); 42666 return this.texture.magFilter; 42667 42668 }, 42669 set: function ( value ) { 42670 42671 console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); 42672 this.texture.magFilter = value; 42673 42674 } 42675 }, 42676 minFilter: { 42677 get: function () { 42678 42679 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); 42680 return this.texture.minFilter; 42681 42682 }, 42683 set: function ( value ) { 42684 42685 console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); 42686 this.texture.minFilter = value; 42687 42688 } 42689 }, 42690 anisotropy: { 42691 get: function () { 42692 42693 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); 42694 return this.texture.anisotropy; 42695 42696 }, 42697 set: function ( value ) { 42698 42699 console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); 42700 this.texture.anisotropy = value; 42701 42702 } 42703 }, 42704 offset: { 42705 get: function () { 42706 42707 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); 42708 return this.texture.offset; 42709 42710 }, 42711 set: function ( value ) { 42712 42713 console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); 42714 this.texture.offset = value; 42715 42716 } 42717 }, 42718 repeat: { 42719 get: function () { 42720 42721 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); 42722 return this.texture.repeat; 42723 42724 }, 42725 set: function ( value ) { 42726 42727 console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); 42728 this.texture.repeat = value; 42729 42730 } 42731 }, 42732 format: { 42733 get: function () { 42734 42735 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); 42736 return this.texture.format; 42737 42738 }, 42739 set: function ( value ) { 42740 42741 console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); 42742 this.texture.format = value; 42743 42744 } 42745 }, 42746 type: { 42747 get: function () { 42748 42749 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); 42750 return this.texture.type; 42751 42752 }, 42753 set: function ( value ) { 42754 42755 console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); 42756 this.texture.type = value; 42757 42758 } 42759 }, 42760 generateMipmaps: { 42761 get: function () { 42762 42763 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); 42764 return this.texture.generateMipmaps; 42765 42766 }, 42767 set: function ( value ) { 42768 42769 console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); 42770 this.texture.generateMipmaps = value; 42771 42772 } 42773 } 42774 42775 } ); 42776 42777 // 42778 42779 Audio.prototype.load = function ( file ) { 42780 42781 console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); 42782 var scope = this; 42783 var audioLoader = new AudioLoader(); 42784 audioLoader.load( file, function ( buffer ) { 42785 42786 scope.setBuffer( buffer ); 42787 42788 } ); 42789 return this; 42790 42791 }; 42792 42793 AudioAnalyser.prototype.getData = function () { 42794 42795 console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); 42796 return this.getFrequencyData(); 42797 42798 }; 42799 42800 // 42801 42802 var GeometryUtils = { 42803 42804 merge: function ( geometry1, geometry2, materialIndexOffset ) { 42805 42806 console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); 42807 var matrix; 42808 42809 if ( geometry2.isMesh ) { 42810 42811 geometry2.matrixAutoUpdate && geometry2.updateMatrix(); 42812 42813 matrix = geometry2.matrix; 42814 geometry2 = geometry2.geometry; 42815 42816 } 42817 42818 geometry1.merge( geometry2, matrix, materialIndexOffset ); 42819 42820 }, 42821 42822 center: function ( geometry ) { 42823 42824 console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); 42825 return geometry.center(); 42826 42827 } 42828 42829 }; 42830 42831 var ImageUtils = { 42832 42833 crossOrigin: undefined, 42834 42835 loadTexture: function ( url, mapping, onLoad, onError ) { 42836 42837 console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); 42838 42839 var loader = new TextureLoader(); 42840 loader.setCrossOrigin( this.crossOrigin ); 42841 42842 var texture = loader.load( url, onLoad, undefined, onError ); 42843 42844 if ( mapping ) texture.mapping = mapping; 42845 42846 return texture; 42847 42848 }, 42849 42850 loadTextureCube: function ( urls, mapping, onLoad, onError ) { 42851 42852 console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); 42853 42854 var loader = new CubeTextureLoader(); 42855 loader.setCrossOrigin( this.crossOrigin ); 42856 42857 var texture = loader.load( urls, onLoad, undefined, onError ); 42858 42859 if ( mapping ) texture.mapping = mapping; 42860 42861 return texture; 42862 42863 }, 42864 42865 loadCompressedTexture: function () { 42866 42867 console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ); 42868 42869 }, 42870 42871 loadCompressedTextureCube: function () { 42872 42873 console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ); 42874 42875 } 42876 42877 }; 42878 42879 // 42880 42881 function Projector() { 42882 42883 console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); 42884 42885 this.projectVector = function ( vector, camera ) { 42886 42887 console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); 42888 vector.project( camera ); 42889 42890 }; 42891 42892 this.unprojectVector = function ( vector, camera ) { 42893 42894 console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); 42895 vector.unproject( camera ); 42896 42897 }; 42898 42899 this.pickingRay = function () { 42900 42901 console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); 42902 42903 }; 42904 42905 } 42906 42907 // 42908 42909 function CanvasRenderer() { 42910 42911 console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); 42912 42913 this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); 42914 this.clear = function () {}; 42915 this.render = function () {}; 42916 this.setClearColor = function () {}; 42917 this.setSize = function () {}; 42918 42919 } 42920 42921 exports.WebGLRenderTargetCube = WebGLRenderTargetCube; 42922 exports.WebGLRenderTarget = WebGLRenderTarget; 42923 exports.WebGLRenderer = WebGLRenderer; 42924 exports.ShaderLib = ShaderLib; 42925 exports.UniformsLib = UniformsLib; 42926 exports.UniformsUtils = UniformsUtils; 42927 exports.ShaderChunk = ShaderChunk; 42928 exports.FogExp2 = FogExp2; 42929 exports.Fog = Fog; 42930 exports.Scene = Scene; 42931 exports.LensFlare = LensFlare; 42932 exports.Sprite = Sprite; 42933 exports.LOD = LOD; 42934 exports.SkinnedMesh = SkinnedMesh; 42935 exports.Skeleton = Skeleton; 42936 exports.Bone = Bone; 42937 exports.Mesh = Mesh; 42938 exports.LineSegments = LineSegments; 42939 exports.Line = Line; 42940 exports.Points = Points; 42941 exports.Group = Group; 42942 exports.VideoTexture = VideoTexture; 42943 exports.DataTexture = DataTexture; 42944 exports.CompressedTexture = CompressedTexture; 42945 exports.CubeTexture = CubeTexture; 42946 exports.CanvasTexture = CanvasTexture; 42947 exports.DepthTexture = DepthTexture; 42948 exports.Texture = Texture; 42949 exports.CompressedTextureLoader = CompressedTextureLoader; 42950 exports.DataTextureLoader = DataTextureLoader; 42951 exports.CubeTextureLoader = CubeTextureLoader; 42952 exports.TextureLoader = TextureLoader; 42953 exports.ObjectLoader = ObjectLoader; 42954 exports.MaterialLoader = MaterialLoader; 42955 exports.BufferGeometryLoader = BufferGeometryLoader; 42956 exports.DefaultLoadingManager = DefaultLoadingManager; 42957 exports.LoadingManager = LoadingManager; 42958 exports.JSONLoader = JSONLoader; 42959 exports.ImageLoader = ImageLoader; 42960 exports.FontLoader = FontLoader; 42961 exports.FileLoader = FileLoader; 42962 exports.Loader = Loader; 42963 exports.Cache = Cache; 42964 exports.AudioLoader = AudioLoader; 42965 exports.SpotLightShadow = SpotLightShadow; 42966 exports.SpotLight = SpotLight; 42967 exports.PointLight = PointLight; 42968 exports.RectAreaLight = RectAreaLight; 42969 exports.HemisphereLight = HemisphereLight; 42970 exports.DirectionalLightShadow = DirectionalLightShadow; 42971 exports.DirectionalLight = DirectionalLight; 42972 exports.AmbientLight = AmbientLight; 42973 exports.LightShadow = LightShadow; 42974 exports.Light = Light; 42975 exports.StereoCamera = StereoCamera; 42976 exports.PerspectiveCamera = PerspectiveCamera; 42977 exports.OrthographicCamera = OrthographicCamera; 42978 exports.CubeCamera = CubeCamera; 42979 exports.Camera = Camera; 42980 exports.AudioListener = AudioListener; 42981 exports.PositionalAudio = PositionalAudio; 42982 exports.AudioContext = AudioContext; 42983 exports.AudioAnalyser = AudioAnalyser; 42984 exports.Audio = Audio; 42985 exports.VectorKeyframeTrack = VectorKeyframeTrack; 42986 exports.StringKeyframeTrack = StringKeyframeTrack; 42987 exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack; 42988 exports.NumberKeyframeTrack = NumberKeyframeTrack; 42989 exports.ColorKeyframeTrack = ColorKeyframeTrack; 42990 exports.BooleanKeyframeTrack = BooleanKeyframeTrack; 42991 exports.PropertyMixer = PropertyMixer; 42992 exports.PropertyBinding = PropertyBinding; 42993 exports.KeyframeTrack = KeyframeTrack; 42994 exports.AnimationUtils = AnimationUtils; 42995 exports.AnimationObjectGroup = AnimationObjectGroup; 42996 exports.AnimationMixer = AnimationMixer; 42997 exports.AnimationClip = AnimationClip; 42998 exports.Uniform = Uniform; 42999 exports.InstancedBufferGeometry = InstancedBufferGeometry; 43000 exports.BufferGeometry = BufferGeometry; 43001 exports.GeometryIdCount = GeometryIdCount; 43002 exports.Geometry = Geometry; 43003 exports.InterleavedBufferAttribute = InterleavedBufferAttribute; 43004 exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer; 43005 exports.InterleavedBuffer = InterleavedBuffer; 43006 exports.InstancedBufferAttribute = InstancedBufferAttribute; 43007 exports.Face3 = Face3; 43008 exports.Object3D = Object3D; 43009 exports.Raycaster = Raycaster; 43010 exports.Layers = Layers; 43011 exports.EventDispatcher = EventDispatcher; 43012 exports.Clock = Clock; 43013 exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant; 43014 exports.LinearInterpolant = LinearInterpolant; 43015 exports.DiscreteInterpolant = DiscreteInterpolant; 43016 exports.CubicInterpolant = CubicInterpolant; 43017 exports.Interpolant = Interpolant; 43018 exports.Triangle = Triangle; 43019 exports.Math = _Math; 43020 exports.Spherical = Spherical; 43021 exports.Cylindrical = Cylindrical; 43022 exports.Plane = Plane; 43023 exports.Frustum = Frustum; 43024 exports.Sphere = Sphere; 43025 exports.Ray = Ray; 43026 exports.Matrix4 = Matrix4; 43027 exports.Matrix3 = Matrix3; 43028 exports.Box3 = Box3; 43029 exports.Box2 = Box2; 43030 exports.Line3 = Line3; 43031 exports.Euler = Euler; 43032 exports.Vector4 = Vector4; 43033 exports.Vector3 = Vector3; 43034 exports.Vector2 = Vector2; 43035 exports.Quaternion = Quaternion; 43036 exports.Color = Color; 43037 exports.MorphBlendMesh = MorphBlendMesh; 43038 exports.ImmediateRenderObject = ImmediateRenderObject; 43039 exports.VertexNormalsHelper = VertexNormalsHelper; 43040 exports.SpotLightHelper = SpotLightHelper; 43041 exports.SkeletonHelper = SkeletonHelper; 43042 exports.PointLightHelper = PointLightHelper; 43043 exports.RectAreaLightHelper = RectAreaLightHelper; 43044 exports.HemisphereLightHelper = HemisphereLightHelper; 43045 exports.GridHelper = GridHelper; 43046 exports.PolarGridHelper = PolarGridHelper; 43047 exports.FaceNormalsHelper = FaceNormalsHelper; 43048 exports.DirectionalLightHelper = DirectionalLightHelper; 43049 exports.CameraHelper = CameraHelper; 43050 exports.BoxHelper = BoxHelper; 43051 exports.ArrowHelper = ArrowHelper; 43052 exports.AxisHelper = AxisHelper; 43053 exports.CatmullRomCurve3 = CatmullRomCurve3; 43054 exports.CubicBezierCurve3 = CubicBezierCurve3; 43055 exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; 43056 exports.LineCurve3 = LineCurve3; 43057 exports.ArcCurve = ArcCurve; 43058 exports.EllipseCurve = EllipseCurve; 43059 exports.SplineCurve = SplineCurve; 43060 exports.CubicBezierCurve = CubicBezierCurve; 43061 exports.QuadraticBezierCurve = QuadraticBezierCurve; 43062 exports.LineCurve = LineCurve; 43063 exports.Shape = Shape; 43064 exports.Path = Path; 43065 exports.ShapePath = ShapePath; 43066 exports.Font = Font; 43067 exports.CurvePath = CurvePath; 43068 exports.Curve = Curve; 43069 exports.ShapeUtils = ShapeUtils; 43070 exports.SceneUtils = SceneUtils; 43071 exports.WireframeGeometry = WireframeGeometry; 43072 exports.ParametricGeometry = ParametricGeometry; 43073 exports.ParametricBufferGeometry = ParametricBufferGeometry; 43074 exports.TetrahedronGeometry = TetrahedronGeometry; 43075 exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry; 43076 exports.OctahedronGeometry = OctahedronGeometry; 43077 exports.OctahedronBufferGeometry = OctahedronBufferGeometry; 43078 exports.IcosahedronGeometry = IcosahedronGeometry; 43079 exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry; 43080 exports.DodecahedronGeometry = DodecahedronGeometry; 43081 exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry; 43082 exports.PolyhedronGeometry = PolyhedronGeometry; 43083 exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry; 43084 exports.TubeGeometry = TubeGeometry; 43085 exports.TubeBufferGeometry = TubeBufferGeometry; 43086 exports.TorusKnotGeometry = TorusKnotGeometry; 43087 exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry; 43088 exports.TorusGeometry = TorusGeometry; 43089 exports.TorusBufferGeometry = TorusBufferGeometry; 43090 exports.TextGeometry = TextGeometry; 43091 exports.SphereGeometry = SphereGeometry; 43092 exports.SphereBufferGeometry = SphereBufferGeometry; 43093 exports.RingGeometry = RingGeometry; 43094 exports.RingBufferGeometry = RingBufferGeometry; 43095 exports.PlaneGeometry = PlaneGeometry; 43096 exports.PlaneBufferGeometry = PlaneBufferGeometry; 43097 exports.LatheGeometry = LatheGeometry; 43098 exports.LatheBufferGeometry = LatheBufferGeometry; 43099 exports.ShapeGeometry = ShapeGeometry; 43100 exports.ShapeBufferGeometry = ShapeBufferGeometry; 43101 exports.ExtrudeGeometry = ExtrudeGeometry; 43102 exports.EdgesGeometry = EdgesGeometry; 43103 exports.ConeGeometry = ConeGeometry; 43104 exports.ConeBufferGeometry = ConeBufferGeometry; 43105 exports.CylinderGeometry = CylinderGeometry; 43106 exports.CylinderBufferGeometry = CylinderBufferGeometry; 43107 exports.CircleGeometry = CircleGeometry; 43108 exports.CircleBufferGeometry = CircleBufferGeometry; 43109 exports.BoxGeometry = BoxGeometry; 43110 exports.BoxBufferGeometry = BoxBufferGeometry; 43111 exports.ShadowMaterial = ShadowMaterial; 43112 exports.SpriteMaterial = SpriteMaterial; 43113 exports.RawShaderMaterial = RawShaderMaterial; 43114 exports.ShaderMaterial = ShaderMaterial; 43115 exports.PointsMaterial = PointsMaterial; 43116 exports.MultiMaterial = MultiMaterial; 43117 exports.MeshPhysicalMaterial = MeshPhysicalMaterial; 43118 exports.MeshStandardMaterial = MeshStandardMaterial; 43119 exports.MeshPhongMaterial = MeshPhongMaterial; 43120 exports.MeshToonMaterial = MeshToonMaterial; 43121 exports.MeshNormalMaterial = MeshNormalMaterial; 43122 exports.MeshLambertMaterial = MeshLambertMaterial; 43123 exports.MeshDepthMaterial = MeshDepthMaterial; 43124 exports.MeshBasicMaterial = MeshBasicMaterial; 43125 exports.LineDashedMaterial = LineDashedMaterial; 43126 exports.LineBasicMaterial = LineBasicMaterial; 43127 exports.Material = Material; 43128 exports.Float64BufferAttribute = Float64BufferAttribute; 43129 exports.Float32BufferAttribute = Float32BufferAttribute; 43130 exports.Uint32BufferAttribute = Uint32BufferAttribute; 43131 exports.Int32BufferAttribute = Int32BufferAttribute; 43132 exports.Uint16BufferAttribute = Uint16BufferAttribute; 43133 exports.Int16BufferAttribute = Int16BufferAttribute; 43134 exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute; 43135 exports.Uint8BufferAttribute = Uint8BufferAttribute; 43136 exports.Int8BufferAttribute = Int8BufferAttribute; 43137 exports.BufferAttribute = BufferAttribute; 43138 exports.REVISION = REVISION; 43139 exports.MOUSE = MOUSE; 43140 exports.CullFaceNone = CullFaceNone; 43141 exports.CullFaceBack = CullFaceBack; 43142 exports.CullFaceFront = CullFaceFront; 43143 exports.CullFaceFrontBack = CullFaceFrontBack; 43144 exports.FrontFaceDirectionCW = FrontFaceDirectionCW; 43145 exports.FrontFaceDirectionCCW = FrontFaceDirectionCCW; 43146 exports.BasicShadowMap = BasicShadowMap; 43147 exports.PCFShadowMap = PCFShadowMap; 43148 exports.PCFSoftShadowMap = PCFSoftShadowMap; 43149 exports.FrontSide = FrontSide; 43150 exports.BackSide = BackSide; 43151 exports.DoubleSide = DoubleSide; 43152 exports.FlatShading = FlatShading; 43153 exports.SmoothShading = SmoothShading; 43154 exports.NoColors = NoColors; 43155 exports.FaceColors = FaceColors; 43156 exports.VertexColors = VertexColors; 43157 exports.NoBlending = NoBlending; 43158 exports.NormalBlending = NormalBlending; 43159 exports.AdditiveBlending = AdditiveBlending; 43160 exports.SubtractiveBlending = SubtractiveBlending; 43161 exports.MultiplyBlending = MultiplyBlending; 43162 exports.CustomBlending = CustomBlending; 43163 exports.AddEquation = AddEquation; 43164 exports.SubtractEquation = SubtractEquation; 43165 exports.ReverseSubtractEquation = ReverseSubtractEquation; 43166 exports.MinEquation = MinEquation; 43167 exports.MaxEquation = MaxEquation; 43168 exports.ZeroFactor = ZeroFactor; 43169 exports.OneFactor = OneFactor; 43170 exports.SrcColorFactor = SrcColorFactor; 43171 exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor; 43172 exports.SrcAlphaFactor = SrcAlphaFactor; 43173 exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor; 43174 exports.DstAlphaFactor = DstAlphaFactor; 43175 exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor; 43176 exports.DstColorFactor = DstColorFactor; 43177 exports.OneMinusDstColorFactor = OneMinusDstColorFactor; 43178 exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor; 43179 exports.NeverDepth = NeverDepth; 43180 exports.AlwaysDepth = AlwaysDepth; 43181 exports.LessDepth = LessDepth; 43182 exports.LessEqualDepth = LessEqualDepth; 43183 exports.EqualDepth = EqualDepth; 43184 exports.GreaterEqualDepth = GreaterEqualDepth; 43185 exports.GreaterDepth = GreaterDepth; 43186 exports.NotEqualDepth = NotEqualDepth; 43187 exports.MultiplyOperation = MultiplyOperation; 43188 exports.MixOperation = MixOperation; 43189 exports.AddOperation = AddOperation; 43190 exports.NoToneMapping = NoToneMapping; 43191 exports.LinearToneMapping = LinearToneMapping; 43192 exports.ReinhardToneMapping = ReinhardToneMapping; 43193 exports.Uncharted2ToneMapping = Uncharted2ToneMapping; 43194 exports.CineonToneMapping = CineonToneMapping; 43195 exports.UVMapping = UVMapping; 43196 exports.CubeReflectionMapping = CubeReflectionMapping; 43197 exports.CubeRefractionMapping = CubeRefractionMapping; 43198 exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping; 43199 exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping; 43200 exports.SphericalReflectionMapping = SphericalReflectionMapping; 43201 exports.CubeUVReflectionMapping = CubeUVReflectionMapping; 43202 exports.CubeUVRefractionMapping = CubeUVRefractionMapping; 43203 exports.RepeatWrapping = RepeatWrapping; 43204 exports.ClampToEdgeWrapping = ClampToEdgeWrapping; 43205 exports.MirroredRepeatWrapping = MirroredRepeatWrapping; 43206 exports.NearestFilter = NearestFilter; 43207 exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter; 43208 exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter; 43209 exports.LinearFilter = LinearFilter; 43210 exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter; 43211 exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter; 43212 exports.UnsignedByteType = UnsignedByteType; 43213 exports.ByteType = ByteType; 43214 exports.ShortType = ShortType; 43215 exports.UnsignedShortType = UnsignedShortType; 43216 exports.IntType = IntType; 43217 exports.UnsignedIntType = UnsignedIntType; 43218 exports.FloatType = FloatType; 43219 exports.HalfFloatType = HalfFloatType; 43220 exports.UnsignedShort4444Type = UnsignedShort4444Type; 43221 exports.UnsignedShort5551Type = UnsignedShort5551Type; 43222 exports.UnsignedShort565Type = UnsignedShort565Type; 43223 exports.UnsignedInt248Type = UnsignedInt248Type; 43224 exports.AlphaFormat = AlphaFormat; 43225 exports.RGBFormat = RGBFormat; 43226 exports.RGBAFormat = RGBAFormat; 43227 exports.LuminanceFormat = LuminanceFormat; 43228 exports.LuminanceAlphaFormat = LuminanceAlphaFormat; 43229 exports.RGBEFormat = RGBEFormat; 43230 exports.DepthFormat = DepthFormat; 43231 exports.DepthStencilFormat = DepthStencilFormat; 43232 exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format; 43233 exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format; 43234 exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format; 43235 exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format; 43236 exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format; 43237 exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format; 43238 exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format; 43239 exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format; 43240 exports.RGB_ETC1_Format = RGB_ETC1_Format; 43241 exports.LoopOnce = LoopOnce; 43242 exports.LoopRepeat = LoopRepeat; 43243 exports.LoopPingPong = LoopPingPong; 43244 exports.InterpolateDiscrete = InterpolateDiscrete; 43245 exports.InterpolateLinear = InterpolateLinear; 43246 exports.InterpolateSmooth = InterpolateSmooth; 43247 exports.ZeroCurvatureEnding = ZeroCurvatureEnding; 43248 exports.ZeroSlopeEnding = ZeroSlopeEnding; 43249 exports.WrapAroundEnding = WrapAroundEnding; 43250 exports.TrianglesDrawMode = TrianglesDrawMode; 43251 exports.TriangleStripDrawMode = TriangleStripDrawMode; 43252 exports.TriangleFanDrawMode = TriangleFanDrawMode; 43253 exports.LinearEncoding = LinearEncoding; 43254 exports.sRGBEncoding = sRGBEncoding; 43255 exports.GammaEncoding = GammaEncoding; 43256 exports.RGBEEncoding = RGBEEncoding; 43257 exports.LogLuvEncoding = LogLuvEncoding; 43258 exports.RGBM7Encoding = RGBM7Encoding; 43259 exports.RGBM16Encoding = RGBM16Encoding; 43260 exports.RGBDEncoding = RGBDEncoding; 43261 exports.BasicDepthPacking = BasicDepthPacking; 43262 exports.RGBADepthPacking = RGBADepthPacking; 43263 exports.CubeGeometry = BoxGeometry; 43264 exports.Face4 = Face4; 43265 exports.LineStrip = LineStrip; 43266 exports.LinePieces = LinePieces; 43267 exports.MeshFaceMaterial = MeshFaceMaterial; 43268 exports.PointCloud = PointCloud; 43269 exports.Particle = Particle; 43270 exports.ParticleSystem = ParticleSystem; 43271 exports.PointCloudMaterial = PointCloudMaterial; 43272 exports.ParticleBasicMaterial = ParticleBasicMaterial; 43273 exports.ParticleSystemMaterial = ParticleSystemMaterial; 43274 exports.Vertex = Vertex; 43275 exports.DynamicBufferAttribute = DynamicBufferAttribute; 43276 exports.Int8Attribute = Int8Attribute; 43277 exports.Uint8Attribute = Uint8Attribute; 43278 exports.Uint8ClampedAttribute = Uint8ClampedAttribute; 43279 exports.Int16Attribute = Int16Attribute; 43280 exports.Uint16Attribute = Uint16Attribute; 43281 exports.Int32Attribute = Int32Attribute; 43282 exports.Uint32Attribute = Uint32Attribute; 43283 exports.Float32Attribute = Float32Attribute; 43284 exports.Float64Attribute = Float64Attribute; 43285 exports.ClosedSplineCurve3 = ClosedSplineCurve3; 43286 exports.SplineCurve3 = SplineCurve3; 43287 exports.Spline = Spline; 43288 exports.BoundingBoxHelper = BoundingBoxHelper; 43289 exports.EdgesHelper = EdgesHelper; 43290 exports.WireframeHelper = WireframeHelper; 43291 exports.XHRLoader = XHRLoader; 43292 exports.BinaryTextureLoader = BinaryTextureLoader; 43293 exports.GeometryUtils = GeometryUtils; 43294 exports.ImageUtils = ImageUtils; 43295 exports.Projector = Projector; 43296 exports.CanvasRenderer = CanvasRenderer; 43297 43298 Object.defineProperty(exports, '__esModule', { value: true }); 43299 43300 })));